mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Added fading animation for fade-in effect for summons
This commit is contained in:
parent
b2f5a87a0f
commit
fb3a08e0a6
@ -589,6 +589,42 @@ ResurrectionAnimation::ResurrectionAnimation(BattleInterface & owner, const CSta
|
||||
|
||||
}
|
||||
|
||||
bool FadingAnimation::init()
|
||||
{
|
||||
logAnim->info("FadingAnimation::init: stack %s", stack->getName());
|
||||
//TODO: pause animation?
|
||||
return true;
|
||||
}
|
||||
|
||||
void FadingAnimation::nextFrame()
|
||||
{
|
||||
float elapsed = GH.mainFPSmng->getElapsedMilliseconds() / 1000.f;
|
||||
float fullTime = AnimationControls::getFadeInDuration();
|
||||
float delta = elapsed / fullTime;
|
||||
progress += delta;
|
||||
|
||||
if (progress > 1.0f)
|
||||
progress = 1.0f;
|
||||
|
||||
uint8_t blueFactor = stack->cloned ? 0 : 255;
|
||||
uint8_t blueAdded = stack->cloned ? 255 : 0;
|
||||
uint8_t alpha = CSDL_Ext::lerp(from, dest, progress);
|
||||
|
||||
ColorShifterMultiplyAndAdd shifterFade ({255, 255, blueFactor, alpha}, {0, 0, blueAdded, 0});
|
||||
stackAnimation(stack)->shiftColor(&shifterFade);
|
||||
|
||||
if (progress == 1.0f)
|
||||
delete this;
|
||||
}
|
||||
|
||||
FadingAnimation::FadingAnimation(BattleInterface & owner, const CStack * _stack, uint8_t alphaFrom, uint8_t alphaDest):
|
||||
BattleStackAnimation(owner, _stack),
|
||||
from(alphaFrom),
|
||||
dest(alphaDest)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
RangedAttackAnimation::RangedAttackAnimation(BattleInterface & owner_, const CStack * attacker, BattleHex dest_, const CStack * defender)
|
||||
: AttackAnimation(owner_, attacker, dest_, defender),
|
||||
projectileEmitted(false)
|
||||
@ -707,7 +743,6 @@ void RangedAttackAnimation::nextFrame()
|
||||
|
||||
RangedAttackAnimation::~RangedAttackAnimation()
|
||||
{
|
||||
//FIXME: this assert triggers under some unclear, rare conditions. Possibly - if game window is inactive and/or in foreground/minimized?
|
||||
assert(!owner.projectilesController->hasActiveProjectile(attackingStack));
|
||||
assert(projectileEmitted);
|
||||
|
||||
@ -846,7 +881,7 @@ void CastAnimation::createProjectile(const Point & from, const Point & dest) con
|
||||
|
||||
uint32_t CastAnimation::getAttackClimaxFrame() const
|
||||
{
|
||||
//FIXME: allow defining this parameter in config file, separately from attackClimaxFrame of missile attacks
|
||||
//TODO: allow defining this parameter in config file, separately from attackClimaxFrame of missile attacks
|
||||
uint32_t maxFrames = stackAnimation(attackingStack)->framesInGroup(group);
|
||||
|
||||
if (maxFrames > 2)
|
||||
@ -1117,7 +1152,7 @@ void HeroCastAnimation::nextFrame()
|
||||
{
|
||||
float frame = hero->getFrame();
|
||||
|
||||
if (frame < 4.0f)
|
||||
if (frame < 4.0f) // middle point of animation //TODO: un-hardcode
|
||||
return;
|
||||
|
||||
if (!projectileEmitted)
|
||||
@ -1130,7 +1165,7 @@ void HeroCastAnimation::nextFrame()
|
||||
if (!owner.projectilesController->hasActiveProjectile(nullptr))
|
||||
{
|
||||
emitAnimationEvent();
|
||||
//FIXME: check H3 - it is possible that hero animation should be paused until hit effect is over, not just projectile
|
||||
//TODO: check H3 - it is possible that hero animation should be paused until hit effect is over, not just projectile
|
||||
hero->play();
|
||||
}
|
||||
}
|
||||
|
@ -205,9 +205,21 @@ public:
|
||||
ResurrectionAnimation(BattleInterface & owner, const CStack * _stack);
|
||||
};
|
||||
|
||||
/// Performs fade-in or fade-out animation on stack
|
||||
class FadingAnimation : public BattleStackAnimation
|
||||
{
|
||||
float progress;
|
||||
uint8_t from;
|
||||
uint8_t dest;
|
||||
public:
|
||||
bool init() override;
|
||||
void nextFrame() override;
|
||||
|
||||
FadingAnimation(BattleInterface & owner, const CStack * _stack, uint8_t alphaFrom, uint8_t alphaDest);
|
||||
};
|
||||
|
||||
class RangedAttackAnimation : public AttackAnimation
|
||||
{
|
||||
|
||||
void setAnimationGroup();
|
||||
void initializeProjectile();
|
||||
void emitProjectile();
|
||||
|
@ -62,7 +62,7 @@ enum Type // list of creature animations, numbers were taken from def files
|
||||
HITTED = 3, // base animation for when stack is taking damage
|
||||
DEFENCE = 4, // alternative animation for defending in melee if stack spent its action on defending
|
||||
DEATH = 5,
|
||||
DEATH_RANGED = 6, // alternative animation for when stack is killed by ranged attack
|
||||
DEATH_RANGED = 6, // Optional, alternative animation for when stack is killed by ranged attack
|
||||
TURN_L = 7,
|
||||
TURN_R = 8,
|
||||
//TURN_L2 = 9, //unused - identical to TURN_L
|
||||
@ -70,14 +70,14 @@ enum Type // list of creature animations, numbers were taken from def files
|
||||
ATTACK_UP = 11,
|
||||
ATTACK_FRONT = 12,
|
||||
ATTACK_DOWN = 13,
|
||||
SHOOT_UP = 14,
|
||||
SHOOT_FRONT = 15,
|
||||
SHOOT_DOWN = 16,
|
||||
CAST_UP = 17,
|
||||
CAST_FRONT = 18,
|
||||
CAST_DOWN = 19,
|
||||
MOVE_START = 20, // small animation to be played before MOVING
|
||||
MOVE_END = 21, // small animation to be played after MOVING
|
||||
SHOOT_UP = 14, // Shooters only
|
||||
SHOOT_FRONT = 15, // Shooters only
|
||||
SHOOT_DOWN = 16, // Shooters only
|
||||
CAST_UP = 17, // If empty, fallback to CAST_FRONT
|
||||
CAST_FRONT = 18, // Used for any special moves - dragon breath, spellcasting, (possibly - Pit Lord/Ogre Mage ability)
|
||||
CAST_DOWN = 19, // If empty, fallback to CAST_FRONT
|
||||
MOVE_START = 20, // small animation to be played before MOVING
|
||||
MOVE_END = 21, // small animation to be played after MOVING
|
||||
|
||||
DEAD = 22, // new group, used to show dead stacks. If empty - last frame from "DEATH" will be copied here
|
||||
DEAD_RANGED = 23, // new group, used to show dead stacks (if DEATH_RANGED was used). If empty - last frame from "DEATH_RANGED" will be copied here
|
||||
|
@ -73,7 +73,6 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
|
||||
//don't show animation when no HP is regenerated
|
||||
switch(bte.effect)
|
||||
{
|
||||
//TODO: move to bonus type handler
|
||||
case Bonus::HP_REGENERATION:
|
||||
displayEffect(EBattleEffect::REGENERATION, soundBase::REGENER, stack->getPosition());
|
||||
break;
|
||||
|
@ -318,7 +318,7 @@ void BattleInterface::stackReset(const CStack * stack)
|
||||
|
||||
void BattleInterface::stackAdded(const CStack * stack)
|
||||
{
|
||||
stacksController->stackAdded(stack);
|
||||
stacksController->stackAdded(stack, false);
|
||||
}
|
||||
|
||||
void BattleInterface::stackRemoved(uint32_t stackID)
|
||||
@ -328,7 +328,7 @@ void BattleInterface::stackRemoved(uint32_t stackID)
|
||||
queue->update();
|
||||
}
|
||||
|
||||
void BattleInterface::stackActivated(const CStack *stack) //TODO: check it all before game state is changed due to abilities
|
||||
void BattleInterface::stackActivated(const CStack *stack)
|
||||
{
|
||||
stacksController->stackActivated(stack);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
|
||||
std::vector<const CStack*> stacks = owner.curInt->cb->battleGetAllStacks(true);
|
||||
for(const CStack * s : stacks)
|
||||
{
|
||||
stackAdded(s);
|
||||
stackAdded(s, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,17 +172,15 @@ void BattleStacksController::stackReset(const CStack * stack)
|
||||
});
|
||||
}
|
||||
|
||||
static const ColorShifterMultiplyAndAdd shifterClone ({255, 255, 0, 255}, {0, 0, 255, 0});
|
||||
|
||||
if (stack->isClone())
|
||||
{
|
||||
animation->shiftColor(&shifterClone);
|
||||
}
|
||||
|
||||
//static const ColorShifterMultiplyAndAdd shifterClone ({255, 255, 0, 255}, {0, 0, 255, 0});
|
||||
//if (stack->isClone())
|
||||
//{
|
||||
// animation->shiftColor(&shifterClone);
|
||||
//}
|
||||
//owner.waitForAnimationCondition(EAnimationEvents::ACTION, false);
|
||||
}
|
||||
|
||||
void BattleStacksController::stackAdded(const CStack * stack)
|
||||
void BattleStacksController::stackAdded(const CStack * stack, bool instant)
|
||||
{
|
||||
// Tower shooters have only their upper half visible
|
||||
static const int turretCreatureAnimationHeight = 235;
|
||||
@ -212,6 +210,17 @@ void BattleStacksController::stackAdded(const CStack * stack)
|
||||
stackAnimation[stack->ID]->pos.y = coords.y;
|
||||
stackAnimation[stack->ID]->pos.w = stackAnimation[stack->ID]->getWidth();
|
||||
stackAnimation[stack->ID]->setType(ECreatureAnimType::HOLDING);
|
||||
|
||||
if (!instant)
|
||||
{
|
||||
ColorShifterMultiplyAndAdd shifterFade ({255, 255, 255, 0}, {0, 0, 0, 0});
|
||||
stackAnimation[stack->ID]->shiftColor(&shifterFade);
|
||||
|
||||
owner.executeOnAnimationCondition(EAnimationEvents::HIT, true, [=]()
|
||||
{
|
||||
addNewAnim(new FadingAnimation(owner, stack, 0, 255));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void BattleStacksController::setActiveStack(const CStack *stack)
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
bool facingRight(const CStack * stack) const;
|
||||
|
||||
void stackReset(const CStack * stack);
|
||||
void stackAdded(const CStack * stack); //new stack appeared on battlefield
|
||||
void stackAdded(const CStack * stack, bool instant); //new stack appeared on battlefield
|
||||
void stackRemoved(uint32_t stackID); //stack disappeared from batlefiled
|
||||
void stackActivated(const CStack *stack); //active stack has been changed
|
||||
void stackMoved(const CStack *stack, std::vector<BattleHex> destHex, int distance); //stack with id number moved to destHex
|
||||
|
@ -19,6 +19,11 @@ static const SDL_Color creatureBlueBorder = { 0, 255, 255, 255 };
|
||||
static const SDL_Color creatureGoldBorder = { 255, 255, 0, 255 };
|
||||
static const SDL_Color creatureNoBorder = { 0, 0, 0, 0 };
|
||||
|
||||
static SDL_Color genShadow(ui8 alpha)
|
||||
{
|
||||
return CSDL_Ext::makeColor(0, 0, 0, alpha);
|
||||
}
|
||||
|
||||
SDL_Color AnimationControls::getBlueBorder()
|
||||
{
|
||||
return creatureBlueBorder;
|
||||
@ -134,6 +139,11 @@ float AnimationControls::getFlightDistance(const CCreature * creature)
|
||||
return static_cast<float>(creature->animation.flightAnimationDistance * 200);
|
||||
}
|
||||
|
||||
float AnimationControls::getFadeInDuration()
|
||||
{
|
||||
return 1.0f / settings["battle"]["animationSpeed"].Float();
|
||||
}
|
||||
|
||||
ECreatureAnimType::Type CreatureAnimation::getType() const
|
||||
{
|
||||
return type;
|
||||
@ -150,6 +160,10 @@ void CreatureAnimation::setType(ECreatureAnimType::Type type)
|
||||
|
||||
void CreatureAnimation::shiftColor(const ColorShifter* shifter)
|
||||
{
|
||||
SDL_Color shadowTest = shifter->shiftColor(genShadow(128));
|
||||
|
||||
shadowAlpha = shadowTest.a;
|
||||
|
||||
if(forward)
|
||||
forward->shiftColor(shifter);
|
||||
|
||||
@ -160,6 +174,7 @@ void CreatureAnimation::shiftColor(const ColorShifter* shifter)
|
||||
CreatureAnimation::CreatureAnimation(const std::string & name_, TSpeedController controller)
|
||||
: name(name_),
|
||||
speed(0.1f),
|
||||
shadowAlpha(128),
|
||||
currentFrame(0),
|
||||
elapsedTime(0),
|
||||
type(ECreatureAnimType::HOLDING),
|
||||
@ -281,11 +296,6 @@ inline int getBorderStrength(float time)
|
||||
return static_cast<int>(borderStrength * 155 + 100); // scale to 0-255
|
||||
}
|
||||
|
||||
static SDL_Color genShadow(ui8 alpha)
|
||||
{
|
||||
return CSDL_Ext::makeColor(0, 0, 0, alpha);
|
||||
}
|
||||
|
||||
static SDL_Color genBorderColor(ui8 alpha, const SDL_Color & base)
|
||||
{
|
||||
return CSDL_Ext::makeColor(base.r, base.g, base.b, ui8(base.a * alpha / 256));
|
||||
@ -306,11 +316,16 @@ static SDL_Color addColors(const SDL_Color & base, const SDL_Color & over)
|
||||
);
|
||||
}
|
||||
|
||||
void CreatureAnimation::genBorderPalette(IImage::BorderPallete & target)
|
||||
void CreatureAnimation::genSpecialPalette(IImage::SpecialPalette & target)
|
||||
{
|
||||
target[0] = genBorderColor(getBorderStrength(elapsedTime), border);
|
||||
target[1] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border));
|
||||
target[2] = addColors(genShadow(64), genBorderColor(getBorderStrength(elapsedTime), border));
|
||||
target[1] = genShadow(shadowAlpha / 2);
|
||||
target[2] = genShadow(shadowAlpha / 2);
|
||||
target[3] = genShadow(shadowAlpha);
|
||||
target[4] = genShadow(shadowAlpha);
|
||||
target[5] = genBorderColor(getBorderStrength(elapsedTime), border);
|
||||
target[6] = addColors(genShadow(shadowAlpha), genBorderColor(getBorderStrength(elapsedTime), border));
|
||||
target[7] = addColors(genShadow(shadowAlpha / 2), genBorderColor(getBorderStrength(elapsedTime), border));
|
||||
}
|
||||
|
||||
void CreatureAnimation::nextFrame(Canvas & canvas, bool facingRight)
|
||||
@ -326,12 +341,13 @@ void CreatureAnimation::nextFrame(Canvas & canvas, bool facingRight)
|
||||
|
||||
if(image)
|
||||
{
|
||||
IImage::BorderPallete borderPallete;
|
||||
genBorderPalette(borderPallete);
|
||||
IImage::SpecialPalette SpecialPalette;
|
||||
genSpecialPalette(SpecialPalette);
|
||||
|
||||
image->setBorderPallete(borderPallete);
|
||||
image->setSpecialPallete(SpecialPalette);
|
||||
|
||||
canvas.draw(image, pos.topLeft(), Rect(0, 0, pos.w, pos.h));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,9 @@ namespace AnimationControls
|
||||
|
||||
/// Returns distance on which flying creatures should during one animation loop
|
||||
float getFlightDistance(const CCreature * creature);
|
||||
|
||||
/// Returns total time for full fade-in effect on newly summoned creatures, in seconds
|
||||
float getFadeInDuration();
|
||||
}
|
||||
|
||||
/// Class which manages animations of creatures/units inside battles
|
||||
@ -80,6 +83,9 @@ private:
|
||||
///type of animation being displayed
|
||||
ECreatureAnimType::Type type;
|
||||
|
||||
/// current value of shadow transparency
|
||||
uint8_t shadowAlpha;
|
||||
|
||||
/// border color, disabled if alpha = 0
|
||||
SDL_Color border;
|
||||
|
||||
@ -90,7 +96,7 @@ private:
|
||||
|
||||
void endAnimation();
|
||||
|
||||
void genBorderPalette(IImage::BorderPallete & target);
|
||||
void genSpecialPalette(IImage::SpecialPalette & target);
|
||||
public:
|
||||
|
||||
/// function(s) that will be called when animation ends, after reset to 1st frame
|
||||
|
@ -108,7 +108,7 @@ public:
|
||||
void adjustPalette(const ColorShifter * shifter) override;
|
||||
void resetPalette() override;
|
||||
|
||||
void setBorderPallete(const BorderPallete & borderPallete) override;
|
||||
void setSpecialPallete(const SpecialPalette & SpecialPalette) override;
|
||||
|
||||
friend class SDLImageLoader;
|
||||
|
||||
@ -212,32 +212,17 @@ CDefFile::CDefFile(std::string Name):
|
||||
data(nullptr),
|
||||
palette(nullptr)
|
||||
{
|
||||
|
||||
#if 0
|
||||
static SDL_Color H3_ORIG_PALETTE[8] =
|
||||
{
|
||||
{ 0, 255, 255, SDL_ALPHA_OPAQUE},
|
||||
{255, 150, 255, SDL_ALPHA_OPAQUE},
|
||||
{255, 100, 255, SDL_ALPHA_OPAQUE},
|
||||
{255, 50, 255, SDL_ALPHA_OPAQUE},
|
||||
{255, 0, 255, SDL_ALPHA_OPAQUE},
|
||||
{255, 255, 0, SDL_ALPHA_OPAQUE},
|
||||
{180, 0, 255, SDL_ALPHA_OPAQUE},
|
||||
{ 0, 255, 0, SDL_ALPHA_OPAQUE}
|
||||
};
|
||||
#endif // 0
|
||||
|
||||
//First 8 colors in def palette used for transparency
|
||||
static SDL_Color H3Palette[8] =
|
||||
{
|
||||
{ 0, 0, 0, 0},// 100% - transparency
|
||||
{ 0, 0, 0, 32},// 75% - shadow border,
|
||||
{ 0, 0, 0, 64},// TODO: find exact value
|
||||
{ 0, 0, 0, 128},// TODO: for transparency
|
||||
{ 0, 0, 0, 128},// 50% - shadow body
|
||||
{ 0, 0, 0, 0},// 100% - selection highlight
|
||||
{ 0, 0, 0, 128},// 50% - shadow body below selection
|
||||
{ 0, 0, 0, 64} // 75% - shadow border below selection
|
||||
{ 0, 0, 0, 0},// transparency ( used in most images )
|
||||
{ 0, 0, 0, 64},// shadow border ( used in battle, adventure map def's )
|
||||
{ 0, 0, 0, 64},// shadow border ( used in fog-of-war def's )
|
||||
{ 0, 0, 0, 128},// shadow body ( used in fog-of-war def's )
|
||||
{ 0, 0, 0, 128},// shadow body ( used in battle, adventure map def's )
|
||||
{ 0, 0, 0, 0},// selection ( used in battle def's )
|
||||
{ 0, 0, 0, 128},// shadow body below selection ( used in battle def's )
|
||||
{ 0, 0, 0, 64} // shadow border below selection ( used in battle def's )
|
||||
};
|
||||
data = animationCache.getCachedFile(ResourceID(std::string("SPRITES/") + Name, EResType::ANIMATION));
|
||||
|
||||
@ -827,11 +812,11 @@ void SDLImage::resetPalette()
|
||||
SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors);
|
||||
}
|
||||
|
||||
void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
|
||||
void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette)
|
||||
{
|
||||
if(surf->format->palette)
|
||||
{
|
||||
SDL_SetColors(surf, const_cast<SDL_Color *>(borderPallete.data()), 5, 3);
|
||||
SDL_SetColors(surf, const_cast<SDL_Color *>(SpecialPalette.data()), 1, 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ class ColorShifter;
|
||||
class IImage
|
||||
{
|
||||
public:
|
||||
using BorderPallete = std::array<SDL_Color, 3>;
|
||||
using SpecialPalette = std::array<SDL_Color, 7>;
|
||||
|
||||
//draws image on surface "where" at position
|
||||
virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, const Rect * src = nullptr, ui8 alpha = 255) const=0;
|
||||
@ -65,8 +65,8 @@ public:
|
||||
virtual void adjustPalette(const ColorShifter * shifter) = 0;
|
||||
virtual void resetPalette() = 0;
|
||||
|
||||
//only indexed bitmaps, colors 5,6,7 must be special
|
||||
virtual void setBorderPallete(const BorderPallete & borderPallete) = 0;
|
||||
//only indexed bitmaps with 7 special colors
|
||||
virtual void setSpecialPallete(const SpecialPalette & SpecialPalette) = 0;
|
||||
|
||||
virtual void horizontalFlip() = 0;
|
||||
virtual void verticalFlip() = 0;
|
||||
|
@ -52,6 +52,13 @@ void Canvas::draw(std::shared_ptr<IImage> image, const Point & pos, const Rect &
|
||||
image->draw(surface, pos.x, pos.y, &sourceRect);
|
||||
}
|
||||
|
||||
void Canvas::draw(std::shared_ptr<IImage> image, const Point & pos, const Rect & sourceRect, uint8_t alpha)
|
||||
{
|
||||
assert(image);
|
||||
if (image)
|
||||
image->draw(surface, pos.x, pos.y, &sourceRect, alpha);
|
||||
}
|
||||
|
||||
void Canvas::draw(Canvas & image, const Point & pos)
|
||||
{
|
||||
blitAt(image.surface, pos.x, pos.y, surface);
|
||||
|
@ -41,6 +41,10 @@ public:
|
||||
/// renders section of image bounded by sourceRect at specified position
|
||||
void draw(std::shared_ptr<IImage> image, const Point & pos, const Rect & sourceRect);
|
||||
|
||||
/// renders section of image bounded by sourceRect at specified position at specific transparency value
|
||||
void draw(std::shared_ptr<IImage> image, const Point & pos, const Rect & sourceRect, uint8_t alpha);
|
||||
|
||||
|
||||
/// renders another canvas onto this canvas
|
||||
void draw(Canvas & image, const Point & pos);
|
||||
|
||||
|
@ -592,7 +592,6 @@
|
||||
"index" : 65,
|
||||
"targetType" : "CREATURE",
|
||||
"animation":{
|
||||
"cast":[2]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "CLONE"
|
||||
@ -636,7 +635,6 @@
|
||||
"index" : 66,
|
||||
"targetType" : "NO_TARGET",
|
||||
"animation":{
|
||||
"cast":[2]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
@ -662,7 +660,6 @@
|
||||
"index" : 67,
|
||||
"targetType" : "NO_TARGET",
|
||||
"animation":{
|
||||
"cast":[2]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
@ -688,7 +685,6 @@
|
||||
"index" : 68,
|
||||
"targetType" : "NO_TARGET",
|
||||
"animation":{
|
||||
"cast":[2]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
@ -714,7 +710,6 @@
|
||||
"index" : 69,
|
||||
"targetType" : "NO_TARGET",
|
||||
"animation":{
|
||||
"cast":[2]
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
|
Loading…
Reference in New Issue
Block a user