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

* new spells

- protection from air
- protection from fire
- protection from water
- protection from earth
* a bit of refactoring in spell handling code
This commit is contained in:
mateuszb 2009-04-22 10:03:13 +00:00
parent e88ba16ffa
commit d14083272d
6 changed files with 178 additions and 142 deletions

View File

@ -261,28 +261,6 @@ CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, C
SDL_SetColorKey(idToObstacle[obst[t].ID]->ourImages[n].bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(idToObstacle[obst[t].ID]->ourImages[n].bitmap->format,0,255,255)); SDL_SetColorKey(idToObstacle[obst[t].ID]->ourImages[n].bitmap, SDL_SRCCOLORKEY, SDL_MapRGB(idToObstacle[obst[t].ID]->ourImages[n].bitmap->format,0,255,255));
} }
} }
//initializing spellToEffect
spellToEffect[17] = 1; //lightning bolt
spellToEffect[18] = 10; //implosion
spellToEffect[27] = 27; //shield
spellToEffect[28] = 2; //air shield
spellToEffect[35] = 41; //dispel
spellToEffect[41] = 36; //bless
spellToEffect[42] = 40; //curse
spellToEffect[43] = 4; //bloodlust
spellToEffect[45] = 56; //weakness
spellToEffect[46] = 54; //stone skin
spellToEffect[47] = 14; //disrupting ray
spellToEffect[48] = 0; //prayer
spellToEffect[49] = 20; //mirth
spellToEffect[50] = 30; //sorrow
spellToEffect[51] = 18; //fortune
spellToEffect[52] = 48; //misfortune
spellToEffect[53] = 31; //haste
spellToEffect[54] = 19; //slow
spellToEffect[56] = 17; //frenzy
spellToEffect[61] = 42; //forgetfulness
} }
CBattleInterface::~CBattleInterface() CBattleInterface::~CBattleInterface()
@ -1863,8 +1841,11 @@ void CBattleInterface::spellCasted(SpellCasted * sc)
SDL_SetClipRect(screen, &buf); //restoring previous clip rect SDL_SetClipRect(screen, &buf); //restoring previous clip rect
break; //for 15 and 16 cases break; //for 15 and 16 cases
} }
case 17: //lightning bolt
displayEffect(1, sc->tile);
displayEffect(CGI->spellh->spells[sc->id].mainEffectAnim, sc->tile);
case 35: //dispel case 35: //dispel
displayEffect(spellToEffect[sc->id], sc->tile); displayEffect(CGI->spellh->spells[sc->id].mainEffectAnim, sc->tile);
} //switch(sc->id) } //switch(sc->id)
} }
@ -1872,7 +1853,7 @@ void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
{ {
for(std::set<ui32>::const_iterator ci = sse.stacks.begin(); ci!=sse.stacks.end(); ++ci) for(std::set<ui32>::const_iterator ci = sse.stacks.begin(); ci!=sse.stacks.end(); ++ci)
{ {
displayEffect(spellToEffect[sse.effect.id], LOCPLINT->cb->battleGetStackByID(*ci)->position); displayEffect(CGI->spellh->spells[sse.effect.id].mainEffectAnim, LOCPLINT->cb->battleGetStackByID(*ci)->position);
} }
redrawBackgroundWithHexes(activeStack); redrawBackgroundWithHexes(activeStack);
} }

View File

@ -165,7 +165,6 @@ private:
std::map< int, CDefHandler * > idToProjectile; //projectiles of creaures (creatureID, defhandler) std::map< int, CDefHandler * > idToProjectile; //projectiles of creaures (creatureID, defhandler)
std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield std::map< int, CDefHandler * > idToObstacle; //obstacles located on the battlefield
std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation> std::map< int, bool > creDir; // <creatureID, if false reverse creature's animation>
std::map< int, int > spellToEffect; //which effect should be played when different spells are casted (spellID, effectID)
unsigned char animCount; unsigned char animCount;
int activeStack; //number of active stack; -1 - no one int activeStack; //number of active stack; -1 - no one
int mouseHoveredStack; //stack hovered by mouse; if -1 -> none int mouseHoveredStack; //stack hovered by mouse; if -1 -> none

