فهرست منبع

Merge pull request #625 from Toneyisnow/toneyisnow/Battle_Clone_Effect

Implement the Clone Effect in battle.
Alexander Shishkin 5 سال پیش
والد
کامیت
00de1fd734

+ 6 - 0
client/CPlayerInterface.cpp

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

+ 6 - 0
client/battle/CBattleAnimations.cpp

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

+ 2 - 0
client/battle/CBattleAnimations.h

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

+ 9 - 0
client/battle/CCreatureAnimation.cpp

@@ -142,6 +142,15 @@ void CCreatureAnimation::setType(CCreatureAnim::EAnimType type)
 	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)
 	: name(name_),
 	  speed(0.1),

+ 3 - 0
client/battle/CCreatureAnimation.h

@@ -104,6 +104,9 @@ public:
 	bool incrementFrame(float timePassed);
 	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.
 
 	void playOnce(CCreatureAnim::EAnimType type); //plays once given stage of animation, then resets to 2

+ 85 - 6
client/gui/CAnimation.cpp

@@ -69,6 +69,9 @@ public:
 class SDLImage : public IImage
 {
 public:
+	
+	const static int DEFAULT_PALETTE_COLORS = 256;
+	
 	//Surface without empty borders
 	SDL_Surface * surf;
 	//size of left and top borders
@@ -87,6 +90,9 @@ public:
 	SDLImage(SDL_Surface * from, bool extraRef);
 	~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, SDL_Rect * dest, SDL_Rect * src, ui8 alpha=255) const override;
 	std::shared_ptr<IImage> scaleFast(float scale) const override;
@@ -100,10 +106,15 @@ public:
 	void verticalFlip() override;
 
 	void shiftPalette(int from, int howMany) override;
+	void adjustPalette(const ColorShifter * shifter) override;
+	void resetPalette() override;
 
 	void setBorderPallete(const BorderPallete & borderPallete) override;
 
 	friend class SDLImageLoader;
+
+private:
+	SDL_Palette * originalPalette;
 };
 
 class SDLImageLoader
@@ -497,8 +508,8 @@ void SDLImageLoader::init(Point SpriteSize, Point Margins, Point FullSize, SDL_C
 	image->fullSize = FullSize;
 
 	//Prepare surface
-	SDL_Palette * p = SDL_AllocPalette(256);
-	SDL_SetPaletteColors(p, pal, 0, 256);
+	SDL_Palette * p = SDL_AllocPalette(SDLImage::DEFAULT_PALETTE_COLORS);
+	SDL_SetPaletteColors(p, pal, 0, SDLImage::DEFAULT_PALETTE_COLORS);
 	SDL_SetSurfacePalette(image->surf, p);
 	SDL_FreePalette(p);
 
@@ -548,18 +559,27 @@ IImage::~IImage() = default;
 SDLImage::SDLImage(CDefFile * data, size_t frame, size_t group)
 	: surf(nullptr),
 	margins(0, 0),
-	fullSize(0, 0)
+	fullSize(0, 0),
+	originalPalette(nullptr)
 {
 	SDLImageLoader loader(this);
 	data->loadFrame(frame, group, loader);
+
+	savePalette();
 }
 
 SDLImage::SDLImage(SDL_Surface * from, bool extraRef)
 	: surf(nullptr),
 	margins(0, 0),
-	fullSize(0, 0)
+	fullSize(0, 0),
+	originalPalette(nullptr)
 {
 	surf = from;
+	if (surf == nullptr)
+		return;
+
+	savePalette();
+
 	if (extraRef)
 		surf->refcount++;
 	fullSize.x = surf->w;
@@ -569,7 +589,8 @@ SDLImage::SDLImage(SDL_Surface * from, bool extraRef)
 SDLImage::SDLImage(const JsonNode & conf)
 	: surf(nullptr),
 	margins(0, 0),
-	fullSize(0, 0)
+	fullSize(0, 0),
+	originalPalette(nullptr)
 {
 	std::string filename = conf["file"].String();
 
@@ -578,6 +599,8 @@ SDLImage::SDLImage(const JsonNode & conf)
 	if(surf == nullptr)
 		return;
 
+	savePalette();
+
 	const JsonNode & jsonMargins = conf["margins"];
 
 	margins.x = jsonMargins["left"].Integer();
@@ -600,7 +623,8 @@ SDLImage::SDLImage(const JsonNode & conf)
 SDLImage::SDLImage(std::string filename)
 	: surf(nullptr),
 	margins(0, 0),
-	fullSize(0, 0)
+	fullSize(0, 0),
+	originalPalette(nullptr)
 {
 	surf = BitmapHandler::loadBitmap(filename);
 
@@ -611,6 +635,7 @@ SDLImage::SDLImage(std::string filename)
 	}
 	else
 	{
+		savePalette();
 		fullSize.x = surf->w;
 		fullSize.y = surf->h;
 	}
@@ -736,6 +761,19 @@ void SDLImage::verticalFlip()
 	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)
 {
 	//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)
 {
 	if(surf->format->palette)
@@ -764,6 +825,12 @@ void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
 SDLImage::~SDLImage()
 {
 	SDL_FreeSurface(surf);
+
+	if(originalPalette != nullptr)
+	{
+		SDL_FreePalette(originalPalette);
+		originalPalette = nullptr;
+	}
 }
 
 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);
 }
 
+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)
 {
 	if (source[group].size() <= frame)

+ 6 - 0
client/gui/CAnimation.h

@@ -16,6 +16,7 @@
 struct SDL_Surface;
 class JsonNode;
 class CDefFile;
+class ColorShifter;
 
 /*
  * Base class for images, can be used for non-animation pictures as well
@@ -44,6 +45,8 @@ public:
 
 	//only indexed bitmaps, 16 colors maximum
 	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
 	virtual void setBorderPallete(const BorderPallete & borderPallete) = 0;
@@ -98,6 +101,9 @@ public:
 	//and loads it if animation is preloaded
 	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.
 	void setCustom(std::string filename, size_t frame, size_t group=0);
 

+ 36 - 0
client/gui/SDL_Extensions.h

@@ -152,6 +152,42 @@ struct ColorPutter
 
 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
 {
 	/// helper that will safely set and un-set ClipRect for SDL_Surface

+ 1 - 1
lib/spells/effects/Clone.cpp

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