1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

* spell animations are handled by new battle animation engine

* armageddon works when there are dead stack on the battlefield
This commit is contained in:
mateuszb 2009-09-17 12:59:04 +00:00
parent 1a08772bc8
commit 451c08922c
3 changed files with 172 additions and 93 deletions

View File

@ -113,6 +113,136 @@ CBattleAnimation::CBattleAnimation(CBattleInterface * _owner)
: owner(_owner), ID(_owner->animIDhelper++)
{}
//effect animation
bool CSpellEffectAnim::init()
{
if(!isEarliest(false))
return false;
if(effect == 12) //armageddon
{
if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
{
CDefHandler * anim;
if(customAnim.size())
anim = CDefHandler::giveDef(customAnim);
else
anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
for(int i=0; i * anim->width < owner->pos.w ; ++i)
{
for(int j=0; j * anim->height < owner->pos.h ; ++j)
{
SBattleEffect be;
be.effectID = ID;
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
be.frame = 0;
be.maxFrame = be.anim->ourImages.size();
be.x = i * anim->width;
be.y = j * anim->height;
owner->battleEffects.push_back(be);
}
}
}
}
else // Effects targeted at a specific creature/hex.
{
if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
{
const CStack* destStack = LOCPLINT->cb->battleGetStackByPos(destTile, false);
Rect &tilePos = owner->bfield[destTile].pos;
SBattleEffect be;
be.effectID = ID;
if(customAnim.size())
be.anim = CDefHandler::giveDef(customAnim);
else
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
be.frame = 0;
be.maxFrame = be.anim->ourImages.size();
switch (effect)
{
case -1:
be.x = x;
be.y = y;
break;
case 0: // Prayer and Lightning Bolt.
case 1:
// Position effect with it's bottom center touching the bottom center of affected tile(s).
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
be.y = tilePos.y + tilePos.h - be.anim->height;
break;
default:
// Position effect with it's center touching the top center of affected tile(s).
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
be.y = tilePos.y - be.anim->height/2;
break;
}
// Correction for 2-hex creatures.
if (destStack != NULL && destStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
owner->battleEffects.push_back(be);
}
}
//battleEffects
return true;
}
void CSpellEffectAnim::nextFrame()
{
for(std::list<SBattleEffect>::iterator it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
{
++(it->frame);
if(it->frame == it->maxFrame)
{
endAnim();
break;
}
else
{
it->x += dx;
it->y += dy;
}
}
}
void CSpellEffectAnim::endAnim()
{
CBattleAnimation::endAnim();
std::vector<std::list<SBattleEffect>::iterator> toDel;
for(std::list<SBattleEffect>::iterator it = owner->battleEffects.begin(); it != owner->battleEffects.end(); ++it)
{
if(it->effectID == ID)
{
toDel.push_back(it);
}
}
for(int b=0; b<toDel.size(); ++b)
{
owner->battleEffects.erase(toDel[b]);
}
delete this;
}
CSpellEffectAnim::CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, int _destTile, int _dx, int _dy)
:CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), dx(_dx), dy(_dy)
{
}
CSpellEffectAnim::CSpellEffectAnim(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy)
:CBattleAnimation(_owner), effect(-1), destTile(0), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy)
{
}
//stack's aniamtion
CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * _owner, int stack)
@ -250,6 +380,9 @@ bool CDefenceAnim::init()
// return false;
//}
if(IDby == -1 && owner->battleEffects.size() > 0)
return false;
int lowestMoveID = owner->animIDhelper + 5;
for(std::list<std::pair<CBattleAnimation *, bool> >::iterator it = owner->pendingAnims.begin(); it != owner->pendingAnims.end(); ++it)
{
@ -261,9 +394,12 @@ bool CDefenceAnim::init()
continue;
const CStack * attacker = LOCPLINT->cb->battleGetStackByID(IDby, false);
if(IDby != -1)
{
int attackerAnimType = owner->creAnims[IDby]->getType();
if( attackerAnimType == 11 && attackerAnimType == 12 && attackerAnimType == 13 && owner->creAnims[IDby]->getFrame() < attacker->creature->attackClimaxFrame )
return false;
}
CReverseAnim * animAsRev = dynamic_cast<CReverseAnim *>(it->first);
@ -281,7 +417,7 @@ bool CDefenceAnim::init()
const CStack * attacked = LOCPLINT->cb->battleGetStackByID(stackID, false);
//reverse unit if necessary
if(isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[IDby]))
if(attacker && isToReverse(attacked->position, attacker->position, owner->creDir[stackID], attacker->hasFeatureOfType(StackFeature::DOUBLE_WIDE), owner->creDir[IDby]))
{
owner->addNewAnim(new CReverseAnim(owner, stackID, attacked->position, true));
return false;
@ -1388,22 +1524,10 @@ void CBattleInterface::show(SDL_Surface * to)
//showing spell effects
if(battleEffects.size())
{
std::vector< std::list<SBattleEffect>::iterator > toErase;
for(std::list<SBattleEffect>::iterator it = battleEffects.begin(); it!=battleEffects.end(); ++it)
{
SDL_Surface * bitmapToBlit = it->anim->ourImages[(it->frame)%it->anim->ourImages.size()].bitmap;
SDL_BlitSurface(bitmapToBlit, NULL, to, &genRect(bitmapToBlit->h, bitmapToBlit->w, pos.x + it->x, pos.y + it->y));
++(it->frame);
if(it->frame == it->maxFrame)
{
toErase.push_back(it);
}
}
for(size_t b=0; b<toErase.size(); ++b)
{
delete toErase[b]->anim;
battleEffects.erase(toErase[b]);
}
}
@ -2319,27 +2443,16 @@ void CBattleInterface::spellCast(SpellCast * sc)
animToDisplay = anims[4];
//displaying animation
CDefEssential * animDef = CDefHandler::giveDefEss(animToDisplay);
int steps = sqrt((float)((destcoord.first - srccoord.first)*(destcoord.first - srccoord.first) + (destcoord.second - srccoord.second) * (destcoord.second - srccoord.second))) / 40;
if(steps <= 0)
steps = 1;
CDefHandler * animDef = CDefHandler::giveDef(animToDisplay);
int dx = (destcoord.first - srccoord.first - animDef->ourImages[0].bitmap->w)/steps, dy = (destcoord.second - srccoord.second - animDef->ourImages[0].bitmap->h)/steps;
SDL_Rect buf;
SDL_GetClipRect(screen, &buf);
SDL_SetClipRect(screen, &pos); //setting rect we can blit to
for(int g=0; g<steps; ++g)
{
show(screen);
SDL_Rect & srcr = animDef->ourImages[g%animDef->ourImages.size()].bitmap->clip_rect;
SDL_Rect dstr = genRect(srcr.h, srcr.w, srccoord.first + g*dx, srccoord.second + g*dy);
SDL_BlitSurface(animDef->ourImages[g%animDef->ourImages.size()].bitmap, &srcr, screen, &dstr);
CSDL_Ext::update(screen);
SDL_framerateDelay(LOCPLINT->mainFPSmng);
}
SDL_SetClipRect(screen, &buf); //restoring previous clip rect
delete animDef;
addNewAnim(new CSpellEffectAnim(this, animToDisplay, srccoord.first, srccoord.second, dx, dy));
break; //for 15 and 16 cases
}
case 17: //lightning bolt
@ -2447,61 +2560,7 @@ void CBattleInterface::castThisSpell(int spellID)
void CBattleInterface::displayEffect(ui32 effect, int destTile)
{
if(effect == 12) //armageddon
{
if(graphics->battleACToDef[effect].size() != 0)
{
CDefHandler * anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
for(int i=0; i * anim->width < pos.w ; ++i)
{
for(int j=0; j * anim->height < pos.h ; ++j)
{
SBattleEffect be;
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
be.frame = 0;
be.maxFrame = be.anim->ourImages.size();
be.x = i * anim->width;
be.y = j * anim->height;
battleEffects.push_back(be);
}
}
}
}
else // Effects targeted at a specific creature/hex.
{
if(graphics->battleACToDef[effect].size() != 0)
{
const CStack* destStack = LOCPLINT->cb->battleGetStackByPos(destTile, false);
Rect &tilePos = bfield[destTile].pos;
SBattleEffect be;
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
be.frame = 0;
be.maxFrame = be.anim->ourImages.size();
switch (effect) {
case 0: // Prayer and Lightning Bolt.
case 1:
// Position effect with it's bottom center touching the bottom center of affected tile(s).
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
be.y = tilePos.y + tilePos.h - be.anim->height;
break;
default:
// Position effect with it's center touching the top center of affected tile(s).
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
be.y = tilePos.y - be.anim->height/2;
break;
}
// Correction for 2-hex creatures.
if (destStack != NULL && destStack->hasFeatureOfType(StackFeature::DOUBLE_WIDE))
be.x += (destStack->attackerOwned ? -1 : 1)*tilePos.w/2;
battleEffects.push_back(be);
}
}
//battleEffects
addNewAnim(new CSpellEffectAnim(this, effect, destTile));
}
void CBattleInterface::setAnimSpeed(int set)