View File

@ -1,73 +1,73 @@
//additional spell info, not included in original heroes III files //additional spell info, not included in original heroes III files
//[spellID - -1 is the end of data in file] [-1 -> spell is negative for influenced creatures; 0 - spell is indifferent for them; 1 - spell is poitive for them] [spell range description in SRSL, none magic] [basic] [advanced] [expert] //[spellID - -1 is the end of data in file] [-1 -> spell is negative for influenced creatures; 0 - spell is indifferent for them; 1 - spell is poitive for them] [main effect animation (AC format), -1 - none] [spell range description in SRSL, none magic] [basic] [advanced] [expert]
0 0 X X X X 0 0 -1 X X X X
1 0 X X X X 1 0 -1 X X X X
2 0 X X X X 2 0 -1 X X X X
3 0 X X X X 3 0 -1 X X X X
4 0 X X X X 4 0 -1 X X X X
5 0 X X X X 5 0 -1 X X X X
6 0 X X X X 6 0 -1 X X X X
7 0 X X X X 7 0 -1 X X X X
8 0 X X X X 8 0 -1 X X X X
9 0 X X X X 9 0 -1 X X X X
10 0 X X X X 10 0 -1 X X X X
11 0 X X X X 11 0 -1 X X X X
12 0 0 0 0 0 12 0 -1 0 0 0 0
13 0 0 0 0 0 13 0 -1 0 0 0 0
14 0 X X X X 14 0 -1 X X X X
15 -1 0 0 0 0 15 -1 64 0 0 0 0
16 -1 0 0 0 0 16 -1 46 0 0 0 0
17 -1 0 0 0 0 17 -1 38 0 0 0 0
18 -1 0 0 0 0 18 -1 10 0 0 0 0
19 -1 0 0 0 0 19 -1 -1 0 0 0 0
20 -1 1 1 1 1 20 -1 45 1 1 1 1
21 -1 0,1 0,1 0,1 0,1 21 -1 53 0,1 0,1 0,1 0,1
22 -1 0-2 0-2 0-2 0-2 22 -1 9 0-2 0-2 0-2 0-2
23 -1 0,1 0,1 0,1 0,1 23 -1 16 0,1 0,1 0,1 0,1
24 -1 X X X X 24 -1 8 X X X X
25 -1 X X X X 25 -1 29 X X X X
26 -1 X X X X 26 -1 12 X X X X
27 1 0 0 0 X 27 1 27 0 0 0 X
28 1 0 0 0 X 28 1 2 0 0 0 X
29 1 0 0 0 X 29 1 -1 0 0 0 X
30 1 0 0 0 X 30 1 22 0 0 0 X
31 1 0 0 0 X 31 1 24 0 0 0 X
32 1 0 0 0 X 32 1 23 0 0 0 X
33 1 0 0 0 X 33 1 26 0 0 0 X
34 1 0 0 0 X 34 1 -1 0 0 0 X
35 0 0 0 0 X 35 0 41 0 0 0 X
36 1 0 0 0 0 36 1 -1 0 0 0 0
37 1 0 0 0 0 37 1 -1 0 0 0 0
38 1 0 0 0 0 38 1 -1 0 0 0 0
39 1 0 0 0 0 39 1 -1 0 0 0 0
40 1 0 0 0 0 40 1 -1 0 0 0 0
41 1 0 0 0 X 41 1 36 0 0 0 X
42 -1 0 0 0 X 42 -1 40 0 0 0 X
43 1 0 0 0 X 43 1 4 0 0 0 X
44 1 0 0 0 X 44 1 -1 0 0 0 X
45 -1 0 0 0 X 45 -1 56 0 0 0 X
46 1 0 0 0 X 46 1 54 0 0 0 X
47 -1 0 0 0 X 47 -1 14 0 0 0 X
48 1 0 0 0 X 48 1 0 0 0 0 X
49 1 0 0 0 X 49 1 20 0 0 0 X
50 -1 0 0 0 X 50 -1 30 0 0 0 X
51 1 0 0 0 X 51 1 18 0 0 0 X
52 -1 0 0 0 X 52 -1 48 0 0 0 X
53 1 0 0 0 X 53 1 31 0 0 0 X
54 -1 0 0 0 X 54 -1 19 0 0 0 X
55 1 0 0 0 0 55 1 -1 0 0 0 0
56 1 0 0 0 0 56 1 17 0 0 0 0
57 -1 0 0 0 0 57 -1 -1 0 0 0 0
58 1 0 0 0 X 58 1 -1 0 0 0 X
59 -1 0 0 0-1 0-2 59 -1 -1 0 0 0-1 0-2
60 -1 0 0 0 0 60 -1 -1 0 0 0 0
61 -1 0 0 0 X 61 -1 42 0 0 0 X
62 -1 0 0 0 0 62 -1 -1 0 0 0 0
63 1 0 0 0 0 63 1 -1 0 0 0 0
64 0 X X X X 64 0 -1 X X X X
65 1 0 0 0 0 65 1 -1 0 0 0 0
66 0 X X X X 66 0 -1 X X X X
67 0 X X X X 67 0 -1 X X X X
68 0 X X X X 68 0 -1 X X X X
69 0 X X X X 69 0 -1 X X X X
-1 -1

