1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Merge pull request #625 from Toneyisnow/toneyisnow/Battle_Clone_Effect

Implement the Clone Effect in battle.
This commit is contained in:
Alexander Shishkin
2020-01-27 13:42:58 +03:00
committed by GitHub
9 changed files with 154 additions and 7 deletions

View File

@ -739,6 +739,12 @@ void CPlayerInterface::battleUnitsChanged(const std::vector<UnitChanges> & units
if(unit->alive() && animation->isDead()) if(unit->alive() && animation->isDead())
animation->setType(CCreatureAnim::HOLDING); animation->setType(CCreatureAnim::HOLDING);
if (unit->isClone())
{
std::unique_ptr<ColorShifterDeepBlue> shifter(new ColorShifterDeepBlue());
animation->shiftColor(shifter.get());
}
//TODO: handle more cases //TODO: handle more cases
} }
break; break;

View File

@ -90,6 +90,12 @@ CBattleStackAnimation::CBattleStackAnimation(CBattleInterface * owner, const CSt
assert(myAnim); assert(myAnim);
} }
void CBattleStackAnimation::shiftColor(const ColorShifter * shifter)
{
assert(myAnim);
myAnim->shiftColor(shifter);
}
void CAttackAnimation::nextFrame() void CAttackAnimation::nextFrame()
{ {
if(myAnim->getType() != group) if(myAnim->getType() != group)

View File

@ -43,6 +43,8 @@ public:
const CStack * stack; //id of stack whose animation it is const CStack * stack; //id of stack whose animation it is
CBattleStackAnimation(CBattleInterface * _owner, const CStack * _stack); CBattleStackAnimation(CBattleInterface * _owner, const CStack * _stack);
void shiftColor(const ColorShifter * shifter);
}; };
/// This class is responsible for managing the battle attack animation /// This class is responsible for managing the battle attack animation

View File

@ -142,6 +142,15 @@ void CCreatureAnimation::setType(CCreatureAnim::EAnimType type)
play(); play();
} }
void CCreatureAnimation::shiftColor(const ColorShifter* shifter)
{
if(forward)
forward->shiftColor(shifter);
if(reverse)
reverse->shiftColor(shifter);
}
CCreatureAnimation::CCreatureAnimation(const std::string & name_, TSpeedController controller) CCreatureAnimation::CCreatureAnimation(const std::string & name_, TSpeedController controller)
: name(name_), : name(name_),
speed(0.1), speed(0.1),

View File

@ -104,6 +104,9 @@ public:
bool incrementFrame(float timePassed); bool incrementFrame(float timePassed);
void setBorderColor(SDL_Color palette); void setBorderColor(SDL_Color palette);
// tint color effect
void shiftColor(const ColorShifter * shifter);
float getCurrentFrame() const; // Gets the current frame ID relative to frame group. float getCurrentFrame() const; // Gets the current frame ID relative to frame group.
void playOnce(CCreatureAnim::EAnimType type); //plays once given stage of animation, then resets to 2 void playOnce(CCreatureAnim::EAnimType type); //plays once given stage of animation, then resets to 2

View File

