diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index 2f656e69e..a10fc2dbd 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -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 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::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(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(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; } } diff --git a/config/AC_desc.txt b/config/AC_desc.txt index 81da9015e..733c2bff3 100644 --- a/config/AC_desc.txt +++ b/config/AC_desc.txt @@ -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 diff --git a/config/cr_abils.txt b/config/cr_abils.txt index 46801a5d2..ce337d784 100644 --- a/config/cr_abils.txt +++ b/config/cr_abils.txt @@ -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 diff --git a/config/spell_info.txt b/config/spell_info.txt index c85dc26e3..a42f73158 100644 --- a/config/spell_info.txt +++ b/config/spell_info.txt @@ -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 \ No newline at end of file diff --git a/config/spell_levels.txt b/config/spell_levels.txt new file mode 100644 index 000000000..b39caa2db --- /dev/null +++ b/config/spell_levels.txt @@ -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 \ No newline at end of file diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index e763003ad..1acbfab50 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -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 & 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; } } diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 59630c0d4..42a47a3ab 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -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; diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index 3798e7c90..ab2a4606e 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -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(bonus->additionalInfo % 1000)); + { + boost::algorithm::replace_first(text, "%d", boost::lexical_cast(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 } diff --git a/lib/CSpellHandler.cpp b/lib/CSpellHandler.cpp index 9d2ebd1a6..46a33497c 100644 --- a/lib/CSpellHandler.cpp +++ b/lib/CSpellHandler.cpp @@ -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!"<>spellID; + int buf; + while(spellID != -1) + { + ast >> buf; + spells[spellID]->level = buf; + ast>>spellID; + } + } + ast.close(); } diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 60ebce899..7df014184 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -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, diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 74852e59c..a2cfee21b 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -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( 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( 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); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 8722c71fc..4a566c4cf 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -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::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::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 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 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