1
0
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:
DjWarmonger 2011-04-25 09:03:13 +00:00
parent 362f413b4d
commit a4d845688a
12 changed files with 232 additions and 115 deletions

View File

@ -2307,6 +2307,20 @@ void CBattleInterface::stackRemoved(const CStack * stack)
void CBattleInterface::stackActivated(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; //givenCommand = NULL;
stackToActivate = stack; stackToActivate = stack;
if(pendingAnims.size() == 0) 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 std::vector<const CStack*> stacks = curInt->cb->battleGetStacks(); //gets only alive stacks
BOOST_FOREACH(const CStack *s, 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(); waitForAnims();
} }
@ -2826,7 +2826,6 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
case 37: //cure case 37: //cure
case 38: //resurrection case 38: //resurrection
case 39: //animate dead case 39: //animate dead
case 78: //dispel helpful spells
for(std::set<ui32>::const_iterator it = sc->affectedCres.begin(); it != sc->affectedCres.end(); ++it) for(std::set<ui32>::const_iterator it = sc->affectedCres.begin(); it != sc->affectedCres.end(); ++it)
{ {
displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(*it, false)->position); displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(*it, false)->position);
@ -2856,24 +2855,32 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
} }
else else
{ {
if (sc->id == 79) // Death Stare switch(sc->id)
{ {
customSpell = true; case 71: //Poison
if (sc->dmgToDisplay > 1) customSpell = true;
{ break;
text = CGI->generaltexth->allTexts[119]; //%d %s die under the terrible gaze of the %s. //case 75: // Aging
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(sc->dmgToDisplay)); // customSpell = true;
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getCreature()->namePl ); // break;
} case 79: // Death Stare
else customSpell = true;
{ if (sc->dmgToDisplay > 1)
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); 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", "Creatures"); //casting stack 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) if (!customSpell)
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id]->name); 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); console->addText(txt);
} }
//displaying heal animation //displaying special abilities
if (action->actionType == BattleAction::STACK_HEAL) switch (action->actionType)
{ {
displayEffect(50, action->destinationTile); case BattleAction::STACK_HEAL:
displayEffect(50, action->destinationTile);
break;
} }
} }

View File

@ -66,8 +66,8 @@
64 1 C20SPX.DEF 64 1 C20SPX.DEF
65 0 65 0
66 0 66 0
67 0 67 1 SP11_.DEF
68 0 68 1 SP02_.DEF
69 1 C05SPE0.DEF 69 1 C05SPE0.DEF
70 2 SP02_.DEF SP10_.DEF 70 2 SP02_.DEF SP10_.DEF
71 1 SP01_.DEF 71 1 SP01_.DEF

View File