View File

@ -255,6 +255,7 @@ void CSpellHandler::loadSpells()
nsp.id = spells.size(); nsp.id = spells.size();
nsp.combatSpell = combSpells; nsp.combatSpell = combSpells;
nsp.creatureAbility = creatureAbility; nsp.creatureAbility = creatureAbility;
nsp.mainEffectAnim = -1;
spells.push_back(nsp); spells.push_back(nsp);
} }
//loading of additional spell traits //loading of additional spell traits
@ -268,15 +269,18 @@ void CSpellHandler::loadSpells()
{ {
//reading header //reading header
std::string dump; std::string dump;
for(int i=0; i<52; ++i) ast>>dump; for(int i=0; i<60; ++i) ast>>dump;
//reading exact info //reading exact info
int spellID; int spellID;
ast>>spellID; ast>>spellID;
while(spellID != -1) while(spellID != -1)
{ {
int buf; int buf;
ast>>buf; ast >> buf;
spells[spellID].positiveness = buf; spells[spellID].positiveness = buf;
ast >> buf;
spells[spellID].mainEffectAnim = buf;
spells[spellID].range.resize(4); spells[spellID].range.resize(4);
for(int g=0; g<4; ++g) for(int g=0; g<4; ++g)
ast>>spells[spellID].range[g]; ast>>spells[spellID].range[g];

View File

@ -38,12 +38,12 @@ public:
si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
std::vector<std::string> range; //description of spell's range in SRSL by magic school level std::vector<std::string> range; //description of spell's range in SRSL by magic school level
std::set<ui16> rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const; //convert range to specific hexes std::set<ui16> rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const; //convert range to specific hexes
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs h & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs
& powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range; & powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range & mainEffectAnim;
} }
}; };

View File

