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)
{
//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;
}
}

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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