@ -17,11 +17,11 @@
+ 17 MAGIC_RESISTANCE 40 0 0 //battle dwarf's magic resistance 40% + 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 + 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 + 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 + 22 SPELL_AFTER_ATTACK 72 0 100 //dendroids cast bind
+ 23 SPELL_AFTER_ATTACK 0 72 100 //dendroid guards cast bind + 23 SPELL_AFTER_ATTACK 72 0 100 //dendroid guards cast bind
+ 24 SPELL_AFTER_ATTACK 0 62 20 //unicorns cast blind with 20% probability + 24 SPELL_AFTER_ATTACK 62 0 20 //unicorns cast blind with 20% probability
+ 24 SPELL_RESISTANCE_AURA 0 55 0 //unicorn + 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 + 25 SPELL_RESISTANCE_AURA 20 55 0 //war unicorn
+ 26 LEVEL_SPELL_IMMUNITY 3 0 0 //green dragon's spell immunity + 26 LEVEL_SPELL_IMMUNITY 3 0 0 //green dragon's spell immunity
+ 26 TWO_HEX_ATTACK_BREATH 0 0 0 //green dragon's breath + 26 TWO_HEX_ATTACK_BREATH 0 0 0 //green dragon's breath
@ -86,22 +86,22 @@
+ 63 LIFE_DRAIN 0 0 0 //vampire lords + 63 LIFE_DRAIN 0 0 0 //vampire lords
+ 64 SPELL_LIKE_ATTACK 76 0 0 //liches + 64 SPELL_LIKE_ATTACK 76 0 0 //liches
+ 65 SPELL_LIKE_ATTACK 76 0 0 //power 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 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 + 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 + 69 DRAGON_NATURE 0 0 0 //ghost dragon is a dragon
+ 70 SPELL_IMMUNITY 0 62 0 //troglodytes are immune to blind + 70 SPELL_IMMUNITY 0 62 0 //troglodytes are immune to blind
+ 71 SPELL_IMMUNITY 0 62 0 //infernal 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 + 72 RETURN_AFTER_STRIKE 0 0 0 //Harpies return after attack
+ 73 BLOCKS_RETALIATION 0 0 0 //Harpy Hags + 73 BLOCKS_RETALIATION 0 0 0 //Harpy Hags
+ 73 RETURN_AFTER_STRIKE 0 0 0 //Harpy Hags return after attack + 73 RETURN_AFTER_STRIKE 0 0 0 //Harpy Hags return after attack
+ 76 SPELL_AFTER_ATTACK 0 70 2020 //medusas + 76 SPELL_AFTER_ATTACK 20 70 2000 //medusas
+ 77 SPELL_AFTER_ATTACK 0 70 2020 //medusa queens + 77 SPELL_AFTER_ATTACK 20 70 2000 //medusa queens
+ 78 SELF_MORALE 0 0 0 //minotaurs + 78 SELF_MORALE 0 0 0 //minotaurs
+ 79 SELF_MORALE 0 0 0 //minotaur kings + 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 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 TWO_HEX_ATTACK_BREATH 0 0 0 //Red Dragon has breath attack
+ 82 DRAGON_NATURE 0 0 0 //red dragon is a dragon + 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 + 83 DRAGON_NATURE 0 0 0 //black dragon is a dragon
+ 87 ADDITIONAL_ATTACK 1 0 0 //wolf raider + 87 ADDITIONAL_ATTACK 1 0 0 //wolf raider
+ 91 SPELLCASTER 2 43 6 //ogre magi cast bloodlust + 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 + 96 ENEMY_DEFENCE_REDUCTION 40 0 0 //behemots
+ 97 ENEMY_DEFENCE_REDUCTION 80 0 0 //ancient behemots + 97 ENEMY_DEFENCE_REDUCTION 80 0 0 //ancient behemots
+ 103 DEATH_STARE 10 0 0 //mighty gorgons + 103 DEATH_STARE 10 0 0 //mighty gorgons
+ 104 SPELL_AFTER_ATTACK 0 78 100 //serpent fly + 104 SPELL_AFTER_ATTACK 100 78 0 //serpent fly
+ 105 SPELL_AFTER_ATTACK 0 45 100 //mighty gorgons + 105 SPELL_AFTER_ATTACK 100 45 0 //mighty gorgons
+ 105 SPELL_AFTER_ATTACK 0 78 100 //dragon fly + 105 SPELL_AFTER_ATTACK 100 78 0 //dragon fly
+ 106 SPELL_AFTER_ATTACK 0 70 20 //basilisks + 106 SPELL_AFTER_ATTACK 20 70 0 //basilisks
+ 107 SPELL_AFTER_ATTACK 0 70 20 //greater basilisks + 107 SPELL_AFTER_ATTACK 20 70 0 //greater basilisks
+ 109 SPELL_AFTER_ATTACK 0 71 20 //Wyvern Monarch + 109 SPELL_AFTER_ATTACK 20 71 0 //Wyvern Monarch
+ 110 ATTACKS_ALL_ADJACENT 0 0 0 //hydras + 110 ATTACKS_ALL_ADJACENT 0 0 0 //hydras
+ 110 BLOCKS_RETALIATION 0 0 0 //hydras + 110 BLOCKS_RETALIATION 0 0 0 //hydras
+ 111 ATTACKS_ALL_ADJACENT 0 0 0 //chaos hydras + 111 ATTACKS_ALL_ADJACENT 0 0 0 //chaos hydras

View File

