mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Support for Death Stare.
Some tweaks are still needed. Level 0 spell-like abilities won't work correctly.
This commit is contained in:
parent
61af4c745e
commit
7591d06b05
@ -2843,19 +2843,39 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
|||||||
}
|
}
|
||||||
|
|
||||||
//displaying message in console
|
//displaying message in console
|
||||||
|
bool customSpell = false;
|
||||||
if(sc->affectedCres.size() == 1)
|
if(sc->affectedCres.size() == 1)
|
||||||
{
|
{
|
||||||
std::string text = CGI->generaltexth->allTexts[195];
|
std::string text = CGI->generaltexth->allTexts[195];
|
||||||
if(sc->castedByHero)
|
if(sc->castedByHero)
|
||||||
{
|
{
|
||||||
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetFightingHero(sc->side)->name);
|
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetFightingHero(sc->side)->name);
|
||||||
|
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getCreature()->namePl ); //target
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix
|
if (sc->id == 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
|
||||||
|
}
|
||||||
|
else
|
||||||
|
boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix
|
||||||
}
|
}
|
||||||
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id]->name);
|
if (!customSpell)
|
||||||
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getCreature()->namePl );
|
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id]->name);
|
||||||
|
|
||||||
console->addText(text);
|
console->addText(text);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2872,7 +2892,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
|||||||
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id]->name);
|
boost::algorithm::replace_first(text, "%s", CGI->spellh->spells[sc->id]->name);
|
||||||
console->addText(text);
|
console->addText(text);
|
||||||
}
|
}
|
||||||
if(sc->dmgToDisplay != 0)
|
if(sc->dmgToDisplay && !customSpell)
|
||||||
{
|
{
|
||||||
std::string dmgInfo = CGI->generaltexth->allTexts[343].substr(1, CGI->generaltexth->allTexts[343].size() - 1);
|
std::string dmgInfo = CGI->generaltexth->allTexts[343].substr(1, CGI->generaltexth->allTexts[343].size() - 1);
|
||||||
boost::algorithm::replace_first(dmgInfo, "%d", boost::lexical_cast<std::string>(sc->dmgToDisplay));
|
boost::algorithm::replace_first(dmgInfo, "%d", boost::lexical_cast<std::string>(sc->dmgToDisplay));
|
||||||
|
@ -115,7 +115,7 @@
|
|||||||
+ 93 SPELL_AFTER_ATTACK 0 77 20 //thunderbirds
|
+ 93 SPELL_AFTER_ATTACK 0 77 20 //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 SPELL_AFTER_ATTACK 0 79 10 //mighty gorgons
|
+ 103 DEATH_STARE 10 0 0 //mighty gorgons
|
||||||
+ 104 SPELL_AFTER_ATTACK 0 78 100 //serpent fly
|
+ 104 SPELL_AFTER_ATTACK 0 78 100 //serpent fly
|
||||||
+ 105 SPELL_AFTER_ATTACK 0 45 100 //mighty gorgons
|
+ 105 SPELL_AFTER_ATTACK 0 45 100 //mighty gorgons
|
||||||
+ 105 SPELL_AFTER_ATTACK 0 78 100 //dragon fly
|
+ 105 SPELL_AFTER_ATTACK 0 78 100 //dragon fly
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
31 PROTECTF.wav # protection from fire
|
31 PROTECTF.wav # protection from fire
|
||||||
32 PROTECTW.wav # protection from water
|
32 PROTECTW.wav # protection from water
|
||||||
33 PROTECTE.wav # protection from earth
|
33 PROTECTE.wav # protection from earth
|
||||||
|
35 DISPELL.wav # dispell
|
||||||
41 BLESS.wav # bless
|
41 BLESS.wav # bless
|
||||||
42 CURSE.wav # curse
|
42 CURSE.wav # curse
|
||||||
43 BLOODLUS.wav # bloodlust
|
43 BLOODLUS.wav # bloodlust
|
||||||
@ -35,7 +36,7 @@
|
|||||||
55 SLAYER.wav # slayer
|
55 SLAYER.wav # slayer
|
||||||
56 FRENZY.wav # frenzy
|
56 FRENZY.wav # frenzy
|
||||||
61 FORGET.wav # forgetfulness
|
61 FORGET.wav # forgetfulness
|
||||||
|
79 DEATHSTR.wav # Death Stare
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +48,6 @@
|
|||||||
#DEATHBLO.wav
|
#DEATHBLO.wav
|
||||||
#DRAINLIF.wav
|
#DRAINLIF.wav
|
||||||
#DRGNSLAY.wav
|
#DRGNSLAY.wav
|
||||||
#DISPELL.wav
|
|
||||||
#DISGUISE.wav
|
#DISGUISE.wav
|
||||||
#DISEASE.wav
|
#DISEASE.wav
|
||||||
#QUIKSAND.wav
|
#QUIKSAND.wav
|
||||||
|
@ -79,6 +79,6 @@
|
|||||||
76 -1 -1 0 0 0 0
|
76 -1 -1 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 -1 -1 0 0 0 0
|
79 0 80 0 0 0 0
|
||||||
80 -1 -1 0 0 0 0
|
80 -1 -1 0 0 0 0
|
||||||
-1
|
-1
|
@ -1791,9 +1791,10 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
|
|||||||
std::remove_if(immunities.begin(), immunities.end(), NegateRemover);
|
std::remove_if(immunities.begin(), immunities.end(), NegateRemover);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
&& 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;
|
||||||
}
|
}
|
||||||
//dispel helpful spells
|
//dispel helpful spells
|
||||||
|
@ -841,6 +841,10 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
|
|||||||
b.type = Bonus::CHANGES_SPELL_COST_FOR_ALLY; break;
|
b.type = Bonus::CHANGES_SPELL_COST_FOR_ALLY; break;
|
||||||
case 'e':
|
case 'e':
|
||||||
b.type = Bonus::DOUBLE_DAMAGE_CHANCE; break;
|
b.type = Bonus::DOUBLE_DAMAGE_CHANCE; break;
|
||||||
|
case 'E':
|
||||||
|
b.type = Bonus::DEATH_STARE;
|
||||||
|
b.subtype = 0; //Gorgon
|
||||||
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
b.type = Bonus::SPELL_DAMAGE_REDUCTION;
|
b.type = Bonus::SPELL_DAMAGE_REDUCTION;
|
||||||
b.subtype = -1; //all magic schools
|
b.subtype = -1; //all magic schools
|
||||||
|
@ -600,6 +600,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
|||||||
case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
|
case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
|
||||||
case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
|
case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
|
||||||
case Bonus::ENEMY_DEFENCE_REDUCTION:
|
case Bonus::ENEMY_DEFENCE_REDUCTION:
|
||||||
|
case Bonus::DEATH_STARE:
|
||||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSybtype(bonus->type, bonus->subtype))));
|
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSybtype(bonus->type, bonus->subtype))));
|
||||||
break;
|
break;
|
||||||
case Bonus::HATE:
|
case Bonus::HATE:
|
||||||
@ -644,7 +645,8 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
|||||||
fileName = "E_CHAMP.bmp"; break;
|
fileName = "E_CHAMP.bmp"; break;
|
||||||
case Bonus::DOUBLE_DAMAGE_CHANCE:
|
case Bonus::DOUBLE_DAMAGE_CHANCE:
|
||||||
fileName = "E_DBLOW.bmp"; break;
|
fileName = "E_DBLOW.bmp"; break;
|
||||||
//"E_DEATH.bmp"
|
case Bonus::DEATH_STARE:
|
||||||
|
fileName = "E_DEATH.bmp"; break;
|
||||||
//"E_DEFBON.bmp"
|
//"E_DEFBON.bmp"
|
||||||
case Bonus::NO_DISTANCE_PENALTY:
|
case Bonus::NO_DISTANCE_PENALTY:
|
||||||
fileName = "E_DIST.bmp"; break;
|
fileName = "E_DIST.bmp"; break;
|
||||||
|
@ -156,7 +156,8 @@ namespace PrimarySkill
|
|||||||
BONUS_NAME(DRAGON_NATURE) \
|
BONUS_NAME(DRAGON_NATURE) \
|
||||||
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*/
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "../client/CSoundBase.h"
|
#include "../client/CSoundBase.h"
|
||||||
#include "CGameHandler.h"
|
#include "CGameHandler.h"
|
||||||
|
#include <boost/random/mersenne_twister.hpp>
|
||||||
|
#include <boost/random/variate_generator.hpp>
|
||||||
|
#include <boost/random/poisson_distribution.hpp>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CGameHandler.cpp, part of VCMI engine
|
* CGameHandler.cpp, part of VCMI engine
|
||||||
@ -3401,6 +3404,11 @@ 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
|
||||||
|
{
|
||||||
|
sc.dmgToDisplay = usedSpellPower;
|
||||||
|
amin(sc.dmgToDisplay, (*attackedCres.begin())->count); // hopefully stack is already reduced after attack
|
||||||
|
}
|
||||||
|
|
||||||
sendAndApply(&sc);
|
sendAndApply(&sc);
|
||||||
|
|
||||||
@ -3585,6 +3593,27 @@ 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
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BattleStackAttacked bsa;
|
||||||
|
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||||
|
bsa.effect = spell->mainEffectAnim; //TODO: find which it is
|
||||||
|
bsa.damageAmount = usedSpellPower * (*it)->valOfBonuses(Bonus::STACK_HEALTH);
|
||||||
|
bsa.stackAttacked = (*it)->ID;
|
||||||
|
bsa.attackerID = -1;
|
||||||
|
(*it)->prepareAttacked(bsa);
|
||||||
|
si.stacks.push_back(bsa);
|
||||||
|
}
|
||||||
|
if(!si.stacks.empty())
|
||||||
|
sendAndApply(&si);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -4210,6 +4239,28 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (attacker->hasBonusOfType(Bonus::DEATH_STARE)) // spell id 79
|
||||||
|
{
|
||||||
|
int staredCreatures = 0;
|
||||||
|
double mean = attacker->count * attacker->valOfBonuses(Bonus::DEATH_STARE, 0) / 100;
|
||||||
|
if (mean >= 1)
|
||||||
|
{
|
||||||
|
boost::poisson_distribution<int, double> p((int)mean);
|
||||||
|
boost::mt19937 rng;
|
||||||
|
boost::variate_generator<boost::mt19937&, boost::poisson_distribution<int, double>> dice (rng, p);
|
||||||
|
staredCreatures += dice();
|
||||||
|
}
|
||||||
|
if (((int)(mean * 100)) < rand() % 100) //fractional chance for one last kill
|
||||||
|
++staredCreatures;
|
||||||
|
|
||||||
|
staredCreatures += attacker->type->level * attacker->valOfBonuses(Bonus::DEATH_STARE, 1);
|
||||||
|
if (staredCreatures)
|
||||||
|
{
|
||||||
|
if (bat.bsa.size() && bat.bsa[0].newAmount > 0) //TODO: death stare was not originally avaliable for multiple-hex attacks, but...
|
||||||
|
handleSpellCasting(79, 0, gs->curB->getStack(bat.bsa[0].stackAttacked)->position,
|
||||||
|
!attacker->attackerOwned, attacker->owner, NULL, NULL, staredCreatures, SpellCasting::AFTER_ATTACK_CASTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &pos)
|
bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &pos)
|
||||||
|
Loading…
Reference in New Issue
Block a user