1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Support for Enchanter ability.

This commit is contained in:
DjWarmonger 2011-10-09 07:20:23 +00:00
parent d607d90a91
commit 5e40d3da72
8 changed files with 81 additions and 26 deletions

View File

@ -1416,7 +1416,14 @@
"level": 6, "level": 6,
"name": [ "Enchanter" ], "name": [ "Enchanter" ],
"faction": -1, "faction": -1,
"ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ] ], //Enchanter //first aid tent can heal "ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ],
[ "ENCHANTER", 3, 28, 3], //air shield
[ "ENCHANTER", 3, 41, 3], //bless
[ "ENCHANTER", 3, 45, 3], //wealness
[ "ENCHANTER", 3, 46, 3], //stone skin
[ "ENCHANTER", 3, 53, 3], //slow
[ "ENCHANTER", 3, 54, 3], //haster
[ "CASTS", 5, 0, 0]], //Enchanter
"defname": "CENCH.DEF", "defname": "CENCH.DEF",
"projectile_defname": "SMBALX.DEF", "projectile_defname": "SMBALX.DEF",
"projectile_spin": false "projectile_spin": false
@ -1427,8 +1434,8 @@
"level": 4, "level": 4,
"name": [ "Sharpshooter" ], "name": [ "Sharpshooter" ],
"faction": -1, "faction": -1,
"ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ], //arrow turret "ability_add": [ [ "NO_OBSTACLES_PENALTY", 0, 0, 0 ],
[ "NO_DISTANCE_PENALTY", 0, 0, 0 ] ], //Sharpshooter //Ammo Cart [ "NO_DISTANCE_PENALTY", 0, 0, 0 ] ], //Sharpshooter
"defname": "CSHARP.DEF", "defname": "CSHARP.DEF",
"projectile_defname": "PELFX.DEF", "projectile_defname": "PELFX.DEF",
"projectile_spin": false "projectile_spin": false

View File

@ -327,7 +327,7 @@ namespace SpellCasting
}; };
enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING, //also includes cast before attack enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING, //also includes cast before attack
MAGIC_MIRROR, CREATURE_ACTIVE_CASTING}; MAGIC_MIRROR, CREATURE_ACTIVE_CASTING, ENCHANTER_CASTING};
} }
namespace Buildings namespace Buildings

View File

@ -1462,6 +1462,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int terType, const
curB->heroes[1] = const_cast<CGHeroInstance*>(heroes[1]); curB->heroes[1] = const_cast<CGHeroInstance*>(heroes[1]);
curB->round = -2; curB->round = -2;
curB->activeStack = -1; curB->activeStack = -1;
curB->enchanterCounter[0] = curB->enchanterCounter[1] = 0; //ready to cast
if(town) if(town)
{ {
@ -1915,7 +1916,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpellHere( int play
if(moreGeneralProblem != SpellCasting::OK) if(moreGeneralProblem != SpellCasting::OK)
return moreGeneralProblem; return moreGeneralProblem;
if (mode != SpellCasting::CREATURE_ACTIVE_CASTING) if (mode != SpellCasting::CREATURE_ACTIVE_CASTING && mode != SpellCasting::ENCHANTER_CASTING)
return battleIsImmune(getHero(player), spell, mode, dest); return battleIsImmune(getHero(player), spell, mode, dest);
else else
return battleIsImmune(NULL, spell, mode, dest); return battleIsImmune(NULL, spell, mode, dest);

View File

@ -59,6 +59,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
std::vector<CObstacleInstance> obstacles; std::vector<CObstacleInstance> obstacles;
ui8 castSpells[2]; //how many spells each side has cast this turn [0] - attacker, [1] - defender ui8 castSpells[2]; //how many spells each side has cast this turn [0] - attacker, [1] - defender
std::vector<const CSpell *> usedSpellsHistory[2]; //each time hero casts spell, it's inserted here -> eagle eye skill std::vector<const CSpell *> usedSpellsHistory[2]; //each time hero casts spell, it's inserted here -> eagle eye skill
si16 enchanterCounter[2]; //tends to pass through 0, so sign is needed
SiegeInfo si; SiegeInfo si;
si32 battlefieldType; si32 battlefieldType;
@ -70,7 +71,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
h & sides & round & activeStack & siege & town & tile & stacks & belligerents & obstacles h & sides & round & activeStack & siege & town & tile & stacks & belligerents & obstacles
& castSpells & si & battlefieldType; & castSpells & si & battlefieldType;
h & heroes; h & heroes;
h & usedSpellsHistory; h & usedSpellsHistory & enchanterCounter;
h & tacticsSide & tacticDistance; h & tacticsSide & tacticDistance;
h & static_cast<CBonusSystemNode&>(*this); h & static_cast<CBonusSystemNode&>(*this);
} }

View File

@ -135,7 +135,7 @@ namespace PrimarySkill
BONUS_NAME(NO_DISTANCE_PENALTY) \ BONUS_NAME(NO_DISTANCE_PENALTY) \
BONUS_NAME(NO_OBSTACLES_PENALTY) \ BONUS_NAME(NO_OBSTACLES_PENALTY) \
BONUS_NAME(SELF_LUCK) /*halfling*/ \ BONUS_NAME(SELF_LUCK) /*halfling*/ \
BONUS_NAME(ENCHANTER)/* for Enchanter spells, subtype - spell id */ \ BONUS_NAME(ENCHANTER)/* for Enchanter spells, val - skill level, subtype - spell id, additionalInfo - cooldown */ \
BONUS_NAME(HEALER) \ BONUS_NAME(HEALER) \
BONUS_NAME(SIEGE_WEAPON) \ BONUS_NAME(SIEGE_WEAPON) \
BONUS_NAME(HYPNOTIZED) \ BONUS_NAME(HYPNOTIZED) \

View File

@ -1506,7 +1506,7 @@ struct BattleSetStackProperty : public CPackForClient //3018
{ {
BattleSetStackProperty(){type = 3018;}; BattleSetStackProperty(){type = 3018;};
enum BattleStackProperty {CASTS, CURRENT_SPELL}; enum BattleStackProperty {CASTS, ENCHANTER_COUNTER};
DLL_EXPORT void applyGs(CGameState *gs); DLL_EXPORT void applyGs(CGameState *gs);
//void applyCl(CClient *cl){}; //void applyCl(CClient *cl){};

View File

@ -839,6 +839,11 @@ DLL_EXPORT void BattleStart::applyGs( CGameState *gs )
DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs ) DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
{ {
gs->curB->castSpells[0] = gs->curB->castSpells[1] = 0; gs->curB->castSpells[0] = gs->curB->castSpells[1] = 0;
for (int i = 0; i < 2; ++i)
{
amax(--gs->curB->enchanterCounter[i], 0);
}
gs->curB->round = round; gs->curB->round = round;
BOOST_FOREACH(CStack *s, gs->curB->stacks) BOOST_FOREACH(CStack *s, gs->curB->stacks)
@ -1296,6 +1301,16 @@ DLL_EXPORT void BattleSetStackProperty::applyGs(CGameState *gs)
amax(stack->casts, 0); amax(stack->casts, 0);
break; break;
} }
case ENCHANTER_COUNTER:
{
int side = gs->curB->whatSide(stack->owner);
if (absolute)
gs->curB->enchanterCounter[side] = val;
else
gs->curB->enchanterCounter[side] += val;
amax(gs->curB->enchanterCounter[side], 0);
break;
}
} }
} }