@ -2246,6 +2246,81 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
} }
} }
ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature)
{
ui32 ret = 0; //value to return
switch(sp->id)
{
case 15: //magic arrow
{
ret = caster->getPrimSkillLevel(2) * 10 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 16: //ice bolt
{
ret = caster->getPrimSkillLevel(2) * 20 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 17: //lightning bolt
{
ret = caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 18: //implosion
{
ret = caster->getPrimSkillLevel(2) * 75 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 20: //frost ring
{
ret = caster->getPrimSkillLevel(2) * 10 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 21: //fireball
{
ret = caster->getPrimSkillLevel(2) * 10 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 22: //inferno
{
ret = caster->getPrimSkillLevel(2) * 10 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 23: //meteor shower
{
ret = caster->getPrimSkillLevel(2) * 10 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 24: //death ripple
{
ret = caster->getPrimSkillLevel(2) * 5 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 25: //destroy undead
{
ret = caster->getPrimSkillLevel(2) * 10 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
case 26: //armageddon
{
ret = caster->getPrimSkillLevel(2) * 50 + sp->powers[caster->getSpellSchoolLevel(sp)];
}
}
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
if(sp->air && affectedCreature->getEffect(30)) //air spell & protection from air
{
ret *= VLC->spellh->spells[30].powers[affectedCreature->getEffect(30)->level];
ret /= 100;
}
else if(sp->fire && affectedCreature->getEffect(31)) //fire spell & protection from fire
{
ret *= VLC->spellh->spells[31].powers[affectedCreature->getEffect(31)->level];
ret /= 100;
}
else if(sp->water && affectedCreature->getEffect(32)) //water spell & protection from water
{
ret *= VLC->spellh->spells[32].powers[affectedCreature->getEffect(32)->level];
ret /= 100;
}
else if (sp->earth && affectedCreature->getEffect(33)) //earth spell & protection from earth
{
ret *= VLC->spellh->spells[33].powers[affectedCreature->getEffect(33)->level];
ret /= 100;
}
return ret;
}
bool CGameHandler::makeCustomAction( BattleAction &ba ) bool CGameHandler::makeCustomAction( BattleAction &ba )
{ {
switch(ba.actionType) switch(ba.actionType)
@ -2281,14 +2356,14 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
//TODO: check resistances //TODO: check resistances
#define SPELL_CAST_TEMPLATE_2(EFFECT_ID, DAMAGE) \ #define SPELL_CAST_TEMPLATE_2 \
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) \
{ \ { \
BattleStackAttacked bsa; \ BattleStackAttacked bsa; \
bsa.flags |= 2; \ bsa.flags |= 2; \
bsa.effect = EFFECT_ID; \ bsa.effect = VLC->spellh->spells[ba.additionalInfo].mainEffectAnim; \
bsa.damageAmount = DAMAGE; \ bsa.damageAmount = calculateSpellDmg(&VLC->spellh->spells[ba.additionalInfo], h, *it); \
bsa.stackAttacked = (*it)->ID; \ bsa.stackAttacked = (*it)->ID; \
prepareAttacked(bsa,*it); \ prepareAttacked(bsa,*it); \
si.stacks.insert(bsa); \ si.stacks.insert(bsa); \
@ -2306,13 +2381,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
//it should spoil anything for other spells //it should spoil anything for other spells
std::set<ui16> attackedHexes = s->rangeInHexes(ba.destinationTile, h->getSpellSchoolLevel(s)); std::set<ui16> attackedHexes = s->rangeInHexes(ba.destinationTile, h->getSpellSchoolLevel(s));
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurences of two hex creatures*/ std::set<CStack*> attackedCres; /*std::set to exclude multiple occurences of two hex creatures*/
if(VLC->spellh->spells[ba.additionalInfo].attributes.find("CREATURE_TARGET") != std::string::npos) //spell to be cast on one specific creature if(VLC->spellh->spells[ba.additionalInfo].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
{
CStack * st = gs->curB->getStackT(ba.destinationTile);
if(st)
attackedCres.insert(st);
}
else if(VLC->spellh->spells[ba.additionalInfo].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
{ {
if(h->getSpellSchoolLevel(s) < 3) /*not expert */ if(h->getSpellSchoolLevel(s) < 3) /*not expert */
{ {
@ -2334,11 +2403,18 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
} }
} //if(h->getSpellSchoolLevel(s) < 3) } //if(h->getSpellSchoolLevel(s) < 3)
} }
else if(VLC->spellh->spells[ba.additionalInfo].attributes.find("CREATURE_TARGET") != std::string::npos) //spell to be cast on one specific creature
{
CStack * st = gs->curB->getStackT(ba.destinationTile);
if(st)
attackedCres.insert(st);
}
else //custom range from attackedHexes else //custom range from attackedHexes
{ {
for(std::set<ui16>::iterator it = attackedHexes.begin(); it != attackedHexes.end(); ++it) for(std::set<ui16>::iterator it = attackedHexes.begin(); it != attackedHexes.end(); ++it)
{ {
CStack * st = gs->curB->getStackT(*it); CStack * st = gs->curB->getStackT(*it);
if(st)
attackedCres.insert(st); attackedCres.insert(st);
} }
} }
@ -2347,43 +2423,15 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
switch(ba.additionalInfo) //spell id switch(ba.additionalInfo) //spell id
{ {
case 15: //magic arrow case 15: //magic arrow
{
SPELL_CAST_TEMPLATE_2(64, h->getPrimSkillLevel(2) * 10 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 16: //ice bolt case 16: //ice bolt
{
SPELL_CAST_TEMPLATE_2(46, h->getPrimSkillLevel(2) * 20 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 17: //lightning bolt case 17: //lightning bolt
{
SPELL_CAST_TEMPLATE_2(38, h->getPrimSkillLevel(2) * 25 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 18: //implosion case 18: //implosion
{
SPELL_CAST_TEMPLATE_2(10, h->getPrimSkillLevel(2) * 75 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 20: //frost ring case 20: //frost ring
{
SPELL_CAST_TEMPLATE_2(45, h->getPrimSkillLevel(2) * 10 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 21: //fireball case 21: //fireball
{
SPELL_CAST_TEMPLATE_2(53, h->getPrimSkillLevel(2) * 10 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 22: //inferno case 22: //inferno
{
SPELL_CAST_TEMPLATE_2(9, h->getPrimSkillLevel(2) * 10 + s->powers[h->getSpellSchoolLevel(s)]);
break;
}
case 23: //meteor shower case 23: //meteor shower
{ {
SPELL_CAST_TEMPLATE_2(16, h->getPrimSkillLevel(2) * 10 + s->powers[h->getSpellSchoolLevel(s)]); SPELL_CAST_TEMPLATE_2;
break; break;
} }
case 24: //death ripple case 24: //death ripple
@ -2396,7 +2444,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
attackedCres.insert(gs->curB->stacks[it]); attackedCres.insert(gs->curB->stacks[it]);
} }
if(attackedCres.size() == 0) break; if(attackedCres.size() == 0) break;
SPELL_CAST_TEMPLATE_2(8, h->getPrimSkillLevel(2) * 5 + s->powers[h->getSpellSchoolLevel(s)]); SPELL_CAST_TEMPLATE_2;
break; break;
} }
case 25: //destroy undead case 25: //destroy undead
@ -2409,7 +2457,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
attackedCres.insert(gs->curB->stacks[it]); attackedCres.insert(gs->curB->stacks[it]);
} }
if(attackedCres.size() == 0) break; if(attackedCres.size() == 0) break;
SPELL_CAST_TEMPLATE_2(29, h->getPrimSkillLevel(2) * 10 + s->powers[h->getSpellSchoolLevel(s)]); SPELL_CAST_TEMPLATE_2;
break; break;
} }
case 26: //armageddon case 26: //armageddon
@ -2421,11 +2469,15 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
attackedCres.insert(gs->curB->stacks[it]); attackedCres.insert(gs->curB->stacks[it]);
} }
if(attackedCres.size() == 0) break; if(attackedCres.size() == 0) break;
SPELL_CAST_TEMPLATE_2(12, h->getPrimSkillLevel(2) * 50 + s->powers[h->getSpellSchoolLevel(s)]); SPELL_CAST_TEMPLATE_2;
break; break;
} }
case 27: //shield case 27: //shield
case 28: //air shield case 28: //air shield
case 30: //protection from air
case 31: //protection from fire
case 32: //protection from water
case 33: //protection from earth
case 41: //bless case 41: //bless
case 42: //curse case 42: //curse
case 43: //bloodlust case 43: //bloodlust