mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Support for Poison, Age, Disease
Partial support for Stone Gaze, Paralyze, Mana drain Partial fix for #134 - animation triggers only for our own stacks, not enemy's Lots of tweaks & fixes.
This commit is contained in:
parent
362f413b4d
commit
a4d845688a
@ -2307,6 +2307,20 @@ void CBattleInterface::stackRemoved(const CStack * stack)
|
||||
|
||||
void CBattleInterface::stackActivated(const CStack * stack)
|
||||
{
|
||||
//don't show animation when no HP is regenerated
|
||||
if (stack->firstHPleft != stack->MaxHealth())
|
||||
{
|
||||
if( stack->hasBonusOfType(Bonus::HP_REGENERATION) || stack->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1))
|
||||
displayEffect(74, stack->position);
|
||||
if( stack->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0))
|
||||
displayEffect(4, stack->position);
|
||||
}
|
||||
|
||||
if(stack->hasBonusOfType(Bonus::MANA_DRAIN))
|
||||
displayEffect(77, stack->position);
|
||||
if(stack->hasBonusOfType(Bonus::POISON))
|
||||
displayEffect(67, stack->position);
|
||||
|
||||
//givenCommand = NULL;
|
||||
stackToActivate = stack;
|
||||
if(pendingAnims.size() == 0)
|
||||
@ -2347,20 +2361,6 @@ void CBattleInterface::newRoundFirst( int round )
|
||||
std::vector<const CStack*> stacks = curInt->cb->battleGetStacks(); //gets only alive stacks
|
||||
BOOST_FOREACH(const CStack *s, stacks)
|
||||
{
|
||||
//don't show animation when no HP is regenerated
|
||||
if (s->firstHPleft == s->MaxHealth())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( s->hasBonusOfType(Bonus::HP_REGENERATION))
|
||||
displayEffect(74, s->position);
|
||||
|
||||
if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 0))
|
||||
displayEffect(4, s->position);
|
||||
|
||||
if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION, 1))
|
||||
displayEffect(74, s->position);
|
||||
}
|
||||
waitForAnims();
|
||||
}
|
||||
@ -2826,7 +2826,6 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
case 37: //cure
|
||||
case 38: //resurrection
|
||||
case 39: //animate dead
|
||||
case 78: //dispel helpful spells
|
||||
for(std::set<ui32>::const_iterator it = sc->affectedCres.begin(); it != sc->affectedCres.end(); ++it)
|
||||
{
|
||||
displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(*it, false)->position);
|
||||
@ -2856,24 +2855,32 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sc->id == 79) // Death Stare
|
||||
switch(sc->id)
|
||||
{
|
||||
customSpell = true;
|
||||
if (sc->dmgToDisplay > 1)
|
||||
{
|
||||
text = CGI->generaltexth->allTexts[119]; //%d %s die under the terrible gaze of the %s.
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(sc->dmgToDisplay));
|
||||
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getCreature()->namePl );
|
||||
}
|
||||
else
|
||||
{
|
||||
text = CGI->generaltexth->allTexts[118]; //One %s dies under the terrible gaze of the %s.
|
||||
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin())->type->nameSing);
|
||||
}
|
||||
boost::algorithm::replace_first(text, "%s", "Creatures"); //casting stack
|
||||
case 71: //Poison
|
||||
customSpell = true;
|
||||
break;
|
||||
//case 75: // Aging
|
||||
// customSpell = true;
|
||||
// break;
|
||||
case 79: // Death Stare
|
||||
customSpell = true;
|
||||
if (sc->dmgToDisplay > 1)
|
||||
{
|
||||
text = CGI->generaltexth->allTexts[119]; //%d %s die under the terrible gaze of the %s.
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(sc->dmgToDisplay));
|
||||
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getCreature()->namePl );
|
||||
}
|
||||
else
|
||||
{
|
||||
text = CGI->generaltexth->allTexts[118]; //One %s dies under the terrible gaze of the %s.
|
||||
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin())->type->nameSing);
|
||||
}
|
||||
boost::algorithm::replace_first(text, "%s", "Creatures"); //casting stack
|
||||
break;
|
||||
default:
|
||||
boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix
|
||||
}
|
||||
else
|
||||
boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix
|
||||
}
|
||||
if (!customSpell)
|
||||
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id]->name);
|
||||
@ -3503,10 +3510,12 @@ void CBattleInterface::startAction(const BattleAction* action)
|
||||
console->addText(txt);
|
||||
}
|
||||
|
||||
//displaying heal animation
|
||||
if (action->actionType == BattleAction::STACK_HEAL)
|
||||
//displaying special abilities
|
||||
switch (action->actionType)
|
||||
{
|
||||
displayEffect(50, action->destinationTile);
|
||||
case BattleAction::STACK_HEAL:
|
||||
displayEffect(50, action->destinationTile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,8 @@
|
||||
64 1 C20SPX.DEF
|
||||
65 0
|
||||
66 0
|
||||
67 0
|
||||
68 0
|
||||
67 1 SP11_.DEF
|
||||
68 1 SP02_.DEF
|
||||
69 1 C05SPE0.DEF
|
||||
70 2 SP02_.DEF SP10_.DEF
|
||||
71 1 SP01_.DEF
|
||||
|
@ -17,11 +17,11 @@
|
||||
+ 17 MAGIC_RESISTANCE 40 0 0 //battle dwarf's magic resistance 40%
|
||||
+ 20 CHANGES_SPELL_COST_FOR_ENEMY 2 0 0 //pegasus makes spell cost higher for enemy mage
|
||||
+ 21 CHANGES_SPELL_COST_FOR_ENEMY 2 0 0 //silver pegasus makes spell cost higher for enemy mage
|
||||
+ 22 SPELL_AFTER_ATTACK 0 72 100 //dendroids cast bind
|
||||
+ 23 SPELL_AFTER_ATTACK 0 72 100 //dendroid guards cast bind
|
||||
+ 24 SPELL_AFTER_ATTACK 0 62 20 //unicorns cast blind with 20% probability
|
||||
+ 22 SPELL_AFTER_ATTACK 72 0 100 //dendroids cast bind
|
||||
+ 23 SPELL_AFTER_ATTACK 72 0 100 //dendroid guards cast bind
|
||||
+ 24 SPELL_AFTER_ATTACK 62 0 20 //unicorns cast blind with 20% probability
|
||||
+ 24 SPELL_RESISTANCE_AURA 0 55 0 //unicorn
|
||||
+ 25 SPELL_AFTER_ATTACK 0 62 20 //war unicorns cast blind with 20% probability
|
||||
+ 25 SPELL_AFTER_ATTACK 62 0 20 //war unicorns cast blind with 20% probability
|
||||
+ 25 SPELL_RESISTANCE_AURA 20 55 0 //war unicorn
|
||||
+ 26 LEVEL_SPELL_IMMUNITY 3 0 0 //green dragon's spell immunity
|
||||
+ 26 TWO_HEX_ATTACK_BREATH 0 0 0 //green dragon's breath
|
||||
@ -86,22 +86,22 @@
|
||||
+ 63 LIFE_DRAIN 0 0 0 //vampire lords
|
||||
+ 64 SPELL_LIKE_ATTACK 76 0 0 //liches
|
||||
+ 65 SPELL_LIKE_ATTACK 76 0 0 //power liches
|
||||
+ 66 SPELL_AFTER_ATTACK 0 42 20 //black knights
|
||||
+ 66 SPELL_AFTER_ATTACK 20 42 0 //black knights
|
||||
+ 67 DOUBLE_DAMAGE_CHANCE 20 0 0 //vampire lords
|
||||
+ 67 SPELL_AFTER_ATTACK 0 42 20 //dread knights
|
||||
+ 67 SPELL_AFTER_ATTACK 20 42 0 //dread knights
|
||||
+ 68 DRAGON_NATURE 0 0 0 //bone dragon is a dragon
|
||||
+ 69 SPELL_AFTER_ATTACK 0 75 20 //ghost dragon
|
||||
+ 69 SPELL_AFTER_ATTACK 20 75 0 //ghost dragon
|
||||
+ 69 DRAGON_NATURE 0 0 0 //ghost dragon is a dragon
|
||||
+ 70 SPELL_IMMUNITY 0 62 0 //troglodytes are immune to blind
|
||||
+ 71 SPELL_IMMUNITY 0 62 0 //infernal troglodytes are immune to blind
|
||||
+ 72 RETURN_AFTER_STRIKE 0 0 0 //Harpies return after attack
|
||||
+ 73 BLOCKS_RETALIATION 0 0 0 //Harpy Hags
|
||||
+ 73 RETURN_AFTER_STRIKE 0 0 0 //Harpy Hags return after attack
|
||||
+ 76 SPELL_AFTER_ATTACK 0 70 2020 //medusas
|
||||
+ 77 SPELL_AFTER_ATTACK 0 70 2020 //medusa queens
|
||||
+ 76 SPELL_AFTER_ATTACK 20 70 2000 //medusas
|
||||
+ 77 SPELL_AFTER_ATTACK 20 70 2000 //medusa queens
|
||||
+ 78 SELF_MORALE 0 0 0 //minotaurs
|
||||
+ 79 SELF_MORALE 0 0 0 //minotaur kings
|
||||
+ 81 SPELL_AFTER_ATTACK 0 74 20 //scorpicore
|
||||
+ 81 SPELL_AFTER_ATTACK 20 74 0 //scorpicore
|
||||
+ 82 LEVEL_SPELL_IMMUNITY 3 0 0 //red dragon's spell immunity
|
||||
+ 82 TWO_HEX_ATTACK_BREATH 0 0 0 //Red Dragon has breath attack
|
||||
+ 82 DRAGON_NATURE 0 0 0 //red dragon is a dragon
|
||||
@ -112,16 +112,16 @@
|
||||
+ 83 DRAGON_NATURE 0 0 0 //black dragon is a dragon
|
||||
+ 87 ADDITIONAL_ATTACK 1 0 0 //wolf raider
|
||||
+ 91 SPELLCASTER 2 43 6 //ogre magi cast bloodlust
|
||||
+ 93 SPELL_AFTER_ATTACK 0 77 20 //thunderbirds
|
||||
+ 93 SPELL_AFTER_ATTACK 20 77 0 //thunderbirds
|
||||
+ 96 ENEMY_DEFENCE_REDUCTION 40 0 0 //behemots
|
||||
+ 97 ENEMY_DEFENCE_REDUCTION 80 0 0 //ancient behemots
|
||||
+ 103 DEATH_STARE 10 0 0 //mighty gorgons
|
||||
+ 104 SPELL_AFTER_ATTACK 0 78 100 //serpent fly
|
||||
+ 105 SPELL_AFTER_ATTACK 0 45 100 //mighty gorgons
|
||||
+ 105 SPELL_AFTER_ATTACK 0 78 100 //dragon fly
|
||||
+ 106 SPELL_AFTER_ATTACK 0 70 20 //basilisks
|
||||
+ 107 SPELL_AFTER_ATTACK 0 70 20 //greater basilisks
|
||||
+ 109 SPELL_AFTER_ATTACK 0 71 20 //Wyvern Monarch
|
||||
+ 104 SPELL_AFTER_ATTACK 100 78 0 //serpent fly
|
||||
+ 105 SPELL_AFTER_ATTACK 100 45 0 //mighty gorgons
|
||||
+ 105 SPELL_AFTER_ATTACK 100 78 0 //dragon fly
|
||||
+ 106 SPELL_AFTER_ATTACK 20 70 0 //basilisks
|
||||
+ 107 SPELL_AFTER_ATTACK 20 70 0 //greater basilisks
|
||||
+ 109 SPELL_AFTER_ATTACK 20 71 0 //Wyvern Monarch
|
||||
+ 110 ATTACKS_ALL_ADJACENT 0 0 0 //hydras
|
||||
+ 110 BLOCKS_RETALIATION 0 0 0 //hydras
|
||||
+ 111 ATTACKS_ALL_ADJACENT 0 0 0 //chaos hydras
|
||||
|
@ -70,15 +70,15 @@
|
||||
67 0 -1 X X X X
|
||||
68 0 -1 X X X X
|
||||
69 0 -1 X X X X
|
||||
70 -1 -1 0 0 0 0
|
||||
71 -1 -1 0 0 0 0
|
||||
72 -1 -1 0 0 0 0
|
||||
73 -1 -1 0 0 0 0
|
||||
74 -1 -1 0 0 0 0
|
||||
75 -1 -1 0 0 0 0
|
||||
76 -1 -1 0 0 0 0
|
||||
70 0 70 0 0 0 0
|
||||
71 -1 67 0 0 0 0
|
||||
72 0 68 0 0 0 0
|
||||
73 -1 69 0 0 0 0
|
||||
74 -1 70 0 0 0 0
|
||||
75 -1 71 0 0 0 0
|
||||
76 0 72 0 0 0 0
|
||||
77 -1 38 0 0 0 0
|
||||
78 -1 41 0 0 0 0
|
||||
79 0 80 0 0 0 0
|
||||
80 -1 -1 0 0 0 0
|
||||
80 0 81 0 0 0 0
|
||||
-1
|
12
config/spell_levels.txt
Normal file
12
config/spell_levels.txt
Normal file
@ -0,0 +1,12 @@
|
||||
70 3
|
||||
71 2
|
||||
72 255
|
||||
73 2
|
||||
74 4
|
||||
75 5
|
||||
76 255
|
||||
77 2
|
||||
78 1
|
||||
79 255
|
||||
80 255
|
||||
-1
|
@ -1792,8 +1792,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
|
||||
}
|
||||
|
||||
if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) ||
|
||||
( immunities.size() > 0 && immunities.totalValue() >= spell->level)
|
||||
&& spell->level) //many creature abilities have level equal to 0, may cause bugs
|
||||
( immunities.size() > 0 && immunities.totalValue() >= spell->level)) //many creature abilities have level equal to 0 by default, fixed in config\spell_levels
|
||||
{
|
||||
return SpellCasting::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
@ -2140,6 +2139,34 @@ void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
|
||||
sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 70: //Stone Gaze
|
||||
case 74: //Paralyze
|
||||
sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 71: //Poison
|
||||
sf.push_back(featureGeneratorVT(Bonus::POISON, 0, 30, 3, Bonus::INDEPENDENT_MAX)); //max hp penalty from this source
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -10, 3, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 72: //Bind
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -100, 1, Bonus::PERCENT_TO_ALL)); //sets speed to zero
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 0)); //marker, TODO: handle it
|
||||
sf.back().duration = Bonus::PERMANENT;
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 73: //Disease
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2 ,3));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2 ,3));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 75: //Age
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -50, 3, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -956,7 +956,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
//case 'c': //some special abilities are threated as spells, will cause bugs
|
||||
case 'c': //some special abilities are threated as spells, work in progress
|
||||
b.type = Bonus::SPELL_AFTER_ATTACK;
|
||||
b.subtype = stringToNumber(mod);
|
||||
break;
|
||||
|
@ -583,9 +583,11 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
|
||||
break;
|
||||
case Bonus::SPELL_AFTER_ATTACK:
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->additionalInfo % 1000));
|
||||
{
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSybtype(bonus->type, bonus->subtype))));
|
||||
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{}//TODO: allow custom bonus types... someday, somehow
|
||||
}
|
||||
|
@ -321,4 +321,24 @@ void CSpellHandler::loadSpells()
|
||||
ast>>spellID;
|
||||
}
|
||||
}
|
||||
ast.close();
|
||||
ast.open(DATA_DIR "/config/spell_levels.txt", std::ios::binary);
|
||||
if(!ast.is_open())
|
||||
{
|
||||
tlog1<<"lack of config/spell_levels.txt file!"<<std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
//custom levels of spells. Level 0 seems to not be supported correctly, but we can replace it it something else
|
||||
int spellID;
|
||||
ast>>spellID;
|
||||
int buf;
|
||||
while(spellID != -1)
|
||||
{
|
||||
ast >> buf;
|
||||
spells[spellID]->level = buf;
|
||||
ast>>spellID;
|
||||
}
|
||||
}
|
||||
ast.close();
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ namespace PrimarySkill
|
||||
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 - spell level, (additional info)%1000 - chance in %; eg. dendroids, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [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(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
||||
@ -157,7 +157,9 @@ namespace PrimarySkill
|
||||
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(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)*/
|
||||
|
||||
/// Struct for handling bonuses of several types. Can be transfered to any hero
|
||||
struct DLL_EXPORT Bonus
|
||||
@ -185,7 +187,7 @@ struct DLL_EXPORT Bonus
|
||||
ARTIFACT,
|
||||
ARTIFACT_INSTANCE,
|
||||
OBJECT,
|
||||
CREATURE_ABILITY,
|
||||
CREATURE_ABILITY,
|
||||
TERRAIN_NATIVE,
|
||||
TERRAIN_OVERLAY,
|
||||
SPELL_EFFECT,
|
||||
|
@ -874,13 +874,7 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
|
||||
s->state -= MOVED;
|
||||
s->state -= HAD_MORALE;
|
||||
s->counterAttacks = 1 + s->valOfBonuses(Bonus::ADDITIONAL_RETALIATION);
|
||||
|
||||
//regeneration
|
||||
if( s->hasBonusOfType(Bonus::HP_REGENERATION) && s->alive() )
|
||||
s->firstHPleft = std::min<ui32>( s->MaxHealth(), s->valOfBonuses(Bonus::HP_REGENERATION) );
|
||||
if( s->hasBonusOfType(Bonus::FULL_HP_REGENERATION) && s->alive() )
|
||||
s->firstHPleft = s->MaxHealth();
|
||||
|
||||
// new turn effects
|
||||
s->battleTurnPassed();
|
||||
}
|
||||
}
|
||||
@ -890,6 +884,34 @@ DLL_EXPORT void BattleSetActiveStack::applyGs( CGameState *gs )
|
||||
gs->curB->activeStack = stack;
|
||||
CStack *st = gs->curB->getStack(stack);
|
||||
|
||||
if (st->alive())
|
||||
{
|
||||
//regeneration
|
||||
if(st->hasBonusOfType(Bonus::HP_REGENERATION))
|
||||
st->firstHPleft = std::min<ui32>( st->MaxHealth(), st->valOfBonuses(Bonus::HP_REGENERATION) );
|
||||
if(st->hasBonusOfType(Bonus::FULL_HP_REGENERATION))
|
||||
st->firstHPleft = st->MaxHealth();
|
||||
if(st->hasBonusOfType(Bonus::POISON))
|
||||
{
|
||||
Bonus * b = st->getBonus(Selector::source(Bonus::SPELL_EFFECT, 71) && Selector::type(Bonus::STACK_HEALTH));
|
||||
if (b) //TODO: what if not?...
|
||||
{
|
||||
b->val -= 10;
|
||||
amax (b->val, -(st->valOfBonuses(Bonus::POISON)));
|
||||
}
|
||||
}
|
||||
if(st->hasBonusOfType(Bonus::MANA_DRAIN))
|
||||
{
|
||||
const CGHeroInstance * enemy = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
|
||||
if (enemy)
|
||||
{
|
||||
ui32 manaDrained = st->valOfBonuses(Bonus::MANA_DRAIN);
|
||||
amin (manaDrained, gs->curB->heroes[0]->mana);
|
||||
gs->getHero(enemy->id)->mana -= manaDrained; //jeez, it's overcomplicate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove bonuses that last until when stack gets new turn
|
||||
st->bonuses.remove_if(Bonus::UntilGetsTurn);
|
||||
|
||||
@ -1135,14 +1157,14 @@ void actualizeEffect(CStack * s, const Bonus & ef)
|
||||
|
||||
DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
|
||||
{
|
||||
int id = effect.begin()->sid; //effects' source ID
|
||||
int spellid = effect.begin()->sid; //effects' source ID
|
||||
|
||||
BOOST_FOREACH(ui32 id, stacks)
|
||||
{
|
||||
CStack *s = gs->curB->getStack(id);
|
||||
if(s)
|
||||
{
|
||||
if(id == 47 || !s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, id)))//disrupting ray or not on the list - just add
|
||||
if(spellid == 47 || spellid == 80 || !s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, spellid)))//disrupting ray or acid breath or not on the list - just add
|
||||
{
|
||||
BOOST_FOREACH(Bonus &fromEffect, effect)
|
||||
{
|
||||
@ -1163,7 +1185,7 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
|
||||
CStack *s = gs->curB->getStack(para.first);
|
||||
if (s)
|
||||
{
|
||||
if (!s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, id) && Selector::typeSybtype(para.second.type, para.second.subtype)))
|
||||
if (!s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, spellid) && Selector::typeSybtype(para.second.type, para.second.subtype)))
|
||||
s->addNewBonus(new Bonus(para.second));
|
||||
else
|
||||
actualizeEffect(s, effect);
|
||||
|
@ -3077,6 +3077,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
bat.flags |= BattleAttack::SHOT;
|
||||
prepareAttack(bat, curStack, destStack, 0);
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
|
||||
//ballista & artillery handling
|
||||
if(destStack->alive() && curStack->getCreature()->idNumber == 146)
|
||||
@ -3203,7 +3204,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
sendAndApply(&EndAction());
|
||||
break;
|
||||
}
|
||||
case BattleAction::STACK_HEAL: //healing
|
||||
case BattleAction::STACK_HEAL: //healing with First Aid Tent
|
||||
{
|
||||
sendAndApply(&StartAction(ba));
|
||||
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
|
||||
@ -3404,14 +3405,12 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
continue;
|
||||
sc.dmgToDisplay += gs->curB->calculateSpellDmg(spell, caster, *it, spellLvl, usedSpellPower);
|
||||
}
|
||||
if (spellID = 79) // Death stare
|
||||
if (spellID == 79) // Death stare
|
||||
{
|
||||
sc.dmgToDisplay = usedSpellPower;
|
||||
amin(sc.dmgToDisplay, (*attackedCres.begin())->count); // hopefully stack is already reduced after attack
|
||||
amin(sc.dmgToDisplay, (*attackedCres.begin())->count); //stack is already reduced after attack
|
||||
}
|
||||
|
||||
sendAndApply(&sc);
|
||||
|
||||
//applying effects
|
||||
switch(spellID)
|
||||
{
|
||||
@ -3477,6 +3476,12 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
case 60: //hypnotize
|
||||
case 61: //forgetfulness
|
||||
case 62: //blind
|
||||
case 70: //Stone Gaze
|
||||
case 71: //Poison
|
||||
case 72: //Bind
|
||||
case 73: //Disease
|
||||
case 74: //Paralyze
|
||||
case 75: //Aging
|
||||
{
|
||||
SetStackEffect sse;
|
||||
Bonus pseudoBonus;
|
||||
@ -3484,8 +3489,10 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
pseudoBonus.val = spellLvl;
|
||||
pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
|
||||
CStack::stackEffectToFeature(sse.effect, pseudoBonus);
|
||||
const Bonus * bonus = NULL;
|
||||
if (caster)
|
||||
bonus = caster->getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, spellID));
|
||||
|
||||
const Bonus * bonus = caster->getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, spellID));
|
||||
si32 power;
|
||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||
{
|
||||
@ -3528,7 +3535,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (caster->hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, spellID)) //TODO: better handling of bonus percentages
|
||||
if (caster && caster->hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, spellID)) //TODO: better handling of bonus percentages
|
||||
{
|
||||
int damagePercent = caster->level * caster->valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / tier;
|
||||
Bonus specialBonus = CStack::featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, pseudoBonus.turnsRemain);
|
||||
@ -3593,17 +3600,21 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 79: //Death stare - handled in a bit different way
|
||||
{
|
||||
StacksInjured si;
|
||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||
{
|
||||
if((*it)->hasBonusOfType (Bonus::UNDEAD) || (*it)->hasBonusOfType (Bonus::NON_LIVING)) //this creature is immune
|
||||
if((*it)->hasBonusOfType(Bonus::UNDEAD) || (*it)->hasBonusOfType(Bonus::NON_LIVING)) //this creature is immune
|
||||
{
|
||||
sc.dmgToDisplay = 0; //TODO: handle Death Stare for multiple targets (?)
|
||||
continue;
|
||||
}
|
||||
|
||||
BattleStackAttacked bsa;
|
||||
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||
bsa.effect = spell->mainEffectAnim; //TODO: find which it is
|
||||
bsa.effect = spell->mainEffectAnim; //from config\spell-Info.txt
|
||||
bsa.damageAmount = usedSpellPower * (*it)->valOfBonuses(Bonus::STACK_HEALTH);
|
||||
bsa.stackAttacked = (*it)->ID;
|
||||
bsa.attackerID = -1;
|
||||
@ -3616,6 +3627,8 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
break;
|
||||
}
|
||||
|
||||
sendAndApply(&sc);
|
||||
|
||||
}
|
||||
|
||||
bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
@ -4203,40 +4216,50 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
||||
if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
|
||||
{
|
||||
std::set<ui32> spellsToCast;
|
||||
BOOST_FOREACH(const Bonus *sf, attacker->getBonuses(Selector::type(Bonus::SPELL_AFTER_ATTACK)))
|
||||
{
|
||||
if (sf->type == Bonus::SPELL_AFTER_ATTACK)
|
||||
spellsToCast.insert (sf->subtype);
|
||||
}
|
||||
BOOST_FOREACH(ui32 spellID, spellsToCast)
|
||||
{
|
||||
const CStack * oneOfAttacked = NULL;
|
||||
for(int g=0; g<bat.bsa.size(); ++g)
|
||||
{
|
||||
const CStack * oneOfAttacked = NULL;
|
||||
for(int g=0; g<bat.bsa.size(); ++g)
|
||||
if (bat.bsa[g].newAmount > 0)
|
||||
{
|
||||
if (bat.bsa[g].newAmount > 0)
|
||||
{
|
||||
oneOfAttacked = gs->curB->getStack(bat.bsa[g].stackAttacked);
|
||||
break;
|
||||
}
|
||||
oneOfAttacked = gs->curB->getStack(bat.bsa[g].stackAttacked);
|
||||
break;
|
||||
}
|
||||
if(oneOfAttacked == NULL) //all attacked creatures have been killed
|
||||
return;
|
||||
|
||||
int spellID = sf->subtype;
|
||||
int spellLevel = sf->val;
|
||||
int chance = sf->additionalInfo % 1000;
|
||||
//int meleeRanged = sf->additionalInfo / 1000;
|
||||
int destination = oneOfAttacked->position;
|
||||
|
||||
const CSpell * spell = VLC->spellh->spells[spellID];
|
||||
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position)
|
||||
!= SpellCasting::OK)
|
||||
continue;
|
||||
|
||||
//check if spell should be casted (probability handling)
|
||||
if( rand()%100 >= chance )
|
||||
continue;
|
||||
|
||||
//casting
|
||||
handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, attacker->count, SpellCasting::AFTER_ATTACK_CASTING);
|
||||
}
|
||||
bool castMe = false;
|
||||
int meleeRanged;
|
||||
if(oneOfAttacked == NULL) //all attacked creatures have been killed
|
||||
return;
|
||||
int spellLevel = 0;
|
||||
BOOST_FOREACH(const Bonus *sf, attacker->getBonuses(Selector::typeSybtype(Bonus::SPELL_AFTER_ATTACK, spellID)))
|
||||
{
|
||||
amax(spellLevel, sf->additionalInfo % 1000); //pick highest level
|
||||
meleeRanged = sf->additionalInfo / 1000;
|
||||
if (meleeRanged == 0 || (meleeRanged == 1 && bat.shot()) || (meleeRanged == 2 && !bat.shot()))
|
||||
castMe = true;
|
||||
}
|
||||
int chance = attacker->valOfBonuses((Selector::typeSybtype(Bonus::SPELL_AFTER_ATTACK, spellID)));
|
||||
amin (chance, 100);
|
||||
int destination = oneOfAttacked->position;
|
||||
|
||||
const CSpell * spell = VLC->spellh->spells[spellID];
|
||||
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position)
|
||||
!= SpellCasting::OK)
|
||||
continue;
|
||||
|
||||
//check if spell should be casted (probability handling)
|
||||
if(rand()%100 >= chance)
|
||||
continue;
|
||||
|
||||
//casting
|
||||
if (castMe)
|
||||
handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, attacker->count, SpellCasting::AFTER_ATTACK_CASTING);
|
||||
}
|
||||
}
|
||||
if (attacker->hasBonusOfType(Bonus::DEATH_STARE)) // spell id 79
|
||||
|
Loading…
Reference in New Issue
Block a user