View File

@ -3344,13 +3344,6 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, NULL, secHero, 0, SpellCasting::CREATURE_ACTIVE_CASTING, stack); handleSpellCasting(spellID, spellLvl, destination, casterSide, stack->owner, NULL, secHero, 0, SpellCasting::CREATURE_ACTIVE_CASTING, stack);
BattleSetStackProperty ssp;
ssp.stackID = ba.stackNumber;
ssp.which = BattleSetStackProperty::CASTS; //reduce number of casts
ssp.val = -1;
ssp.absolute = false;
sendAndApply(&ssp);
sendAndApply(&end_action); sendAndApply(&end_action);
break; break;
} }
@ -3505,10 +3498,27 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
sc.attackerType = (stack ? stack->type->idNumber : -1); sc.attackerType = (stack ? stack->type->idNumber : -1);
//calculating affected creatures for all spells //calculating affected creatures for all spells
std::set<CStack*> attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination); std::set<CStack*> attackedCres;
for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it) if (mode != SpellCasting::ENCHANTER_CASTING)
{ {
sc.affectedCres.insert((*it)->ID); attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination);
for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
{
sc.affectedCres.insert((*it)->ID);
}
}
else //enchanter - hit all possible stacks
{
BOOST_FOREACH (CStack * stack, gs->curB->stacks)
{
/*if it's non negative spell and our unit or non positive spell and hostile unit */
if((spell->positiveness >= 0 && stack->owner == casterColor)
||(spell->positiveness <= 0 && stack->owner != casterColor ))
{
if(stack->alive()) //TODO: allow dead targets somewhere in the future
attackedCres.insert(stack);
}
}
} }
//checking if creatures resist //checking if creatures resist
@ -3844,6 +3854,16 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
if(!si.stacks.empty()) //after spellcast info shows if(!si.stacks.empty()) //after spellcast info shows
sendAndApply(&si); sendAndApply(&si);
if (mode == SpellCasting::CREATURE_ACTIVE_CASTING || mode == SpellCasting::ENCHANTER_CASTING) //reduce number of casts remaining
{
BattleSetStackProperty ssp;
ssp.stackID = stack->ID;
ssp.which = BattleSetStackProperty::CASTS;
ssp.val = -1;
ssp.absolute = false;
sendAndApply(&ssp);
}
//Magic Mirror effect //Magic Mirror effect
if (spell->positiveness < 0 && mode != SpellCasting::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence if (spell->positiveness < 0 && mode != SpellCasting::MAGIC_MIRROR && spell->level && spell->range[0] == "0") //it is actual spell and can be reflected to single target, no recurrence
{ {
@ -4007,14 +4027,25 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
} }
} }
} }
BonusList * bl = st->getBonuses(Selector::type(Bonus::ENCHANTER)).get(); BonusList bl = *(st->getBonuses(Selector::type(Bonus::ENCHANTER)));
if (bl->size()) int side = gs->curB->whatSide(st->owner);
if (bl.size() && st->casts && !gs->curB->enchanterCounter[side])
{ {
bte.effect = Bonus::ENCHANTER; int index = rand() % bl.size();
int index = rand() % bl->size(); int spellID = bl[index]->subtype; //spell ID
bte.val = (*bl)[index]->subtype; //spell ID if (gs->curB->battleCanCastThisSpell(st->owner, VLC->spellh->spells[spellID], SpellCasting::ENCHANTER_CASTING)); //TODO: select another?
bte.additionalInfo = (*bl)[index]->val; //spell level {
sendAndApply(&bte); int spellLeveL = bl[index]->val; //spell level
const CGHeroInstance * enemyHero = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
handleSpellCasting(spellID, spellLeveL, -1, side, st->owner, NULL, enemyHero, 0, SpellCasting::ENCHANTER_CASTING, st);
BattleSetStackProperty ssp;
ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
ssp.absolute = false;
ssp.val = bl[index]->additionalInfo; //increase cooldown counter
ssp.stackID = st->ID;
sendAndApply(&ssp);
}
} }
} }
} }