@ -70,15 +70,15 @@
67 0 -1 X X X X 67 0 -1 X X X X
68 0 -1 X X X X 68 0 -1 X X X X
69 0 -1 X X X X 69 0 -1 X X X X
70 -1 -1 0 0 0 0 70 0 70 0 0 0 0
71 -1 -1 0 0 0 0 71 -1 67 0 0 0 0
72 -1 -1 0 0 0 0 72 0 68 0 0 0 0
73 -1 -1 0 0 0 0 73 -1 69 0 0 0 0
74 -1 -1 0 0 0 0 74 -1 70 0 0 0 0
75 -1 -1 0 0 0 0 75 -1 71 0 0 0 0
76 -1 -1 0 0 0 0 76 0 72 0 0 0 0
77 -1 38 0 0 0 0 77 -1 38 0 0 0 0
78 -1 41 0 0 0 0 78 -1 41 0 0 0 0
79 0 80 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 -1

12
config/spell_levels.txt Normal file
View 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

View File

@ -1792,8 +1792,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
} }
if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) || if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) ||
( immunities.size() > 0 && immunities.totalValue() >= spell->level) ( immunities.size() > 0 && immunities.totalValue() >= spell->level)) //many creature abilities have level equal to 0 by default, fixed in config\spell_levels
&& spell->level) //many creature abilities have level equal to 0, may cause bugs
{ {
return SpellCasting::STACK_IMMUNE_TO_SPELL; 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.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; sf.back().sid = sse.sid;
break; 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;
} }
} }

View File

@ -956,7 +956,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
break; break;
case 'a': 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.type = Bonus::SPELL_AFTER_ATTACK;
b.subtype = stringToNumber(mod); b.subtype = stringToNumber(mod);
break; break;

View File

@ -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); boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
break; break;
case Bonus::SPELL_AFTER_ATTACK: 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); boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
break; break;
}
default: default:
{}//TODO: allow custom bonus types... someday, somehow {}//TODO: allow custom bonus types... someday, somehow
} }

View File

@ -321,4 +321,24 @@ void CSpellHandler::loadSpells()
ast>>spellID; 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();
} }

View File

