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:
parent
1a08772bc8
commit
451c08922c
@ -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)
|
||||
|
@ -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__
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user