mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-25 21:38:59 +02:00
Implemented configurable hit/affect animation
* need more testing
This commit is contained in:
parent
f4cf12d3f8
commit
75b93b070d
client/battle
config
lib
@ -20,6 +20,7 @@
|
||||
#include "../../lib/BattleState.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/CSpellHandler.h"
|
||||
|
||||
/*
|
||||
* CBattleAnimations.cpp, part of VCMI engine
|
||||
@ -865,83 +866,81 @@ void CShootingAnimation::endAnim()
|
||||
delete this;
|
||||
}
|
||||
|
||||
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx, int _dy, bool _Vflip, bool _areaEffect)
|
||||
:CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), x(0), y(0), dx(_dx), dy(_dy), Vflip(_Vflip) , areaEffect(_areaEffect)
|
||||
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx, int _dy, bool _Vflip, bool _alignToBottom)
|
||||
:CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), x(-1), y(-1), dx(_dx), dy(_dy), Vflip(_Vflip), alignToBottom(_alignToBottom)
|
||||
{
|
||||
logAnim->debugStream() << "Created spell anim for effect #" << effect;
|
||||
}
|
||||
|
||||
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip, bool _areaEffect)
|
||||
:CBattleAnimation(_owner), effect(-1), destTile(0), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy), Vflip(_Vflip), areaEffect(_areaEffect)
|
||||
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip, bool _alignToBottom)
|
||||
:CBattleAnimation(_owner), effect(-1), destTile(BattleHex::INVALID), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy), Vflip(_Vflip), alignToBottom(_alignToBottom)
|
||||
{
|
||||
logAnim->debugStream() << "Created spell anim for " << customAnim;
|
||||
}
|
||||
|
||||
CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip, bool _alignToBottom)
|
||||
:CBattleAnimation(_owner), effect(-1), destTile(_destTile), customAnim(_customAnim), x(-1), y(-1), dx(0), dy(0), Vflip(_Vflip), alignToBottom(_alignToBottom)
|
||||
{
|
||||
logAnim->debugStream() << "Created spell anim for " << customAnim;
|
||||
}
|
||||
|
||||
|
||||
bool CSpellEffectAnimation::init()
|
||||
{
|
||||
if(!isEarliest(true))
|
||||
return false;
|
||||
|
||||
if(effect == 12) //armageddon
|
||||
|
||||
if(customAnim.empty() && effect != ui32(-1) && !graphics->battleACToDef[effect].empty())
|
||||
{
|
||||
customAnim = graphics->battleACToDef[effect][0];
|
||||
}
|
||||
|
||||
if(customAnim.empty())
|
||||
{
|
||||
if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
|
||||
endAnim();
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool areaEffect = (!destTile.isValid() && x == -1 && y == -1);
|
||||
|
||||
if(areaEffect) //f.e. armageddon
|
||||
{
|
||||
CDefHandler * anim = CDefHandler::giveDef(customAnim);
|
||||
|
||||
for(int i=0; i * anim->width < owner->pos.w ; ++i)
|
||||
{
|
||||
CDefHandler * anim;
|
||||
if(customAnim.size())
|
||||
anim = CDefHandler::giveDef(customAnim);
|
||||
else
|
||||
anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
|
||||
|
||||
if (Vflip)
|
||||
for(int j=0; j * anim->height < owner->pos.h ; ++j)
|
||||
{
|
||||
for (auto & elem : anim->ourImages)
|
||||
BattleEffect be;
|
||||
be.effectID = ID;
|
||||
be.anim = CDefHandler::giveDef(customAnim);
|
||||
if (Vflip)
|
||||
{
|
||||
CSDL_Ext::VflipSurf(elem.bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i * anim->width < owner->pos.w ; ++i)
|
||||
{
|
||||
for(int j=0; j * anim->height < owner->pos.h ; ++j)
|
||||
{
|
||||
BattleEffect be;
|
||||
be.effectID = ID;
|
||||
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
|
||||
if (Vflip)
|
||||
for (auto & elem : be.anim->ourImages)
|
||||
{
|
||||
for (auto & elem : be.anim->ourImages)
|
||||
{
|
||||
CSDL_Ext::VflipSurf(elem.bitmap);
|
||||
}
|
||||
CSDL_Ext::VflipSurf(elem.bitmap);
|
||||
}
|
||||
be.currentFrame = 0;
|
||||
be.maxFrame = be.anim->ourImages.size();
|
||||
be.x = i * anim->width + owner->pos.x;
|
||||
be.y = j * anim->height + owner->pos.y;
|
||||
be.position = BattleHex::INVALID;
|
||||
|
||||
owner->battleEffects.push_back(be);
|
||||
}
|
||||
be.currentFrame = 0;
|
||||
be.maxFrame = be.anim->ourImages.size();
|
||||
be.x = i * anim->width + owner->pos.x;
|
||||
be.y = j * anim->height + owner->pos.y;
|
||||
be.position = BattleHex::INVALID;
|
||||
|
||||
owner->battleEffects.push_back(be);
|
||||
}
|
||||
}
|
||||
else //there is nothing to play
|
||||
{
|
||||
endAnim();
|
||||
return false;
|
||||
}
|
||||
|
||||
delete anim;
|
||||
}
|
||||
else // Effects targeted at a specific creature/hex.
|
||||
{
|
||||
if(effect == -1 || graphics->battleACToDef[effect].size() != 0)
|
||||
{
|
||||
|
||||
const CStack* destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(destTile, false);
|
||||
Rect &tilePos = owner->bfield[destTile]->pos;
|
||||
BattleEffect be;
|
||||
be.effectID = ID;
|
||||
if(customAnim.size())
|
||||
be.anim = CDefHandler::giveDef(customAnim);
|
||||
else
|
||||
be.anim = CDefHandler::giveDef(graphics->battleACToDef[effect][0]);
|
||||
be.anim = CDefHandler::giveDef(customAnim);
|
||||
|
||||
if (Vflip)
|
||||
{
|
||||
@ -953,28 +952,31 @@ bool CSpellEffectAnimation::init()
|
||||
|
||||
be.currentFrame = 0;
|
||||
be.maxFrame = be.anim->ourImages.size();
|
||||
if(effect == 1)
|
||||
be.maxFrame = 3;
|
||||
|
||||
//todo: lightning anim frame count override
|
||||
|
||||
// if(effect == 1)
|
||||
// be.maxFrame = 3;
|
||||
|
||||
switch (effect)
|
||||
if(x == -1)
|
||||
{
|
||||
be.x = tilePos.x + tilePos.w/2 - be.anim->width/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
case ui32(-1):
|
||||
be.x = x;
|
||||
}
|
||||
|
||||
if(y == -1)
|
||||
{
|
||||
if(alignToBottom)
|
||||
be.y = tilePos.y + tilePos.h - be.anim->height;
|
||||
else
|
||||
be.y = tilePos.y - be.anim->height/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
be.y = y;
|
||||
break;
|
||||
case 0: // Prayer and Lightning Bolt.
|
||||
case 1:
|
||||
case 19: // Slow
|
||||
// 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.
|
||||
@ -988,12 +990,7 @@ bool CSpellEffectAnimation::init()
|
||||
be.position = destTile;
|
||||
|
||||
owner->battleEffects.push_back(be);
|
||||
}
|
||||
else //there is nothing to play
|
||||
{
|
||||
endAnim();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
//battleEffects
|
||||
return true;
|
||||
|
@ -223,13 +223,14 @@ private:
|
||||
std::string customAnim;
|
||||
int x, y, dx, dy;
|
||||
bool Vflip;
|
||||
bool areaEffect;
|
||||
bool alignToBottom;
|
||||
public:
|
||||
bool init();
|
||||
void nextFrame();
|
||||
void endAnim();
|
||||
|
||||
CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _areaEffect = true);
|
||||
CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _areaEffect = true);
|
||||
CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);
|
||||
CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false);
|
||||
CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip = false, bool _alignToBottom = false);
|
||||
virtual ~CSpellEffectAnimation(){};
|
||||
};
|
||||
|
@ -1228,8 +1228,6 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
{
|
||||
const CSpell &spell = *CGI->spellh->objects[sc->id];
|
||||
|
||||
std::vector< std::string > anims; //for magic arrow and ice bolt
|
||||
|
||||
const std::string& castSoundPath = spell.getCastSound();
|
||||
|
||||
if(!castSoundPath.empty())
|
||||
@ -1243,6 +1241,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
//playing projectile animation
|
||||
if(sc->tile.isValid())
|
||||
{
|
||||
|
||||
//todo: srccoord of creature caster
|
||||
Point srccoord = (sc->side ? Point(770, 60) : Point(30, 60)) + pos;
|
||||
Point destcoord = CClickableHex::getXYUnitAnim(sc->tile, curInt->cb->battleGetStackByPos(sc->tile), this); //position attacked by projectile
|
||||
@ -1275,58 +1274,31 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
waitForAnims();
|
||||
|
||||
//queuing hit animation
|
||||
if(sc->tile.isValid())
|
||||
{
|
||||
for(const CSpell::TAnimation & animation : spell.animationInfo.hit)
|
||||
{
|
||||
//Point destcoord = CClickableHex::getXYUnitAnim(sc->tile, curInt->cb->battleGetStackByPos(sc->tile), this); //position attacked by projectile
|
||||
|
||||
//addNewAnim(new CSpellEffectAnimation(this, animation, destTile, 0, 0, false, areaEffect));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//whole battlefield
|
||||
for(const CSpell::TAnimation & animation : spell.animationInfo.hit)
|
||||
{
|
||||
addNewAnim(new CSpellEffectAnimation(this, animation.resourceName, sc->tile, false, animation.verticalPosition == VerticalPosition::BOTTOM));
|
||||
}
|
||||
|
||||
//queuing affect animation
|
||||
//queuing affect /resist animation
|
||||
for (auto & elem : sc->affectedCres)
|
||||
{
|
||||
for(const CSpell::TAnimation & animation : spell.animationInfo.affect)
|
||||
BattleHex position = curInt->cb->battleGetStackByID(elem, false)->position;
|
||||
|
||||
if(vstd::contains(sc->resisted,elem))
|
||||
{
|
||||
//Point destcoord = CClickableHex::getXYUnitAnim(sc->tile, curInt->cb->battleGetStackByPos(sc->tile), this); //position attacked by projectile
|
||||
|
||||
//addNewAnim(new CSpellEffectAnimation(this, animation, destTile, 0, 0, false, areaEffect));
|
||||
displayEffect(78, position);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const CSpell::TAnimation & animation : spell.animationInfo.affect)
|
||||
{
|
||||
addNewAnim(new CSpellEffectAnimation(this, animation.resourceName, position, false, animation.verticalPosition == VerticalPosition::BOTTOM));
|
||||
}
|
||||
}
|
||||
//displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(elem, false)->position);
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch(sc->id)
|
||||
{
|
||||
|
||||
case SpellID::LIGHTNING_BOLT:
|
||||
case SpellID::TITANS_LIGHTNING_BOLT:
|
||||
case SpellID::THUNDERBOLT:
|
||||
case SpellID::CHAIN_LIGHTNING: //TODO: zigzag effect
|
||||
for (auto & elem : sc->affectedCres) //in case we have multiple targets
|
||||
{
|
||||
displayEffect(1, curInt->cb->battleGetStackByID(elem, false)->position);
|
||||
displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(elem, false)->position);
|
||||
}
|
||||
break;
|
||||
case SpellID::DISPEL:
|
||||
case SpellID::CURE:
|
||||
case SpellID::RESURRECTION:
|
||||
case SpellID::ANIMATE_DEAD:
|
||||
case SpellID::DISPEL_HELPFUL_SPELLS:
|
||||
case SpellID::SACRIFICE: //TODO: animation upon killed stack
|
||||
for(auto & elem : sc->affectedCres)
|
||||
{
|
||||
displayEffect(spell.mainEffectAnim, curInt->cb->battleGetStackByID(elem, false)->position);
|
||||
}
|
||||
break;
|
||||
case SpellID::SUMMON_FIRE_ELEMENTAL:
|
||||
case SpellID::SUMMON_EARTH_ELEMENTAL:
|
||||
case SpellID::SUMMON_WATER_ELEMENTAL:
|
||||
@ -1337,18 +1309,12 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
break;
|
||||
} //switch(sc->id)
|
||||
|
||||
if (spell.isDamageSpell() && sc->affectedCres.empty()) //for example Inferno that causes no BattleStackAttacked
|
||||
{
|
||||
if(sc->tile.isValid() && graphics->battleACToDef.count(spell.mainEffectAnim)) //eg. when casting Lind Mine or Fire Wall
|
||||
displayEffect (spell.mainEffectAnim, sc->tile);
|
||||
}
|
||||
// if (spell.isDamageSpell() && sc->affectedCres.empty()) //for example Inferno that causes no BattleStackAttacked
|
||||
// {
|
||||
// if(sc->tile.isValid() && graphics->battleACToDef.count(spell.mainEffectAnim)) //eg. when casting Lind Mine or Fire Wall
|
||||
// displayEffect (spell.mainEffectAnim, sc->tile);
|
||||
// }
|
||||
|
||||
//support for resistance
|
||||
for(auto & elem : sc->resisted)
|
||||
{
|
||||
int tile = curInt->cb->battleGetStackByID(elem)->position;
|
||||
displayEffect(78, tile);
|
||||
}
|
||||
|
||||
//displaying message in console
|
||||
bool customSpell = false;
|
||||
@ -1511,16 +1477,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
|
||||
|
||||
void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
|
||||
{
|
||||
int effID = sse.effect.back().sid;
|
||||
if(effID != -1) //can be -1 for defensive stance effect
|
||||
{
|
||||
for(auto & elem : sse.stacks)
|
||||
{
|
||||
bool areaEffect(CGI->spellh->objects[effID]->getTargetType() == CSpell::ETargetType::NO_TARGET);
|
||||
displayEffect(CGI->spellh->objects[effID]->mainEffectAnim, curInt->cb->battleGetStackByID(elem)->position, areaEffect);
|
||||
}
|
||||
}
|
||||
else if (sse.stacks.size() == 1 && sse.effect.size() == 2)
|
||||
if (sse.effect.back().sid == -1 && sse.stacks.size() == 1 && sse.effect.size() == 2)
|
||||
{
|
||||
const Bonus & bns = sse.effect.front();
|
||||
if (bns.source == Bonus::OTHER && bns.type == Bonus::PRIMARY_SKILL)
|
||||
|
@ -11,8 +11,21 @@
|
||||
"animationQueue":{
|
||||
"type": "array",
|
||||
"items":{
|
||||
"type": "string",
|
||||
"format": "defFile"
|
||||
"anyOf":[
|
||||
{
|
||||
//assumed verticalPosition: top
|
||||
"type": "string",
|
||||
"format": "defFile"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties":{
|
||||
"verticalPosition": {"type":"string", "enum":["top","bottom"]},
|
||||
"defName": {"type":"string", "format": "defFile"}
|
||||
},
|
||||
"additionalProperties" : false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"animation":{
|
||||
|
@ -68,7 +68,7 @@
|
||||
"targetType": "CREATURE",
|
||||
"anim" : 38,
|
||||
"animation":{
|
||||
"hit":["C03SPA0", "C11SPA1"]
|
||||
"hit":[{"defName":"C03SPA0", "verticalPosition":"bottom"}, "C11SPA1"]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "LIGHTBLT"
|
||||
@ -119,7 +119,7 @@
|
||||
"targetType": "CREATURE",
|
||||
"anim" : 38,
|
||||
"animation":{
|
||||
"affect":["C03SPA0", "C11SPA1"]
|
||||
"affect":[{"defName":"C03SPA0", "verticalPosition":"bottom"}, "C11SPA1"]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "CHAINLTE"
|
||||
@ -323,7 +323,7 @@
|
||||
"targetType" : "CREATURE",
|
||||
"anim" : 38,
|
||||
"animation":{
|
||||
"hit":["C03SPA0", "C11SPA1"]
|
||||
"hit":[{"defName":"C03SPA0", "verticalPosition":"bottom"}, "C11SPA1"]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "LIGHTBLT"
|
||||
|
@ -591,7 +591,7 @@
|
||||
"targetType" : "CREATURE",
|
||||
"anim" : 0,
|
||||
"animation":{
|
||||
"affect":["C10SPW"]
|
||||
"affect":[{"defName":"C10SPW", "verticalPosition":"bottom"}]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "PRAYER"
|
||||
@ -901,7 +901,7 @@
|
||||
"targetType" : "CREATURE",
|
||||
"anim" : 19,
|
||||
"animation":{
|
||||
"affect":["C09SPE0"]
|
||||
"affect":[{"defName":"C09SPE0", "verticalPosition":"bottom"}]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "MUCKMIRE"
|
||||
|
@ -570,7 +570,7 @@ std::string CSpell::AnimationInfo::selectProjectile(const double angle) const
|
||||
if(info.minimumAngle < angle && info.minimumAngle > maximum)
|
||||
{
|
||||
maximum = info.minimumAngle;
|
||||
res = info.defName;
|
||||
res = info.resourceName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -886,16 +886,39 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
spell->iconScroll = graphicsNode["iconScroll"].String();
|
||||
|
||||
const JsonNode & animationNode = json["animation"];
|
||||
spell->animationInfo.affect = animationNode["affect"].convertTo<CSpell::TAnimationQueue>();
|
||||
spell->animationInfo.cast = animationNode["cast"].convertTo<CSpell::TAnimationQueue>();
|
||||
spell->animationInfo.hit = animationNode["hit"].convertTo<CSpell::TAnimationQueue>();
|
||||
|
||||
auto loadAnimationQueue = [&](const std::string & jsonName, CSpell::TAnimationQueue & q)
|
||||
{
|
||||
auto queueNode = animationNode[jsonName].Vector();
|
||||
for(const JsonNode & item : queueNode)
|
||||
{
|
||||
CSpell::TAnimation newItem;
|
||||
newItem.verticalPosition = VerticalPosition::TOP;
|
||||
|
||||
if(item.getType() == JsonNode::DATA_STRING)
|
||||
newItem.resourceName = item.String();
|
||||
else if(item.getType() == JsonNode::DATA_STRUCT)
|
||||
{
|
||||
newItem.resourceName = item["defName"].String();
|
||||
|
||||
auto vPosStr = item["verticalPosition"].String();
|
||||
if("bottom" == vPosStr)
|
||||
newItem.verticalPosition = VerticalPosition::BOTTOM;
|
||||
}
|
||||
q.push_back(newItem);
|
||||
}
|
||||
};
|
||||
|
||||
loadAnimationQueue("affect", spell->animationInfo.affect);
|
||||
loadAnimationQueue("cast", spell->animationInfo.cast);
|
||||
loadAnimationQueue("hit", spell->animationInfo.hit);
|
||||
|
||||
const JsonVector & projectile = animationNode["projectile"].Vector();
|
||||
|
||||
for(const JsonNode & item : projectile)
|
||||
{
|
||||
CSpell::ProjectileInfo info;
|
||||
info.defName = item["defName"].String();
|
||||
info.resourceName = item["defName"].String();
|
||||
info.minimumAngle = item["minimumAngle"].Float();
|
||||
|
||||
spell->animationInfo.projectile.push_back(info);
|
||||
|
@ -73,6 +73,7 @@ public:
|
||||
const BattleInfo * cb;
|
||||
};
|
||||
|
||||
enum class VerticalPosition : ui8{TOP, CENTER, BOTTOM};
|
||||
|
||||
class DLL_LINKAGE CSpell
|
||||
{
|
||||
@ -84,15 +85,26 @@ public:
|
||||
double minimumAngle;
|
||||
|
||||
///resource name
|
||||
std::string defName;
|
||||
std::string resourceName;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & minimumAngle & defName;
|
||||
h & minimumAngle & resourceName;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::string TAnimation;
|
||||
struct AnimationItem
|
||||
{
|
||||
std::string resourceName;
|
||||
VerticalPosition verticalPosition;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & resourceName & verticalPosition;
|
||||
}
|
||||
};
|
||||
|
||||
typedef AnimationItem TAnimation;
|
||||
typedef std::vector<TAnimation> TAnimationQueue;
|
||||
|
||||
struct DLL_LINKAGE AnimationInfo
|
||||
|
Loading…
x
Reference in New Issue
Block a user