@ -92,7 +92,7 @@ namespace PrimarySkill
BONUS_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \ 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_ALLY) /*in mana points (value) , eg. mage*/ \
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \ 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(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(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*/ \ 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(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(EXP_MULTIPLIER)/* val - percent of additional exp gained by stack/commander (base value 100)*/\
BONUS_NAME(SHOTS)\ 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 for handling bonuses of several types. Can be transfered to any hero
struct DLL_EXPORT Bonus struct DLL_EXPORT Bonus
@ -185,7 +187,7 @@ struct DLL_EXPORT Bonus
ARTIFACT, ARTIFACT,
ARTIFACT_INSTANCE, ARTIFACT_INSTANCE,
OBJECT, OBJECT,
CREATURE_ABILITY, CREATURE_ABILITY,
TERRAIN_NATIVE, TERRAIN_NATIVE,
TERRAIN_OVERLAY, TERRAIN_OVERLAY,
SPELL_EFFECT, SPELL_EFFECT,

View File

@ -874,13 +874,7 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
s->state -= MOVED; s->state -= MOVED;
s->state -= HAD_MORALE; s->state -= HAD_MORALE;
s->counterAttacks = 1 + s->valOfBonuses(Bonus::ADDITIONAL_RETALIATION); s->counterAttacks = 1 + s->valOfBonuses(Bonus::ADDITIONAL_RETALIATION);
// new turn effects
//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();
s->battleTurnPassed(); s->battleTurnPassed();
} }
} }
@ -890,6 +884,34 @@ DLL_EXPORT void BattleSetActiveStack::applyGs( CGameState *gs )
gs->curB->activeStack = stack; gs->curB->activeStack = stack;
CStack *st = gs->curB->getStack(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 //remove bonuses that last until when stack gets new turn
st->bonuses.remove_if(Bonus::UntilGetsTurn); st->bonuses.remove_if(Bonus::UntilGetsTurn);
@ -1135,14 +1157,14 @@ void actualizeEffect(CStack * s, const Bonus & ef)
DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs ) 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) BOOST_FOREACH(ui32 id, stacks)
{ {
CStack *s = gs->curB->getStack(id); CStack *s = gs->curB->getStack(id);
if(s) 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) BOOST_FOREACH(Bonus &fromEffect, effect)
{ {
@ -1163,7 +1185,7 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
CStack *s = gs->curB->getStack(para.first); CStack *s = gs->curB->getStack(para.first);
if (s) 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)); s->addNewBonus(new Bonus(para.second));
else else
actualizeEffect(s, effect); actualizeEffect(s, effect);

View File

@ -3077,6 +3077,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
bat.flags |= BattleAttack::SHOT; bat.flags |= BattleAttack::SHOT;
prepareAttack(bat, curStack, destStack, 0); prepareAttack(bat, curStack, destStack, 0);
sendAndApply(&bat); sendAndApply(&bat);
handleAfterAttackCasting(bat);
//ballista & artillery handling //ballista & artillery handling
if(destStack->alive() && curStack->getCreature()->idNumber == 146) if(destStack->alive() && curStack->getCreature()->idNumber == 146)
@ -3203,7 +3204,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
sendAndApply(&EndAction()); sendAndApply(&EndAction());
break; break;
} }
case BattleAction::STACK_HEAL: //healing case BattleAction::STACK_HEAL: //healing with First Aid Tent
{ {
sendAndApply(&StartAction(ba)); sendAndApply(&StartAction(ba));
const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side]; const CGHeroInstance * attackingHero = gs->curB->heroes[ba.side];
@ -3404,14 +3405,12 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
continue; continue;
sc.dmgToDisplay += gs->curB->calculateSpellDmg(spell, caster, *it, spellLvl, usedSpellPower); sc.dmgToDisplay += gs->curB->calculateSpellDmg(spell, caster, *it, spellLvl, usedSpellPower);
} }
if (spellID = 79) // Death stare if (spellID == 79) // Death stare
{ {
sc.dmgToDisplay = usedSpellPower; 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 //applying effects
switch(spellID) switch(spellID)
{ {
@ -3477,6 +3476,12 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
case 60: //hypnotize case 60: //hypnotize
case 61: //forgetfulness case 61: //forgetfulness
case 62: //blind case 62: //blind
case 70: //Stone Gaze
case 71: //Poison
case 72: //Bind
case 73: //Disease
case 74: //Paralyze
case 75: //Aging
{ {
SetStackEffect sse; SetStackEffect sse;
Bonus pseudoBonus; Bonus pseudoBonus;
@ -3484,8 +3489,10 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
pseudoBonus.val = spellLvl; pseudoBonus.val = spellLvl;
pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower); pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
CStack::stackEffectToFeature(sse.effect, pseudoBonus); 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; si32 power;
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it) 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; 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; int damagePercent = caster->level * caster->valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / tier;
Bonus specialBonus = CStack::featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, pseudoBonus.turnsRemain); 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;
} }
break;
case 79: //Death stare - handled in a bit different way case 79: //Death stare - handled in a bit different way
{ {
StacksInjured si; StacksInjured si;
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it) 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; continue;
}
BattleStackAttacked bsa; BattleStackAttacked bsa;
bsa.flags |= BattleStackAttacked::EFFECT; 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.damageAmount = usedSpellPower * (*it)->valOfBonuses(Bonus::STACK_HEALTH);
bsa.stackAttacked = (*it)->ID; bsa.stackAttacked = (*it)->ID;
bsa.attackerID = -1; bsa.attackerID = -1;
@ -3616,6 +3627,8 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
break; break;
} }
sendAndApply(&sc);
} }
bool CGameHandler::makeCustomAction( BattleAction &ba ) bool CGameHandler::makeCustomAction( BattleAction &ba )
@ -4203,40 +4216,50 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
const CStack * attacker = gs->curB->getStack(bat.stackAttacking); const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) ) if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
{ {
std::set<ui32> spellsToCast;
BOOST_FOREACH(const Bonus *sf, attacker->getBonuses(Selector::type(Bonus::SPELL_AFTER_ATTACK))) 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; if (bat.bsa[g].newAmount > 0)
for(int g=0; g<bat.bsa.size(); ++g)
{ {
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 if (attacker->hasBonusOfType(Bonus::DEATH_STARE)) // spell id 79