@ -69,6 +69,9 @@ public:
class SDLImage : public IImage class SDLImage : public IImage
{ {
public: public:
const static int DEFAULT_PALETTE_COLORS = 256;
//Surface without empty borders //Surface without empty borders
SDL_Surface * surf; SDL_Surface * surf;
//size of left and top borders //size of left and top borders
@ -87,6 +90,9 @@ public:
SDLImage(SDL_Surface * from, bool extraRef); SDLImage(SDL_Surface * from, bool extraRef);
~SDLImage(); ~SDLImage();
// Keep the original palette, in order to do color switching operation
void savePalette();
void draw(SDL_Surface * where, int posX=0, int posY=0, Rect *src=nullptr, ui8 alpha=255) const override; void draw(SDL_Surface * where, int posX=0, int posY=0, Rect *src=nullptr, ui8 alpha=255) const override;
void draw(SDL_Surface * where, SDL_Rect * dest, SDL_Rect * src, ui8 alpha=255) const override; void draw(SDL_Surface * where, SDL_Rect * dest, SDL_Rect * src, ui8 alpha=255) const override;
std::shared_ptr<IImage> scaleFast(float scale) const override; std::shared_ptr<IImage> scaleFast(float scale) const override;
@ -100,10 +106,15 @@ public:
void verticalFlip() override; void verticalFlip() override;
void shiftPalette(int from, int howMany) override; void shiftPalette(int from, int howMany) override;
void adjustPalette(const ColorShifter * shifter) override;
void resetPalette() override;
void setBorderPallete(const BorderPallete & borderPallete) override; void setBorderPallete(const BorderPallete & borderPallete) override;
friend class SDLImageLoader; friend class SDLImageLoader;
private:
SDL_Palette * originalPalette;
}; };
class SDLImageLoader class SDLImageLoader
@ -497,8 +508,8 @@ void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_C
image->fullSize = FullSize; image->fullSize = FullSize;
//Prepare surface //Prepare surface
SDL_Palette * p = SDL_AllocPalette(256); SDL_Palette * p = SDL_AllocPalette(SDLImage::DEFAULT_PALETTE_COLORS);
SDL_SetPaletteColors(p, pal, 0, 256); SDL_SetPaletteColors(p, pal, 0, SDLImage::DEFAULT_PALETTE_COLORS);
SDL_SetSurfacePalette(image->surf, p); SDL_SetSurfacePalette(image->surf, p);
SDL_FreePalette(p); SDL_FreePalette(p);
@ -548,18 +559,27 @@ IImage::~IImage() = default;
SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group) SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group)
: surf(nullptr), : surf(nullptr),
margins(0, 0), margins(0, 0),
fullSize(0, 0) fullSize(0, 0),
originalPalette(nullptr)
{ {
SDLImageLoader loader(this); SDLImageLoader loader(this);
data->loadFrame(frame, group, loader); data->loadFrame(frame, group, loader);
savePalette();
} }
SDLImage::SDLImage(SDL_Surface * from, bool extraRef) SDLImage::SDLImage(SDL_Surface * from, bool extraRef)
: surf(nullptr), : surf(nullptr),
margins(0, 0), margins(0, 0),
fullSize(0, 0) fullSize(0, 0),
originalPalette(nullptr)
{ {
surf = from; surf = from;
if (surf == nullptr)
return;
savePalette();
if (extraRef) if (extraRef)
surf->refcount++; surf->refcount++;
fullSize.x = surf->w; fullSize.x = surf->w;
@ -569,7 +589,8 @@ SDLImage::SDLImage(SDL_Surface * from, bool extraRef)
SDLImage::SDLImage(const JsonNode & conf) SDLImage::SDLImage(const JsonNode & conf)
: surf(nullptr), : surf(nullptr),
margins(0, 0), margins(0, 0),
fullSize(0, 0) fullSize(0, 0),
originalPalette(nullptr)
{ {
std::string filename = conf["file"].String(); std::string filename = conf["file"].String();
@ -578,6 +599,8 @@ SDLImage::SDLImage(const JsonNode & conf)
if(surf == nullptr) if(surf == nullptr)
return; return;
savePalette();
const JsonNode & jsonMargins = conf["margins"]; const JsonNode & jsonMargins = conf["margins"];
margins.x = jsonMargins["left"].Integer(); margins.x = jsonMargins["left"].Integer();
@ -600,7 +623,8 @@ SDLImage::SDLImage(const JsonNode & conf)
SDLImage::SDLImage(std::string filename) SDLImage::SDLImage(std::string filename)
: surf(nullptr), : surf(nullptr),
margins(0, 0), margins(0, 0),
fullSize(0, 0) fullSize(0, 0),
originalPalette(nullptr)
{ {
surf = BitmapHandler::loadBitmap(filename); surf = BitmapHandler::loadBitmap(filename);
@ -611,6 +635,7 @@ SDLImage::SDLImage(std::string filename)
} }
else else
{ {
savePalette();
fullSize.x = surf->w; fullSize.x = surf->w;
fullSize.y = surf->h; fullSize.y = surf->h;
} }
@ -736,6 +761,19 @@ void SDLImage::verticalFlip()
surf = flipped; surf = flipped;
} }
// Keep the original palette, in order to do color switching operation
void SDLImage::savePalette()
{
// For some images that don't have palette, skip this
if(surf->format->palette == nullptr)
return;
if(originalPalette == nullptr)
originalPalette = SDL_AllocPalette(DEFAULT_PALETTE_COLORS);
SDL_SetPaletteColors(originalPalette, surf->format->palette->colors, 0, DEFAULT_PALETTE_COLORS);
}
void SDLImage::shiftPalette(int from, int howMany) void SDLImage::shiftPalette(int from, int howMany)
{ {
//works with at most 16 colors, if needed more -> increase values //works with at most 16 colors, if needed more -> increase values
@ -753,6 +791,29 @@ void SDLImage::shiftPalette(int from, int howMany)
} }
} }
void SDLImage::adjustPalette(const ColorShifter * shifter)
{
if(originalPalette == nullptr)
return;
SDL_Palette* palette = surf->format->palette;
// Note: here we skip the first 8 colors in the palette that predefined in H3Palette
for(int i = 8; i < palette->ncolors; i++)
{
palette->colors[i] = shifter->shiftColor(originalPalette->colors[i]);
}
}
void SDLImage::resetPalette()
{
if(originalPalette == nullptr)
return;
// Always keept the original palette not changed, copy a new palette to assign to surface
SDL_SetPaletteColors(surf->format->palette, originalPalette->colors, 0, originalPalette->ncolors);
}
void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete) void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
{ {
if(surf->format->palette) if(surf->format->palette)
@ -764,6 +825,12 @@ void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
SDLImage::~SDLImage() SDLImage::~SDLImage()
{ {
SDL_FreeSurface(surf); SDL_FreeSurface(surf);
if(originalPalette != nullptr)
{
SDL_FreePalette(originalPalette);
originalPalette = nullptr;
}
} }
std::shared_ptr<IImage> CAnimation::getFromExtraDef(std::string filename) std::shared_ptr<IImage> CAnimation::getFromExtraDef(std::string filename)
@ -1014,6 +1081,18 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra
load(index, targetGroup); load(index, targetGroup);
} }
void CAnimation::shiftColor(const ColorShifter * shifter)
{
for(auto groupIter = images.begin(); groupIter != images.end(); groupIter++)
{
for(auto frameIter = groupIter->second.begin(); frameIter != groupIter->second.end(); frameIter++)
{
std::shared_ptr<IImage> image = frameIter->second;
image->adjustPalette(shifter);
}
}
}
void CAnimation::setCustom(std::string filename, size_t frame, size_t group) void CAnimation::setCustom(std::string filename, size_t frame, size_t group)
{ {
if (source[group].size() <= frame) if (source[group].size() <= frame)

View File

@ -16,6 +16,7 @@
struct SDL_Surface; struct SDL_Surface;
class JsonNode; class JsonNode;
class CDefFile; class CDefFile;
class ColorShifter;
/* /*
* Base class for images, can be used for non-animation pictures as well * Base class for images, can be used for non-animation pictures as well
@ -44,6 +45,8 @@ public:
//only indexed bitmaps, 16 colors maximum //only indexed bitmaps, 16 colors maximum
virtual void shiftPalette(int from, int howMany) = 0; virtual void shiftPalette(int from, int howMany) = 0;
virtual void adjustPalette(const ColorShifter * shifter) = 0;
virtual void resetPalette() = 0;
//only indexed bitmaps, colors 5,6,7 must be special //only indexed bitmaps, colors 5,6,7 must be special
virtual void setBorderPallete(const BorderPallete & borderPallete) = 0; virtual void setBorderPallete(const BorderPallete & borderPallete) = 0;
@ -98,6 +101,9 @@ public:
//and loads it if animation is preloaded //and loads it if animation is preloaded
void duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup); void duplicateImage(const size_t sourceGroup, const size_t sourceFrame, const size_t targetGroup);
// adjust the color of the animation, used in battle spell effects, e.g. Cloned objects
void shiftColor(const ColorShifter * shifter);
//add custom surface to the selected position. //add custom surface to the selected position.
void setCustom(std::string filename, size_t frame, size_t group=0); void setCustom(std::string filename, size_t frame, size_t group=0);

View File

@ -152,6 +152,42 @@ struct ColorPutter
typedef void (*BlitterWithRotationVal)(SDL_Surface *src,SDL_Rect srcRect, SDL_Surface * dst, SDL_Rect dstRect, ui8 rotation); typedef void (*BlitterWithRotationVal)(SDL_Surface *src,SDL_Rect srcRect, SDL_Surface * dst, SDL_Rect dstRect, ui8 rotation);
class ColorShifter
{
public:
virtual SDL_Color shiftColor(SDL_Color clr) const = 0;
};
class ColorShifterLightBlue : public ColorShifter
{
public:
SDL_Color shiftColor(SDL_Color clr) const override
{
clr.b = clr.b + (255 - clr.b) / 2;
return clr;
}
};
class ColorShifterDeepBlue : public ColorShifter
{
public:
SDL_Color shiftColor(SDL_Color clr) const override
{
clr.b = 255;
return clr;
}
};
class ColorShifterDeepRed : public ColorShifter
{
public:
SDL_Color shiftColor(SDL_Color clr) const override
{
clr.r = 255;
return clr;
}
};
namespace CSDL_Ext namespace CSDL_Ext
{ {
/// helper that will safely set and un-set ClipRect for SDL_Surface /// helper that will safely set and un-set ClipRect for SDL_Surface

View File

@ -51,7 +51,7 @@ void Clone::apply(BattleStateProxy * battleState, RNG & rng, const Mechanics * m
if(clonedStack->getCount() < 1) if(clonedStack->getCount() < 1)
continue; continue;
auto hex = m->cb->getAvaliableHex(clonedStack->creatureId(), m->casterSide); auto hex = m->cb->getAvaliableHex(clonedStack->creatureId(), m->casterSide, clonedStack->getPosition());
if(!hex.isValid()) if(!hex.isValid())
{ {