View File

@ -72,6 +72,22 @@ public:
CBattleAnimation(CBattleInterface * _owner);
};
class CSpellEffectAnim : public CBattleAnimation
{
private:
ui32 effect;
int destTile;
std::string customAnim;
int x, y, dx, dy;
public:
bool init();
void nextFrame();
void endAnim();
CSpellEffectAnim(CBattleInterface * _owner, ui32 _effect, int _destTile, int _dx = 0, int _dy = 0);
CSpellEffectAnim(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0);
};
class CBattleStackAnimation : public CBattleAnimation
{
public:
@ -319,6 +335,14 @@ struct BattleSettings
}
};
struct SBattleEffect
{
int x, y; //position on the screen
int frame, maxFrame;
CDefHandler * anim; //animation to display
int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim
};
class CBattleInterface : public CIntObject
{
private:
@ -361,12 +385,6 @@ private:
bool blockedByObstacle(int hex) const;
bool isCatapultAttackable(int hex) const; //returns true if given tile can be attacked by catapult
struct SBattleEffect
{
int x, y; //position on the screen
int frame, maxFrame;
CDefHandler * anim; //animation to display
};
std::list<SBattleEffect> battleEffects; //different animations to display on the screen like spell effects
class SiegeHelper
@ -468,6 +486,7 @@ public:
friend class CBattleAttack;
friend class CMeleeAttack;
friend class CShootingAnim;
friend class CSpellEffectAnim;
};
#endif // __CBATTLEINTERFACE_H__

View File

@ -2540,6 +2540,7 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHer
|| (s->id == 26) //Armageddon
)
{
if(stacks[it]->alive())
attackedCres.insert(stacks[it]);
}
}