mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	BattleInt split is finished, start of refactoring:
- Refactoring of siege controller code - Replaced some usages of C struct SDL_Surface with proper c++ class IImage - Refactoring of rendering of battlefield objects (WIP)
This commit is contained in:
		| @@ -370,7 +370,7 @@ void CBattleActionsController::handleHex(BattleHex myNumber, int eventType) | ||||
| 				} | ||||
| 				break; | ||||
| 			case PossiblePlayerBattleAction::CATAPULT: | ||||
| 				if (owner->siegeController && owner->siegeController->isCatapultAttackable(myNumber)) | ||||
| 				if (owner->siegeController && owner->siegeController->isAttackableByCatapult(myNumber)) | ||||
| 					legalAction = true; | ||||
| 				break; | ||||
| 			case PossiblePlayerBattleAction::HEAL: | ||||
|   | ||||
| @@ -762,7 +762,7 @@ bool CShootingAnimation::init() | ||||
| 	const CCreature *shooterInfo = shooter->getCreature(); | ||||
|  | ||||
| 	if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS) | ||||
| 		shooterInfo = owner->siegeController->turretCreature(); | ||||
| 		shooterInfo = owner->siegeController->getTurretCreature(); | ||||
|  | ||||
| 	Point shooterPos; | ||||
| 	Point shotPos; | ||||
| @@ -831,7 +831,7 @@ void CShootingAnimation::nextFrame() | ||||
| 		const CCreature *shooterInfo = attackingStack->getCreature(); | ||||
|  | ||||
| 		if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS) | ||||
| 			shooterInfo = owner->siegeController->turretCreature(); | ||||
| 			shooterInfo = owner->siegeController->getTurretCreature(); | ||||
|  | ||||
| 		// animation should be paused if there is an active projectile | ||||
| 		if ( stackAnimation(attackingStack)->getCurrentFrame() >= shooterInfo->animation.attackClimaxFrame ) | ||||
|   | ||||
| @@ -94,7 +94,6 @@ void CBattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & b | ||||
| 	//waitForAnims(); //fixme: freezes game :? | ||||
| } | ||||
|  | ||||
|  | ||||
| void CBattleEffectsController::startAction(const BattleAction* action) | ||||
| { | ||||
| 	const CStack *stack = owner->curInt->cb->battleGetStackByID(action->stackNumber); | ||||
| @@ -124,29 +123,23 @@ void CBattleEffectsController::startAction(const BattleAction* action) | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| void CBattleEffectsController::showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects) | ||||
| void CBattleEffectsController::showBattlefieldObjects(SDL_Surface *to, const BattleHex & destTile) | ||||
| { | ||||
| 	for (auto & elem : battleEffects) | ||||
| 	{ | ||||
| 		int currentFrame = static_cast<int>(floor(elem->currentFrame)); | ||||
| 		currentFrame %= elem->animation->size(); | ||||
| 		if (!elem.position.isValid() && destTile != BattleHex::HEX_AFTER_ALL) | ||||
| 			continue; | ||||
|  | ||||
| 		auto img = elem->animation->getImage(currentFrame); | ||||
| 		if (elem.position.isValid() && elem.position != destTile) | ||||
| 			continue; | ||||
|  | ||||
| 		SDL_Rect temp_rect = genRect(img->height(), img->width(), elem->x, elem->y); | ||||
| 		int currentFrame = static_cast<int>(floor(elem.currentFrame)); | ||||
| 		currentFrame %= elem.animation->size(); | ||||
|  | ||||
| 		auto img = elem.animation->getImage(currentFrame); | ||||
|  | ||||
| 		SDL_Rect temp_rect = genRect(img->height(), img->width(), elem.x, elem.y); | ||||
|  | ||||
| 		img->draw(to, &temp_rect, nullptr); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleEffectsController::sortObjectsByHex(BattleObjectsByHex & sorted) | ||||
| { | ||||
| 	for (auto & battleEffect : battleEffects) | ||||
| 	{ | ||||
| 		if (battleEffect.position.isValid()) | ||||
| 			sorted.hex[battleEffect.position].effects.push_back(&battleEffect); | ||||
| 		else | ||||
| 			sorted.afterAll.effects.push_back(&battleEffect); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -54,19 +54,21 @@ class CBattleEffectsController | ||||
| { | ||||
| 	CBattleInterface * owner; | ||||
|  | ||||
| 	std::vector<BattleEffect> battleEffects; //different animations to display on the screen like spell effects | ||||
| 	/// list of current effects that are being displayed on screen (spells & creature abilities) | ||||
| 	std::vector<BattleEffect> battleEffects; | ||||
|  | ||||
| public: | ||||
| 	CBattleEffectsController(CBattleInterface * owner); | ||||
|  | ||||
| 	void startAction(const BattleAction* action); | ||||
| 	void sortObjectsByHex(BattleObjectsByHex & sorted); | ||||
|  | ||||
| 	void displayCustomEffects(const std::vector<CustomEffectInfo> & customEffects); | ||||
|  | ||||
| 	void displayEffect(EBattleEffect::EBattleEffect effect, const BattleHex & destTile); //displays custom effect on the battlefield | ||||
| 	void displayEffect(EBattleEffect::EBattleEffect effect, uint32_t soundID, const BattleHex & destTile); //displays custom effect on the battlefield | ||||
| 	void battleTriggerEffect(const BattleTriggerEffect & bte); | ||||
| 	void showBattleEffects(SDL_Surface *to, const std::vector<const BattleEffect *> &battleEffects); | ||||
|  | ||||
| 	void showBattlefieldObjects(SDL_Surface *to, const BattleHex & destTile); | ||||
|  | ||||
|  | ||||
| 	friend class CEffectAnimation; // currently, battleEffects is largely managed by CEffectAnimation, TODO: move this logic into CBattleEffectsController | ||||
|   | ||||
| @@ -957,27 +957,36 @@ void CBattleInterface::show(SDL_Surface *to) | ||||
| 	activateStack(); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ) | ||||
| { | ||||
| 	if (siegeController) | ||||
| 		siegeController->showBattlefieldObjects(to, location); | ||||
| 	obstacleController->showBattlefieldObjects(to, location); | ||||
| 	stacksController->showBattlefieldObjects(to, location); | ||||
| 	effectsController->showBattlefieldObjects(to, location); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::showBattlefieldObjects(SDL_Surface *to) | ||||
| { | ||||
| 	auto showHexEntry = [&](BattleObjectsByHex::HexData & hex) | ||||
| 	{ | ||||
| 		if (siegeController) | ||||
| 			siegeController->showPiecesOfWall(to, hex.walls); | ||||
| 		obstacleController->showObstacles(to, hex.obstacles); | ||||
| 		stacksController->showAliveStacks(to, hex.alive); | ||||
| 		effectsController->showBattleEffects(to, hex.effects); | ||||
| 	}; | ||||
| 	//auto showHexEntry = [&](BattleObjectsByHex::HexData & hex) | ||||
| 	//{ | ||||
| 	//	if (siegeController) | ||||
| 	//		siegeController->showPiecesOfWall(to, hex.walls); | ||||
| 	//	obstacleController->showObstacles(to, hex.obstacles); | ||||
| 	//	stacksController->showAliveStacks(to, hex.alive); | ||||
| 	//	effectsController->showBattleEffects(to, hex.effects); | ||||
| 	//}; | ||||
|  | ||||
| 	BattleObjectsByHex objects = sortObjectsByHex(); | ||||
| 	//BattleObjectsByHex objects = sortObjectsByHex(); | ||||
|  | ||||
| 	// dead stacks should be blit first | ||||
| 	stacksController->showStacks(to, objects.beforeAll.dead); | ||||
| 	for (auto & data : objects.hex) | ||||
| 		stacksController->showStacks(to, data.dead); | ||||
| 	stacksController->showStacks(to, objects.afterAll.dead); | ||||
| 	//stacksController->showStacks(to, objects.beforeAll.dead); | ||||
| 	//for (auto & data : objects.hex) | ||||
| 	//	stacksController->showStacks(to, data.dead); | ||||
| 	//stacksController->showStacks(to, objects.afterAll.dead); | ||||
|  | ||||
| 	// display objects that must be blit before anything else (e.g. topmost walls) | ||||
| 	showHexEntry(objects.beforeAll); | ||||
| 	//showHexEntry(objects.beforeAll); | ||||
|  | ||||
| 	// show heroes after "beforeAll" - e.g. topmost wall in siege | ||||
| 	if (attackingHero) | ||||
| @@ -987,11 +996,11 @@ void CBattleInterface::showBattlefieldObjects(SDL_Surface *to) | ||||
|  | ||||
| 	// actual blit of most of objects, hex by hex | ||||
| 	// NOTE: row-by-row blitting may be a better approach | ||||
| 	for (auto &data : objects.hex) | ||||
| 		showHexEntry(data); | ||||
| 	//for (auto &data : objects.hex) | ||||
| 	//	showHexEntry(data); | ||||
|  | ||||
| 	// objects that must be blit *after* everything else - e.g. bottom tower or some spell effects | ||||
| 	showHexEntry(objects.afterAll); | ||||
| 	//showHexEntry(objects.afterAll); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::showInterface(SDL_Surface *to) | ||||
| @@ -1020,19 +1029,6 @@ void CBattleInterface::showInterface(SDL_Surface *to) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| BattleObjectsByHex CBattleInterface::sortObjectsByHex() | ||||
| { | ||||
| 	BattleObjectsByHex sorted; | ||||
|  | ||||
| 	stacksController->sortObjectsByHex(sorted); | ||||
| 	obstacleController->sortObjectsByHex(sorted); | ||||
| 	effectsController->sortObjectsByHex(sorted); | ||||
| 	if (siegeController) | ||||
| 		siegeController->sortObjectsByHex(sorted); | ||||
|  | ||||
| 	return sorted; | ||||
| } | ||||
|  | ||||
| void CBattleInterface::castThisSpell(SpellID spellID) | ||||
| { | ||||
| 	actionsController->castThisSpell(spellID); | ||||
|   | ||||
| @@ -70,28 +70,6 @@ struct StackAttackedInfo | ||||
| 	bool cloneKilled; | ||||
| }; | ||||
|  | ||||
|  | ||||
| struct BattleObjectsByHex | ||||
| { | ||||
| 	typedef std::vector<int> TWallList; | ||||
| 	typedef std::vector<const CStack *> TStackList; | ||||
| 	typedef std::vector<const BattleEffect *> TEffectList; | ||||
| 	typedef std::vector<std::shared_ptr<const CObstacleInstance>> TObstacleList; | ||||
|  | ||||
| 	struct HexData | ||||
| 	{ | ||||
| 		TWallList walls; | ||||
| 		TStackList dead; | ||||
| 		TStackList alive; | ||||
| 		TEffectList effects; | ||||
| 		TObstacleList obstacles; | ||||
| 	}; | ||||
|  | ||||
| 	HexData beforeAll; | ||||
| 	HexData afterAll; | ||||
| 	std::array<HexData, GameConstants::BFIELD_SIZE> hex; | ||||
| }; | ||||
|  | ||||
| /// Big class which handles the overall battle interface actions and it is also responsible for | ||||
| /// drawing everything correctly. | ||||
| class CBattleInterface : public WindowBase | ||||
| @@ -128,8 +106,7 @@ private: | ||||
| 	void showInterface(SDL_Surface *to); | ||||
|  | ||||
| 	void showBattlefieldObjects(SDL_Surface *to); | ||||
|  | ||||
| 	BattleObjectsByHex sortObjectsByHex(); | ||||
| 	void showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ); | ||||
|  | ||||
| 	void setHeroAnimation(ui8 side, int phase); | ||||
| public: | ||||
|   | ||||
| @@ -584,7 +584,7 @@ Point CClickableHex::getXYUnitAnim(BattleHex hexNum, const CStack * stack, CBatt | ||||
|  | ||||
| 	Point ret(-500, -500); //returned value | ||||
| 	if(stack && stack->initialPosition < 0) //creatures in turrets | ||||
| 		return cbi->siegeController->turretCreaturePosition(stack->initialPosition); | ||||
| 		return cbi->siegeController->getTurretCreaturePosition(stack->initialPosition); | ||||
|  | ||||
| 	static const Point basePos(-190, -139); // position of creature in topleft corner | ||||
| 	static const int imageShiftX = 30; // X offset to base pos for facing right stacks, negative for facing left | ||||
|   | ||||
| @@ -145,7 +145,11 @@ public: | ||||
| 	//CStack * ourStack; | ||||
| 	bool strictHovered; //for determining if hex is hovered by mouse (this is different problem than hex's graphic hovering) | ||||
| 	CBattleInterface * myInterface; //interface that owns me | ||||
| 	static Point getXYUnitAnim(BattleHex hexNum, const CStack * creature, CBattleInterface * cbi); //returns (x, y) of left top corner of animation | ||||
|  | ||||
| 	/// returns (x, y) of left top corner of animation | ||||
| 	/// FIXME: move someplace else? | ||||
| 	/// FIXME: some usages should be replaced with creAnims->pos? | ||||
| 	static Point getXYUnitAnim(BattleHex hexNum, const CStack * creature, CBattleInterface * cbi); | ||||
|  | ||||
| 	//for user interactions | ||||
| 	void hover (bool on) override; | ||||
|   | ||||
| @@ -122,10 +122,19 @@ void CBattleObstacleController::showAbsoluteObstacles(SDL_Surface * to) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleObstacleController::showObstacles(SDL_Surface * to, std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles) | ||||
| void CBattleObstacleController::showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ) | ||||
| { | ||||
| 	for(auto & obstacle : obstacles) | ||||
| 	for (auto &obstacle : owner->curInt->cb->battleGetAllObstacles()) | ||||
| 	{ | ||||
| 		if (obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) | ||||
| 			continue; | ||||
|  | ||||
| 		if (obstacle->obstacleType != CObstacleInstance::MOAT) | ||||
| 			continue; | ||||
|  | ||||
| 		if ( obstacle->pos != location) | ||||
| 			continue; | ||||
|  | ||||
| 		auto img = getObstacleImage(*obstacle); | ||||
| 		if(img) | ||||
| 		{ | ||||
| @@ -135,22 +144,6 @@ void CBattleObstacleController::showObstacles(SDL_Surface * to, std::vector<std: | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleObstacleController::sortObjectsByHex(BattleObjectsByHex & sorted) | ||||
| { | ||||
| 	std::map<BattleHex, std::shared_ptr<const CObstacleInstance>> backgroundObstacles; | ||||
| 	for (auto &obstacle : owner->curInt->cb->battleGetAllObstacles()) { | ||||
| 		if (obstacle->obstacleType != CObstacleInstance::ABSOLUTE_OBSTACLE | ||||
| 			&& obstacle->obstacleType != CObstacleInstance::MOAT) { | ||||
| 			backgroundObstacles[obstacle->pos] = obstacle; | ||||
| 		} | ||||
| 	} | ||||
| 	for (auto &op : backgroundObstacles) | ||||
| 	{ | ||||
| 		sorted.beforeAll.obstacles.push_back(op.second); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| std::shared_ptr<IImage> CBattleObstacleController::getObstacleImage(const CObstacleInstance & oi) | ||||
| { | ||||
| 	int frameIndex = (owner->animCount+1) *25 / owner->getAnimSpeed(); | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
|  | ||||
| struct SDL_Surface; | ||||
| struct BattleObjectsByHex; | ||||
| struct BattleHex; | ||||
| class IImage; | ||||
| class CAnimation; | ||||
| class CBattleInterface; | ||||
| @@ -24,6 +25,10 @@ class CBattleObstacleController | ||||
| 	CBattleInterface * owner; | ||||
|  | ||||
| 	std::map<si32, std::shared_ptr<CAnimation>> obstacleAnimations; | ||||
|  | ||||
| 	std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi); | ||||
| 	Point getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle); | ||||
|  | ||||
| public: | ||||
| 	CBattleObstacleController(CBattleInterface * owner); | ||||
|  | ||||
| @@ -31,11 +36,7 @@ public: | ||||
| 	void showObstacles(SDL_Surface *to, std::vector<std::shared_ptr<const CObstacleInstance>> &obstacles); | ||||
| 	void showAbsoluteObstacles(SDL_Surface *to); | ||||
|  | ||||
| 	void sortObjectsByHex(BattleObjectsByHex & sorted); | ||||
|  | ||||
| 	std::shared_ptr<IImage> getObstacleImage(const CObstacleInstance & oi); | ||||
|  | ||||
| 	Point getObstaclePosition(std::shared_ptr<IImage> image, const CObstacleInstance & obstacle); | ||||
| 	void showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ); | ||||
|  | ||||
| 	void redrawBackgroundWithHexes(SDL_Surface * to); | ||||
| }; | ||||
|   | ||||
| @@ -58,7 +58,7 @@ void CBattleProjectileController::initStackProjectile(const CStack * stack) | ||||
| { | ||||
| 	const CCreature * creature;//creature whose shots should be loaded | ||||
| 	if(stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS) | ||||
| 		creature = owner->siegeController->turretCreature(); | ||||
| 		creature = owner->siegeController->getTurretCreature(); | ||||
| 	else | ||||
| 		creature = stack->getCreature(); | ||||
|  | ||||
| @@ -208,7 +208,7 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const | ||||
| 	const CCreature *shooterInfo = shooter->getCreature(); | ||||
|  | ||||
| 	if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS) | ||||
| 		shooterInfo = owner->siegeController->turretCreature(); | ||||
| 		shooterInfo = owner->siegeController->getTurretCreature(); | ||||
|  | ||||
| 	if(!shooterInfo->animation.missleFrameAngles.size()) | ||||
| 		logAnim->error("Mod error: Creature '%s' on the Archer's tower is not a shooter. Mod should be fixed. Trying to use archer's data instead..." | ||||
|   | ||||
| @@ -10,51 +10,37 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CBattleSiegeController.h" | ||||
|  | ||||
| #include "../CMusicHandler.h" | ||||
| #include "../../lib/NetPacks.h" | ||||
| #include "../CGameInfo.h" | ||||
| #include "../../CCallback.h" | ||||
| #include "../CBitmapHandler.h" | ||||
| #include "../CPlayerInterface.h" | ||||
| #include "../../lib/CStack.h" | ||||
| #include "../../lib/mapObjects/CGTownInstance.h" | ||||
| #include "CBattleInterface.h" | ||||
| #include "CBattleAnimations.h" | ||||
| #include "CBattleInterface.h" | ||||
| #include "CBattleInterfaceClasses.h" | ||||
| #include "CBattleStacksController.h" | ||||
|  | ||||
| CBattleSiegeController::~CBattleSiegeController() | ||||
| { | ||||
| 	auto gateState = owner->curInt->cb->battleGetGateState(); | ||||
| 	for (int g = 0; g < ARRAY_COUNT(walls); ++g) | ||||
| 	{ | ||||
| 		if (g != EWallVisual::GATE || (gateState != EGateState::NONE && gateState != EGateState::CLOSED && gateState != EGateState::BLOCKED)) | ||||
| 			SDL_FreeSurface(walls[g]); | ||||
| 	} | ||||
| #include "../CMusicHandler.h" | ||||
| #include "../CGameInfo.h" | ||||
| #include "../CPlayerInterface.h" | ||||
| #include "../gui/CAnimation.h" | ||||
|  | ||||
| 	SDL_FreeSurface(moatSurface); | ||||
| 	SDL_FreeSurface(mlipSurface); | ||||
| } | ||||
| #include "../../CCallback.h" | ||||
| #include "../../lib/NetPacks.h" | ||||
| #include "../../lib/CStack.h" | ||||
| #include "../../lib/mapObjects/CGTownInstance.h" | ||||
|  | ||||
| std::string CBattleSiegeController::getSiegeName(ui16 what) const | ||||
| { | ||||
| 	return getSiegeName(what, EWallState::INTACT); | ||||
| } | ||||
|  | ||||
| std::string CBattleSiegeController::getSiegeName(ui16 what, int state) const | ||||
| std::string CBattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState::EWallState state) const | ||||
| { | ||||
| 	auto getImageIndex = [&]() -> int | ||||
| 	{ | ||||
| 		switch (state) | ||||
| 		{ | ||||
| 		case EWallState::INTACT : return 1; | ||||
| 		case EWallState::INTACT : | ||||
| 			return 1; | ||||
| 		case EWallState::DAMAGED : | ||||
| 			if(what == 2 || what == 3 || what == 8) // towers don't have separate image here - INTACT and DAMAGED is 1, DESTROYED is 2 | ||||
| 			// towers don't have separate image here - INTACT and DAMAGED is 1, DESTROYED is 2 | ||||
| 			if(what == EWallVisual::KEEP || what == EWallVisual::BOTTOM_TOWER || what == EWallVisual::UPPER_TOWER) | ||||
| 				return 1; | ||||
| 			else | ||||
| 				return 2; | ||||
| 		case EWallState::DESTROYED : | ||||
| 			if (what == 2 || what == 3 || what == 8) | ||||
| 			if (what == EWallVisual::KEEP || what == EWallVisual::BOTTOM_TOWER || what == EWallVisual::UPPER_TOWER) | ||||
| 				return 2; | ||||
| 			else | ||||
| 				return 3; | ||||
| @@ -67,8 +53,6 @@ std::string CBattleSiegeController::getSiegeName(ui16 what, int state) const | ||||
|  | ||||
| 	switch(what) | ||||
| 	{ | ||||
| 	case EWallVisual::BACKGROUND: | ||||
| 		return prefix + "BACK.BMP"; | ||||
| 	case EWallVisual::BACKGROUND_WALL: | ||||
| 		{ | ||||
| 			switch(town->town->faction->index) | ||||
| @@ -119,38 +103,64 @@ std::string CBattleSiegeController::getSiegeName(ui16 what, int state) const | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleSiegeController::printPartOfWall(SDL_Surface *to, int what) | ||||
| void CBattleSiegeController::showWallPiece(SDL_Surface *to, EWallVisual::EWallVisual what) | ||||
| { | ||||
| 	Point pos = Point(-1, -1); | ||||
| 	auto & ci = town->town->clientInfo; | ||||
| 	auto const & pos = ci.siegePositions[what]; | ||||
|  | ||||
| 	if (vstd::iswithin(what, 1, 17)) | ||||
| 	{ | ||||
| 		pos.x = ci.siegePositions[what].x + owner->pos.x; | ||||
| 		pos.y = ci.siegePositions[what].y + owner->pos.y; | ||||
| 	} | ||||
|  | ||||
| 	if (town->town->faction->index == ETownType::TOWER | ||||
| 		&& (what == EWallVisual::MOAT || what == EWallVisual::BACKGROUND_MOAT)) | ||||
| 		return; // no moat in Tower. TODO: remove hardcode somehow? | ||||
|  | ||||
| 	if (pos.x != -1) | ||||
| 	{ | ||||
| 		//gate have no displayed bitmap when drawbridge is raised | ||||
| 		if (what == EWallVisual::GATE) | ||||
| 		{ | ||||
| 			auto gateState = owner->curInt->cb->battleGetGateState(); | ||||
| 			if (gateState != EGateState::OPENED && gateState != EGateState::DESTROYED) | ||||
| 				return; | ||||
| 		} | ||||
|  | ||||
| 		blitAt(walls[what], pos.x, pos.y, to); | ||||
| 	} | ||||
| 	wallPieceImages[what]->draw(to, pos.x + owner->pos.x, pos.y + owner->pos.y); | ||||
| } | ||||
|  | ||||
| std::string CBattleSiegeController::getBattleBackgroundName() | ||||
| std::string CBattleSiegeController::getBattleBackgroundName() const | ||||
| { | ||||
| 	return getSiegeName(0); | ||||
| 	const std::string & prefix = town->town->clientInfo.siegePrefix; | ||||
| 	return prefix + "BACK.BMP"; | ||||
| } | ||||
|  | ||||
| bool CBattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what) const | ||||
| { | ||||
| 	//FIXME: use this instead of buildings test? | ||||
| 	//ui8 siegeLevel = owner->curInt->cb->battleGetSiegeLevel(); | ||||
|  | ||||
| 	bool isMoat = (what == EWallVisual::BACKGROUND_MOAT || what == EWallVisual::MOAT); | ||||
| 	bool isKeep = what == EWallVisual::KEEP_BATTLEMENT; | ||||
| 	bool isTower = (what == EWallVisual::UPPER_BATTLEMENT || what == EWallVisual::BOTTOM_BATTLEMENT); | ||||
|  | ||||
| 	bool hasMoat = town->hasBuilt(BuildingID::CITADEL) && town->town->faction->index != ETownType::TOWER; | ||||
| 	bool hasKeep = town->hasBuilt(BuildingID::CITADEL); | ||||
| 	bool hasTower = town->hasBuilt(BuildingID::CASTLE); | ||||
|  | ||||
| 	if ( isMoat ) return hasMoat; | ||||
| 	if ( isKeep ) return hasKeep; | ||||
| 	if ( isTower ) return hasTower; | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| BattleHex CBattleSiegeController::getWallPiecePosition(EWallVisual::EWallVisual what) const | ||||
| { | ||||
| 	static const std::array<BattleHex, 18> wallsPositions = { | ||||
| 		BattleHex::INVALID, // background, handled separately | ||||
| 		BattleHex::HEX_BEFORE_ALL, | ||||
| 		135, | ||||
| 		BattleHex::HEX_AFTER_ALL, | ||||
| 		182, | ||||
| 		130, | ||||
| 		78, | ||||
| 		12, | ||||
| 		BattleHex::HEX_BEFORE_ALL, | ||||
| 		94, | ||||
| 		112, | ||||
| 		165, | ||||
| 		45, | ||||
| 		BattleHex::INVALID, //moat, printed as obstacle // BattleHex::HEX_BEFORE_ALL, | ||||
| 		BattleHex::INVALID, //moat, printed as obstacle | ||||
| 		135, | ||||
| 		BattleHex::HEX_AFTER_ALL, | ||||
| 		BattleHex::HEX_BEFORE_ALL | ||||
| 	}; | ||||
|  | ||||
| 	return wallsPositions[what]; | ||||
| } | ||||
|  | ||||
| CBattleSiegeController::CBattleSiegeController(CBattleInterface * owner, const CGTownInstance *siegeTown): | ||||
| @@ -159,35 +169,37 @@ CBattleSiegeController::CBattleSiegeController(CBattleInterface * owner, const C | ||||
| { | ||||
| 	assert(owner->fieldController.get() == nullptr); // must be created after this | ||||
|  | ||||
| 	moatSurface = BitmapHandler::loadBitmap( getSiegeName(13) ); | ||||
| 	mlipSurface = BitmapHandler::loadBitmap( getSiegeName(14) ); | ||||
|  | ||||
| 	for (int g = 0; g < ARRAY_COUNT(walls); ++g) | ||||
| 	for (int g = 0; g < wallPieceImages.size(); ++g) | ||||
| 	{ | ||||
| 		if (g != EWallVisual::GATE) | ||||
| 			walls[g] = BitmapHandler::loadBitmap(getSiegeName(g)); | ||||
| 		if ( g == EWallVisual::GATE ) // gate is initially closed and has no image to display in this state | ||||
| 			continue; | ||||
|  | ||||
| 		if ( !getWallPieceExistance(EWallVisual::EWallVisual(g)) ) | ||||
| 			continue; | ||||
|  | ||||
| 		wallPieceImages[g] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(g), EWallState::INTACT)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const CCreature *CBattleSiegeController::turretCreature() | ||||
| const CCreature *CBattleSiegeController::getTurretCreature() const | ||||
| { | ||||
| 	return CGI->creh->objects[town->town->clientInfo.siegeShooter]; | ||||
| } | ||||
|  | ||||
| Point CBattleSiegeController::turretCreaturePosition( BattleHex position ) | ||||
| Point CBattleSiegeController::getTurretCreaturePosition( BattleHex position ) const | ||||
| { | ||||
| 	// Turret positions are read out of the config/wall_pos.txt | ||||
| 	int posID = 0; | ||||
| 	switch (position) | ||||
| 	{ | ||||
| 	case BattleHex::CASTLE_CENTRAL_TOWER: // keep creature | ||||
| 		posID = 18; | ||||
| 		posID = EWallVisual::CREATURE_KEEP; | ||||
| 		break; | ||||
| 	case BattleHex::CASTLE_BOTTOM_TOWER: // bottom creature | ||||
| 		posID = 19; | ||||
| 		posID = EWallVisual::CREATURE_BOTTOM_TOWER; | ||||
| 		break; | ||||
| 	case BattleHex::CASTLE_UPPER_TOWER: // upper creature | ||||
| 		posID = 20; | ||||
| 		posID = EWallVisual::CREATURE_UPPER_TOWER; | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| @@ -203,12 +215,11 @@ Point CBattleSiegeController::turretCreaturePosition( BattleHex position ) | ||||
| 	return Point(0,0); | ||||
| } | ||||
|  | ||||
|  | ||||
| void CBattleSiegeController::gateStateChanged(const EGateState state) | ||||
| { | ||||
| 	auto oldState = owner->curInt->cb->battleGetGateState(); | ||||
| 	bool playSound = false; | ||||
| 	int stateId = EWallState::NONE; | ||||
| 	auto stateId = EWallState::NONE; | ||||
| 	switch(state) | ||||
| 	{ | ||||
| 	case EGateState::CLOSED: | ||||
| @@ -229,102 +240,87 @@ void CBattleSiegeController::gateStateChanged(const EGateState state) | ||||
| 	} | ||||
|  | ||||
| 	if (oldState != EGateState::NONE && oldState != EGateState::CLOSED && oldState != EGateState::BLOCKED) | ||||
| 		SDL_FreeSurface(walls[EWallVisual::GATE]); | ||||
| 		wallPieceImages[EWallVisual::GATE] = nullptr; | ||||
|  | ||||
| 	if (stateId != EWallState::NONE) | ||||
| 		walls[EWallVisual::GATE] = BitmapHandler::loadBitmap(getSiegeName(EWallVisual::GATE, stateId)); | ||||
| 		wallPieceImages[EWallVisual::GATE] = IImage::createFromFile(getWallPieceImageName(EWallVisual::GATE,  stateId)); | ||||
|  | ||||
| 	if (playSound) | ||||
| 		CCS->soundh->playSound(soundBase::DRAWBRG); | ||||
| } | ||||
|  | ||||
| void CBattleSiegeController::showAbsoluteObstacles(SDL_Surface * to) | ||||
| { | ||||
| 	ui8 siegeLevel = owner->curInt->cb->battleGetSiegeLevel(); | ||||
| 	if (siegeLevel >= 2) //citadel or castle | ||||
| 	auto & info = town->town->clientInfo; | ||||
|  | ||||
| 	if (getWallPieceExistance(EWallVisual::MOAT)) | ||||
| 	{ | ||||
| 		//print moat/mlip | ||||
| 		auto const & pos = info.siegePositions[EWallVisual::MOAT]; | ||||
| 		wallPieceImages[EWallVisual::MOAT]->draw(to, pos.x + owner->pos.x, pos.y + owner->pos.y); | ||||
| 	} | ||||
|  | ||||
| 		auto & info = town->town->clientInfo; | ||||
| 		Point moatPos(info.siegePositions[13].x, info.siegePositions[13].y); | ||||
| 		Point mlipPos(info.siegePositions[14].x, info.siegePositions[14].y); | ||||
|  | ||||
| 		if (moatSurface) //eg. tower has no moat | ||||
| 			blitAt(moatSurface, moatPos.x + owner->pos.x, moatPos.y  + owner->pos.y, to); | ||||
| 		if (mlipSurface) //eg. tower has no mlip | ||||
| 			blitAt(mlipSurface, mlipPos.x + owner->pos.x, mlipPos.y + owner->pos.y, to); | ||||
|  | ||||
| 		printPartOfWall(to, EWallVisual::BACKGROUND_MOAT); | ||||
| 	if (getWallPieceExistance(EWallVisual::BACKGROUND_MOAT)) | ||||
| 	{ | ||||
| 		auto const & pos = info.siegePositions[EWallVisual::BACKGROUND_MOAT]; | ||||
| 		wallPieceImages[EWallVisual::BACKGROUND_MOAT]->draw(to, pos.x + owner->pos.x, pos.y + owner->pos.y); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleSiegeController::sortObjectsByHex(BattleObjectsByHex & sorted) | ||||
| void CBattleSiegeController::showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ) | ||||
| { | ||||
| 	sorted.beforeAll.walls.push_back(EWallVisual::BACKGROUND_WALL); | ||||
| 	sorted.hex[135].walls.push_back(EWallVisual::KEEP); | ||||
| 	sorted.afterAll.walls.push_back(EWallVisual::BOTTOM_TOWER); | ||||
| 	sorted.hex[182].walls.push_back(EWallVisual::BOTTOM_WALL); | ||||
| 	sorted.hex[130].walls.push_back(EWallVisual::WALL_BELLOW_GATE); | ||||
| 	sorted.hex[78].walls.push_back(EWallVisual::WALL_OVER_GATE); | ||||
| 	sorted.hex[12].walls.push_back(EWallVisual::UPPER_WALL); | ||||
| 	sorted.beforeAll.walls.push_back(EWallVisual::UPPER_TOWER); | ||||
| 	sorted.hex[94].walls.push_back(EWallVisual::GATE); | ||||
| 	sorted.hex[112].walls.push_back(EWallVisual::GATE_ARCH); | ||||
| 	sorted.hex[165].walls.push_back(EWallVisual::BOTTOM_STATIC_WALL); | ||||
| 	sorted.hex[45].walls.push_back(EWallVisual::UPPER_STATIC_WALL); | ||||
|  | ||||
| 	if (town->hasBuilt(BuildingID::CITADEL)) | ||||
| 	for (int i = EWallVisual::WALL_FIRST; i <= EWallVisual::WALL_LAST; ++i) | ||||
| 	{ | ||||
| 		sorted.beforeAll.walls.push_back(EWallVisual::MOAT); | ||||
| 		//sorted.beforeAll.walls.push_back(EWallVisual::BACKGROUND_MOAT); // blit as absolute obstacle | ||||
| 		sorted.hex[135].walls.push_back(EWallVisual::KEEP_BATTLEMENT); | ||||
| 	} | ||||
| 	if (town->hasBuilt(BuildingID::CASTLE)) | ||||
| 	{ | ||||
| 		sorted.afterAll.walls.push_back(EWallVisual::BOTTOM_BATTLEMENT); | ||||
| 		sorted.beforeAll.walls.push_back(EWallVisual::UPPER_BATTLEMENT); | ||||
| 	} | ||||
| } | ||||
| 		auto wallPiece = EWallVisual::EWallVisual(i); | ||||
|  | ||||
| 		if ( !getWallPieceExistance(wallPiece)) | ||||
| 			continue; | ||||
|  | ||||
| void CBattleSiegeController::showPiecesOfWall(SDL_Surface *to, std::vector<int> pieces) | ||||
| { | ||||
| 	for (auto piece : pieces) | ||||
| 	{ | ||||
| 		if (piece < 15) // not a tower - just print | ||||
| 			printPartOfWall(to, piece); | ||||
| 		else // tower. find if tower is built and not destroyed - stack is present | ||||
| 		if ( getWallPiecePosition(wallPiece) != location) | ||||
| 			continue; | ||||
|  | ||||
| 		if (wallPiece != EWallVisual::KEEP_BATTLEMENT && | ||||
| 			wallPiece != EWallVisual::BOTTOM_BATTLEMENT && | ||||
| 			wallPiece != EWallVisual::UPPER_BATTLEMENT) | ||||
| 		{ | ||||
| 			// PieceID    StackID | ||||
| 			// 15 = keep,  -2 | ||||
| 			// 16 = lower, -3 | ||||
| 			// 17 = upper, -4 | ||||
| 			showWallPiece(to, wallPiece); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 			// tower. check if tower is alive - stack is found | ||||
| 			int stackPos = 13 - piece; | ||||
| 		// tower. check if tower is alive - stack is found | ||||
| 		BattleHex stackPos; | ||||
| 		switch(wallPiece) | ||||
| 		{ | ||||
| 		case EWallVisual::KEEP_BATTLEMENT: | ||||
| 			stackPos = BattleHex::CASTLE_CENTRAL_TOWER; | ||||
| 			break; | ||||
| 		case EWallVisual::BOTTOM_BATTLEMENT: | ||||
| 			stackPos = BattleHex::CASTLE_BOTTOM_TOWER; | ||||
| 			break; | ||||
| 		case EWallVisual::UPPER_BATTLEMENT: | ||||
| 			stackPos = BattleHex::CASTLE_UPPER_TOWER; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 			const CStack *turret = nullptr; | ||||
| 		const CStack *turret = nullptr; | ||||
|  | ||||
| 			for (auto & stack : owner->curInt->cb->battleGetAllStacks(true)) | ||||
| 		for (auto & stack : owner->curInt->cb->battleGetAllStacks(true)) | ||||
| 		{ | ||||
| 			if(stack->initialPosition == stackPos) | ||||
| 			{ | ||||
| 				if(stack->initialPosition == stackPos) | ||||
| 				{ | ||||
| 					turret = stack; | ||||
| 					break; | ||||
| 				} | ||||
| 				turret = stack; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 			if (turret) | ||||
| 			{ | ||||
| 				std::vector<const CStack *> stackList(1, turret); | ||||
| 				owner->stacksController->showStacks(to, stackList); | ||||
| 				printPartOfWall(to, piece); | ||||
| 			} | ||||
| 		if (turret) | ||||
| 		{ | ||||
| 			owner->stacksController->showStack(to, turret); | ||||
| 			showWallPiece(to, wallPiece); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| bool CBattleSiegeController::isCatapultAttackable(BattleHex hex) const | ||||
| bool CBattleSiegeController::isAttackableByCatapult(BattleHex hex) const | ||||
| { | ||||
| 	if (owner->tacticsMode) | ||||
| 		return false; | ||||
| @@ -362,13 +358,13 @@ void CBattleSiegeController::stackIsCatapulting(const CatapultAttack & ca) | ||||
|  | ||||
| 	for (auto attackInfo : ca.attackedParts) | ||||
| 	{ | ||||
| 		int wallId = attackInfo.attackedPart + 2; | ||||
| 		int wallId = attackInfo.attackedPart + EWallVisual::DESTRUCTIBLE_FIRST; | ||||
| 		//gate state changing handled separately | ||||
| 		if (wallId == EWallVisual::GATE) | ||||
| 			continue; | ||||
|  | ||||
| 		SDL_FreeSurface(walls[wallId]); | ||||
| 		walls[wallId] = BitmapHandler::loadBitmap( | ||||
| 			getSiegeName(wallId, owner->curInt->cb->battleGetWallState(attackInfo.attackedPart))); | ||||
| 		auto wallState = EWallState::EWallState(owner->curInt->cb->battleGetWallState(attackInfo.attackedPart)); | ||||
|  | ||||
| 		wallPieceImages[wallId] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(wallId), wallState)); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -10,22 +10,23 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../../lib/GameConstants.h" | ||||
| #include "../../lib/battle/BattleHex.h" | ||||
|  | ||||
| struct BattleObjectsByHex; | ||||
| struct CatapultAttack; | ||||
| struct SDL_Surface; | ||||
| struct BattleHex; | ||||
| struct Point; | ||||
| struct SDL_Surface; | ||||
| class CGTownInstance; | ||||
| class CBattleInterface; | ||||
| class CCreature; | ||||
| class IImage; | ||||
|  | ||||
| namespace EWallVisual | ||||
| { | ||||
| 	enum EWallVisual | ||||
| 	{ | ||||
| 		BACKGROUND = 0, | ||||
| 		BACKGROUND_WALL = 1, | ||||
| 		BACKGROUND, | ||||
| 		BACKGROUND_WALL, | ||||
|  | ||||
| 		KEEP, | ||||
| 		BOTTOM_TOWER, | ||||
| 		BOTTOM_WALL, | ||||
| @@ -34,6 +35,7 @@ namespace EWallVisual | ||||
| 		UPPER_WALL, | ||||
| 		UPPER_TOWER, | ||||
| 		GATE, | ||||
|  | ||||
| 		GATE_ARCH, | ||||
| 		BOTTOM_STATIC_WALL, | ||||
| 		UPPER_STATIC_WALL, | ||||
| @@ -41,7 +43,18 @@ namespace EWallVisual | ||||
| 		BACKGROUND_MOAT, | ||||
| 		KEEP_BATTLEMENT, | ||||
| 		BOTTOM_BATTLEMENT, | ||||
| 		UPPER_BATTLEMENT | ||||
| 		UPPER_BATTLEMENT, | ||||
|  | ||||
| 		CREATURE_KEEP, | ||||
| 		CREATURE_BOTTOM_TOWER, | ||||
| 		CREATURE_UPPER_TOWER, | ||||
|  | ||||
| 		WALL_FIRST = BACKGROUND_WALL, | ||||
| 		WALL_LAST  = UPPER_BATTLEMENT, | ||||
|  | ||||
| 		// these entries are mapped to EWallPart enum | ||||
| 		DESTRUCTIBLE_FIRST = KEEP, | ||||
| 		DESTRUCTIBLE_LAST = GATE, | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| @@ -49,32 +62,39 @@ class CBattleSiegeController | ||||
| { | ||||
| 	CBattleInterface * owner; | ||||
|  | ||||
| 	SDL_Surface *moatSurface; | ||||
| 	SDL_Surface *mlipSurface; | ||||
| 	/// besieged town | ||||
| 	const CGTownInstance *town; | ||||
|  | ||||
| 	SDL_Surface* walls[18]; | ||||
| 	const CGTownInstance *town; //besieged town | ||||
| 	/// sections of castle walls, in their currently visible state | ||||
| 	std::array<std::shared_ptr<IImage>, EWallVisual::WALL_LAST + 1> wallPieceImages; | ||||
|  | ||||
| 	std::string getSiegeName(ui16 what) const; | ||||
| 	std::string getSiegeName(ui16 what, int state) const; // state uses EWallState enum | ||||
| 	/// return URI for image for a wall piece | ||||
| 	std::string getWallPieceImageName(EWallVisual::EWallVisual what, EWallState::EWallState state) const; | ||||
|  | ||||
| 	void printPartOfWall(SDL_Surface *to, int what); | ||||
| 	/// returns BattleHex to which chosen wall piece is bound | ||||
| 	BattleHex getWallPiecePosition(EWallVisual::EWallVisual what) const; | ||||
|  | ||||
| 	/// returns true if chosen wall piece should be present in current battle | ||||
| 	bool getWallPieceExistance(EWallVisual::EWallVisual what) const; | ||||
|  | ||||
| 	void showWallPiece(SDL_Surface *to, EWallVisual::EWallVisual what); | ||||
|  | ||||
| public: | ||||
| 	CBattleSiegeController(CBattleInterface * owner, const CGTownInstance *siegeTown); | ||||
| 	~CBattleSiegeController(); | ||||
|  | ||||
| 	void showPiecesOfWall(SDL_Surface *to, std::vector<int> pieces); | ||||
|  | ||||
| 	std::string getBattleBackgroundName(); | ||||
| 	const CCreature *turretCreature(); | ||||
| 	Point turretCreaturePosition( BattleHex position ); | ||||
|  | ||||
| 	/// call-ins from server | ||||
| 	void gateStateChanged(const EGateState state); | ||||
| 	void stackIsCatapulting(const CatapultAttack & ca); | ||||
|  | ||||
| 	/// call-ins from other battle controllers | ||||
| 	void showAbsoluteObstacles(SDL_Surface * to); | ||||
| 	bool isCatapultAttackable(BattleHex hex) const; //returns true if given tile can be attacked by catapult | ||||
| 	void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls | ||||
| 	void showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ); | ||||
|  | ||||
| 	/// queries from other battle controllers | ||||
| 	bool isAttackableByCatapult(BattleHex hex) const; | ||||
| 	std::string getBattleBackgroundName() const; | ||||
| 	const CCreature *getTurretCreature() const; | ||||
| 	Point getTurretCreaturePosition( BattleHex position ) const; | ||||
|  | ||||
|  | ||||
| 	void sortObjectsByHex(BattleObjectsByHex & sorted); | ||||
| }; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
| #include "CBattleEffectsController.h" | ||||
| #include "CBattleProjectileController.h" | ||||
| #include "CBattleControlPanel.h" | ||||
| #include "../CBitmapHandler.h" | ||||
| #include "../gui/CAnimation.h" | ||||
| #include "../gui/SDL_Extensions.h" | ||||
| #include "../gui/CGuiHandler.h" | ||||
| #include "../../lib/battle/BattleHex.h" | ||||
| @@ -56,42 +56,24 @@ static void onAnimationFinished(const CStack *stack, std::weak_ptr<CCreatureAnim | ||||
| 	animation->onAnimationReset += std::bind(&onAnimationFinished, stack, anim); | ||||
| } | ||||
|  | ||||
| static void transformPalette(SDL_Surface *surf, double rCor, double gCor, double bCor) | ||||
| { | ||||
| 	SDL_Color *colorsToChange = surf->format->palette->colors; | ||||
| 	for (int g=0; g<surf->format->palette->ncolors; ++g) | ||||
| 	{ | ||||
| 		SDL_Color *color = &colorsToChange[g]; | ||||
| 		if (color->b != 132 && | ||||
| 			color->g != 231 && | ||||
| 			color->r != 255) //it's not yellow border | ||||
| 		{ | ||||
| 			color->r = static_cast<Uint8>(color->r * rCor); | ||||
| 			color->g = static_cast<Uint8>(color->g * gCor); | ||||
| 			color->b = static_cast<Uint8>(color->b * bCor); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CBattleStacksController::CBattleStacksController(CBattleInterface * owner): | ||||
| 	owner(owner) | ||||
| { | ||||
| 	//preparing graphics for displaying amounts of creatures | ||||
| 	amountNormal = BitmapHandler::loadBitmap("CMNUMWIN.BMP"); | ||||
| 	CSDL_Ext::alphaTransform(amountNormal); | ||||
| 	transformPalette(amountNormal, 0.59, 0.19, 0.93); | ||||
| 	amountNormal     = IImage::createFromFile("CMNUMWIN.BMP"); | ||||
| 	amountPositive   = IImage::createFromFile("CMNUMWIN.BMP"); | ||||
| 	amountNegative   = IImage::createFromFile("CMNUMWIN.BMP"); | ||||
| 	amountEffNeutral = IImage::createFromFile("CMNUMWIN.BMP"); | ||||
|  | ||||
| 	amountPositive = BitmapHandler::loadBitmap("CMNUMWIN.BMP"); | ||||
| 	CSDL_Ext::alphaTransform(amountPositive); | ||||
| 	transformPalette(amountPositive, 0.18, 1.00, 0.18); | ||||
| 	ColorShifterAddMulExcept shifterNormal  ({0,0,0,0}, {150,  48, 237, 255}, {132, 231, 255, 255}); | ||||
| 	ColorShifterAddMulExcept shifterPositive({0,0,0,0}, { 45, 255,  45, 255}, {132, 231, 255, 255}); | ||||
| 	ColorShifterAddMulExcept shifterNegative({0,0,0,0}, {255,  45,  45, 255}, {132, 231, 255, 255}); | ||||
| 	ColorShifterAddMulExcept shifterNeutral ({0,0,0,0}, {255, 255,  45, 255}, {132, 231, 255, 255}); | ||||
|  | ||||
| 	amountNegative = BitmapHandler::loadBitmap("CMNUMWIN.BMP"); | ||||
| 	CSDL_Ext::alphaTransform(amountNegative); | ||||
| 	transformPalette(amountNegative, 1.00, 0.18, 0.18); | ||||
|  | ||||
| 	amountEffNeutral = BitmapHandler::loadBitmap("CMNUMWIN.BMP"); | ||||
| 	CSDL_Ext::alphaTransform(amountEffNeutral); | ||||
| 	transformPalette(amountEffNeutral, 1.00, 1.00, 0.18); | ||||
| 	amountNormal->adjustPalette(&shifterNormal); | ||||
| 	amountPositive->adjustPalette(&shifterPositive); | ||||
| 	amountNegative->adjustPalette(&shifterNegative); | ||||
| 	amountEffNeutral->adjustPalette(&shifterNeutral); | ||||
|  | ||||
| 	std::vector<const CStack*> stacks = owner->curInt->cb->battleGetAllStacks(true); | ||||
| 	for(const CStack * s : stacks) | ||||
| @@ -100,15 +82,7 @@ CBattleStacksController::CBattleStacksController(CBattleInterface * owner): | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CBattleStacksController::~CBattleStacksController() | ||||
| { | ||||
| 	SDL_FreeSurface(amountNormal); | ||||
| 	SDL_FreeSurface(amountNegative); | ||||
| 	SDL_FreeSurface(amountPositive); | ||||
| 	SDL_FreeSurface(amountEffNeutral); | ||||
| } | ||||
|  | ||||
| void CBattleStacksController::sortObjectsByHex(BattleObjectsByHex & sorted) | ||||
| void CBattleStacksController::showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ) | ||||
| { | ||||
| 	auto getCurrentPosition = [&](const CStack *stack) -> BattleHex | ||||
| 	{ | ||||
| @@ -127,18 +101,15 @@ void CBattleStacksController::sortObjectsByHex(BattleObjectsByHex & sorted) | ||||
| 		return stack->getPosition(); | ||||
| 	}; | ||||
|  | ||||
| 	auto stacks = owner->curInt->cb->battleGetStacksIf([](const CStack *s) | ||||
| 	{ | ||||
| 		return !s->isTurret(); | ||||
| 	}); | ||||
| 	auto stacks = owner->curInt->cb->battleGetAllStacks(true); | ||||
|  | ||||
| 	for (auto & stack : stacks) | ||||
| 	{ | ||||
| 		if (creAnims.find(stack->ID) == creAnims.end()) //e.g. for summoned but not yet handled stacks | ||||
| 			continue; | ||||
|  | ||||
| 		if (stack->initialPosition < 0) // turret shooters are handled separately | ||||
| 			continue; | ||||
| 		//if (stack->initialPosition < 0) // turret shooters are handled separately | ||||
| 		//	continue; | ||||
|  | ||||
| 		//FIXME: hack to ignore ghost stacks | ||||
| 		if ((creAnims[stack->ID]->getType() == CCreatureAnim::DEAD || creAnims[stack->ID]->getType() == CCreatureAnim::HOLDING) && stack->isGhost()) | ||||
| @@ -146,24 +117,34 @@ void CBattleStacksController::sortObjectsByHex(BattleObjectsByHex & sorted) | ||||
|  | ||||
| 		if (creAnims[stack->ID]->isDead()) | ||||
| 		{ | ||||
| 			sorted.hex[stack->getPosition()].dead.push_back(stack); | ||||
| 			//if ( location == stack->getPosition() ) | ||||
| 			if ( location == BattleHex::HEX_BEFORE_ALL ) //FIXME: any cases when this won't work? | ||||
| 			{}; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		// standing - blit at current position | ||||
| 		if (!creAnims[stack->ID]->isMoving()) | ||||
| 		{ | ||||
| 			sorted.hex[stack->getPosition()].alive.push_back(stack); | ||||
| 			if ( location == stack->getPosition() ) | ||||
| 			{}; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		// flying creature - just blit them over everyone else | ||||
| 		if (stack->hasBonusOfType(Bonus::FLYING)) | ||||
| 		{ | ||||
| 			sorted.afterAll.alive.push_back(stack); | ||||
| 			if ( location == BattleHex::HEX_AFTER_ALL) | ||||
| 			{}; | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		sorted.hex[getCurrentPosition(stack)].alive.push_back(stack); | ||||
| 		// else - unit moving on ground | ||||
| 		{ | ||||
| 			if ( location == getCurrentPosition(stack) ) | ||||
| 			{}; | ||||
| 			continue; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -184,7 +165,7 @@ void CBattleStacksController::stackReset(const CStack * stack) | ||||
|  | ||||
| 	if (stack->isClone()) | ||||
| 	{ | ||||
| 		ColorShifterDeepBlue shifter; | ||||
| 		auto shifter = ColorShifterAddMul::deepBlue(); | ||||
| 		animation->shiftColor(&shifter); | ||||
| 	} | ||||
|  | ||||
| @@ -201,12 +182,12 @@ void CBattleStacksController::stackAdded(const CStack * stack) | ||||
| 	{ | ||||
| 		assert(owner->siegeController); | ||||
|  | ||||
| 		const CCreature *turretCreature = owner->siegeController->turretCreature(); | ||||
| 		const CCreature *turretCreature = owner->siegeController->getTurretCreature(); | ||||
|  | ||||
| 		creAnims[stack->ID] = AnimationControls::getAnimation(turretCreature); | ||||
| 		creAnims[stack->ID]->pos.h = 225; | ||||
|  | ||||
| 		coords = owner->siegeController->turretCreaturePosition(stack->initialPosition); | ||||
| 		coords = owner->siegeController->getTurretCreaturePosition(stack->initialPosition); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| @@ -263,7 +244,7 @@ void CBattleStacksController::setHoveredStack(const CStack *stack) | ||||
| 		mouseHoveredStack = nullptr; | ||||
| } | ||||
|  | ||||
| void CBattleStacksController::showAliveStacks(SDL_Surface *to, std::vector<const CStack *> stacks) | ||||
| bool CBattleStacksController::stackNeedsAmountBox(const CStack * stack) | ||||
| { | ||||
| 	BattleHex currentActionTarget; | ||||
| 	if(owner->curInt->curAction) | ||||
| @@ -273,39 +254,41 @@ void CBattleStacksController::showAliveStacks(SDL_Surface *to, std::vector<const | ||||
| 			currentActionTarget = target.at(0).hexValue; | ||||
| 	} | ||||
|  | ||||
| 	auto isAmountBoxVisible = [&](const CStack *stack) -> bool | ||||
| 	if(!stack->alive()) | ||||
| 		return false; | ||||
|  | ||||
| 	if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->getCount() == 1) //do not show box for singular war machines, stacked war machines with box shown are supported as extension feature | ||||
| 		return false; | ||||
|  | ||||
| 	if(stack->getCount() == 0) //hide box when target is going to die anyway - do not display "0 creatures" | ||||
| 		return false; | ||||
|  | ||||
| 	for(auto anim : pendingAnims) //no matter what other conditions below are, hide box when creature is playing hit animation | ||||
| 	{ | ||||
| 		if(stack->hasBonusOfType(Bonus::SIEGE_WEAPON) && stack->getCount() == 1) //do not show box for singular war machines, stacked war machines with box shown are supported as extension feature | ||||
| 		auto hitAnimation = dynamic_cast<CDefenceAnimation*>(anim.first); | ||||
| 		if(hitAnimation && (hitAnimation->stack->ID == stack->ID)) //we process only "current creature" as other creatures will be processed reliably on their own iteration | ||||
| 			return false; | ||||
| 	} | ||||
|  | ||||
| 		if(stack->getCount() == 0) //hide box when target is going to die anyway - do not display "0 creatures" | ||||
| 			return false; | ||||
|  | ||||
| 		for(auto anim : pendingAnims) //no matter what other conditions below are, hide box when creature is playing hit animation | ||||
| 	if(owner->curInt->curAction) | ||||
| 	{ | ||||
| 		if(owner->curInt->curAction->stackNumber == stack->ID) //stack is currently taking action (is not a target of another creature's action etc) | ||||
| 		{ | ||||
| 			auto hitAnimation = dynamic_cast<CDefenceAnimation*>(anim.first); | ||||
| 			if(hitAnimation && (hitAnimation->stack->ID == stack->ID)) //we process only "current creature" as other creatures will be processed reliably on their own iteration | ||||
| 			if(owner->curInt->curAction->actionType == EActionType::WALK || owner->curInt->curAction->actionType == EActionType::SHOOT) //hide when stack walks or shoots | ||||
| 				return false; | ||||
|  | ||||
| 			else if(owner->curInt->curAction->actionType == EActionType::WALK_AND_ATTACK && currentActionTarget != stack->getPosition()) //when attacking, hide until walk phase finished | ||||
| 				return false; | ||||
| 		} | ||||
|  | ||||
| 		if(owner->curInt->curAction) | ||||
| 		{ | ||||
| 			if(owner->curInt->curAction->stackNumber == stack->ID) //stack is currently taking action (is not a target of another creature's action etc) | ||||
| 			{ | ||||
| 				if(owner->curInt->curAction->actionType == EActionType::WALK || owner->curInt->curAction->actionType == EActionType::SHOOT) //hide when stack walks or shoots | ||||
| 					return false; | ||||
|  | ||||
| 				else if(owner->curInt->curAction->actionType == EActionType::WALK_AND_ATTACK && currentActionTarget != stack->getPosition()) //when attacking, hide until walk phase finished | ||||
| 					return false; | ||||
| 			} | ||||
|  | ||||
| 			if(owner->curInt->curAction->actionType == EActionType::SHOOT && currentActionTarget == stack->getPosition()) //hide if we are ranged attack target | ||||
| 				return false; | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	}; | ||||
| 		if(owner->curInt->curAction->actionType == EActionType::SHOOT && currentActionTarget == stack->getPosition()) //hide if we are ranged attack target | ||||
| 			return false; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void CBattleStacksController::showStackAmountBox(SDL_Surface *to, const CStack * stack) | ||||
| { | ||||
| 	auto getEffectsPositivness = [&](const std::vector<si32> & activeSpells) -> int | ||||
| 	{ | ||||
| 		int pos = 0; | ||||
| @@ -316,7 +299,7 @@ void CBattleStacksController::showAliveStacks(SDL_Surface *to, std::vector<const | ||||
| 		return pos; | ||||
| 	}; | ||||
|  | ||||
| 	auto getAmountBoxBackground = [&](int positivness) -> SDL_Surface * | ||||
| 	auto getAmountBoxBackground = [&](int positivness) -> auto | ||||
| 	{ | ||||
| 		if (positivness > 0) | ||||
| 			return amountPositive; | ||||
| @@ -325,48 +308,36 @@ void CBattleStacksController::showAliveStacks(SDL_Surface *to, std::vector<const | ||||
| 		return amountEffNeutral; | ||||
| 	}; | ||||
|  | ||||
| 	showStacks(to, stacks); // Actual display of all stacks | ||||
| 	const int sideShift = stack->side == BattleSide::ATTACKER ? 1 : -1; | ||||
| 	const int reverseSideShift = stack->side == BattleSide::ATTACKER ? -1 : 1; | ||||
| 	const BattleHex nextPos = stack->getPosition() + sideShift; | ||||
| 	const bool edge = stack->getPosition() % GameConstants::BFIELD_WIDTH == (stack->side == BattleSide::ATTACKER ? GameConstants::BFIELD_WIDTH - 2 : 1); | ||||
| 	const bool moveInside = !edge && !owner->fieldController->stackCountOutsideHex(nextPos); | ||||
| 	int xAdd = (stack->side == BattleSide::ATTACKER ? 220 : 202) + | ||||
| 			(stack->doubleWide() ? 44 : 0) * sideShift + | ||||
| 			(moveInside ? amountNormal->width() + 10 : 0) * reverseSideShift; | ||||
| 	int yAdd = 260 + ((stack->side == BattleSide::ATTACKER || moveInside) ? 0 : -15); | ||||
|  | ||||
| 	for (auto & stack : stacks) | ||||
| 	{ | ||||
| 		assert(stack); | ||||
| 		//printing amount | ||||
| 		if (isAmountBoxVisible(stack)) | ||||
| 		{ | ||||
| 			const int sideShift = stack->side == BattleSide::ATTACKER ? 1 : -1; | ||||
| 			const int reverseSideShift = stack->side == BattleSide::ATTACKER ? -1 : 1; | ||||
| 			const BattleHex nextPos = stack->getPosition() + sideShift; | ||||
| 			const bool edge = stack->getPosition() % GameConstants::BFIELD_WIDTH == (stack->side == BattleSide::ATTACKER ? GameConstants::BFIELD_WIDTH - 2 : 1); | ||||
| 			const bool moveInside = !edge && !owner->fieldController->stackCountOutsideHex(nextPos); | ||||
| 			int xAdd = (stack->side == BattleSide::ATTACKER ? 220 : 202) + | ||||
| 					   (stack->doubleWide() ? 44 : 0) * sideShift + | ||||
| 					   (moveInside ? amountNormal->w + 10 : 0) * reverseSideShift; | ||||
| 			int yAdd = 260 + ((stack->side == BattleSide::ATTACKER || moveInside) ? 0 : -15); | ||||
| 	//blitting amount background box | ||||
| 	std::vector<si32> activeSpells = stack->activeSpells(); | ||||
|  | ||||
| 			//blitting amount background box | ||||
| 			SDL_Surface *amountBG = amountNormal; | ||||
| 			std::vector<si32> activeSpells = stack->activeSpells(); | ||||
| 			if (!activeSpells.empty()) | ||||
| 				amountBG = getAmountBoxBackground(getEffectsPositivness(activeSpells)); | ||||
| 	auto amountBG = activeSpells.empty() ? amountNormal : getAmountBoxBackground(getEffectsPositivness(activeSpells)); | ||||
| 	amountBG->draw(to, creAnims[stack->ID]->pos.x + xAdd, creAnims[stack->ID]->pos.y + yAdd); | ||||
|  | ||||
| 			SDL_Rect temp_rect = genRect(amountBG->h, amountBG->w, creAnims[stack->ID]->pos.x + xAdd, creAnims[stack->ID]->pos.y + yAdd); | ||||
| 			SDL_BlitSurface(amountBG, nullptr, to, &temp_rect); | ||||
| 	//blitting amount | ||||
| 	Point textPos(creAnims[stack->ID]->pos.x + xAdd + amountNormal->width()/2, | ||||
| 			creAnims[stack->ID]->pos.y + yAdd + amountNormal->height()/2); | ||||
| 	graphics->fonts[FONT_TINY]->renderTextCenter(to, makeNumberShort(stack->getCount()), Colors::WHITE, textPos); | ||||
|  | ||||
| 			//blitting amount | ||||
| 			Point textPos(creAnims[stack->ID]->pos.x + xAdd + amountNormal->w/2, | ||||
| 						  creAnims[stack->ID]->pos.y + yAdd + amountNormal->h/2); | ||||
| 			graphics->fonts[FONT_TINY]->renderTextCenter(to, makeNumberShort(stack->getCount()), Colors::WHITE, textPos); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleStacksController::showStacks(SDL_Surface *to, std::vector<const CStack *> stacks) | ||||
| void CBattleStacksController::showStack(SDL_Surface *to, const CStack * stack) | ||||
| { | ||||
| 	for (const CStack *stack : stacks) | ||||
| 	{ | ||||
| 		creAnims[stack->ID]->nextFrame(to, facingRight(stack)); // do actual blit | ||||
| 		creAnims[stack->ID]->incrementFrame(float(GH.mainFPSmng->getElapsedMilliseconds()) / 1000); | ||||
| 	} | ||||
| 	creAnims[stack->ID]->nextFrame(to, facingRight(stack)); // do actual blit | ||||
| 	creAnims[stack->ID]->incrementFrame(float(GH.mainFPSmng->getElapsedMilliseconds()) / 1000); | ||||
|  | ||||
| 	if (stackNeedsAmountBox(stack)) | ||||
| 		showStackAmountBox(to, stack); | ||||
| } | ||||
|  | ||||
| void CBattleStacksController::updateBattleAnimations() | ||||
|   | ||||
| @@ -21,15 +21,16 @@ class CBattleAnimation; | ||||
| class CCreatureAnimation; | ||||
| class CStack; | ||||
| class CBattleAnimation; | ||||
| class IImage; | ||||
|  | ||||
| class CBattleStacksController | ||||
| { | ||||
| 	CBattleInterface * owner; | ||||
|  | ||||
| 	SDL_Surface *amountNormal; | ||||
| 	SDL_Surface *amountNegative; | ||||
| 	SDL_Surface *amountPositive; | ||||
| 	SDL_Surface *amountEffNeutral; | ||||
| 	std::shared_ptr<IImage> amountNormal; | ||||
| 	std::shared_ptr<IImage> amountNegative; | ||||
| 	std::shared_ptr<IImage> amountPositive; | ||||
| 	std::shared_ptr<IImage> amountEffNeutral; | ||||
|  | ||||
| 	std::list<std::pair<CBattleAnimation *, bool>> pendingAnims; //currently displayed animations <anim, initialized> | ||||
| 	std::map<int32_t, std::shared_ptr<CCreatureAnimation>> creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID) | ||||
| @@ -44,11 +45,13 @@ class CBattleStacksController | ||||
| 	si32 creatureSpellToCast; | ||||
|  | ||||
| 	ui32 animIDhelper; //for giving IDs for animations | ||||
|  | ||||
| 	bool stackNeedsAmountBox(const CStack * stack); | ||||
| 	void showStackAmountBox(SDL_Surface *to, const CStack * stack); | ||||
|  | ||||
| public: | ||||
| 	CBattleStacksController(CBattleInterface * owner); | ||||
| 	~CBattleStacksController(); | ||||
|  | ||||
| 	void sortObjectsByHex(BattleObjectsByHex & sorted); | ||||
| 	bool shouldRotate(const CStack * stack, const BattleHex & oldPos, const BattleHex & nextHex); | ||||
| 	bool facingRight(const CStack * stack); | ||||
|  | ||||
| @@ -72,8 +75,10 @@ public: | ||||
| 	void setHoveredStack(const CStack *stack); | ||||
| 	void setSelectedStack(const CStack *stack); | ||||
|  | ||||
| 	void showAliveStacks(SDL_Surface *to, std::vector<const CStack *> stacks); | ||||
| 	void showStacks(SDL_Surface *to, std::vector<const CStack *> stacks); | ||||
| 	void showAliveStack(SDL_Surface *to, const CStack * stack); | ||||
| 	void showStack(SDL_Surface *to, const CStack * stack); | ||||
|  | ||||
| 	void showBattlefieldObjects(SDL_Surface *to, const BattleHex & location ); | ||||
|  | ||||
| 	void addNewAnim(CBattleAnimation *anim); //adds new anim to pendingAnims | ||||
| 	void updateBattleAnimations(); | ||||
|   | ||||
| @@ -134,6 +134,11 @@ public: | ||||
| 	~SDLImageLoader(); | ||||
| }; | ||||
|  | ||||
| std::shared_ptr<IImage> IImage::createFromFile( const std::string & path ) | ||||
| { | ||||
| 	return std::shared_ptr<IImage>(new SDLImage(path)); | ||||
| } | ||||
|  | ||||
| // Extremely simple file cache. TODO: smarter, more general solution | ||||
| class CFileCache | ||||
| { | ||||
|   | ||||
| @@ -69,6 +69,9 @@ public: | ||||
|  | ||||
| 	IImage(); | ||||
| 	virtual ~IImage(); | ||||
|  | ||||
| 	/// loads image from specified file. Returns 0-sized images on failure | ||||
| 	static std::shared_ptr<IImage> createFromFile( const std::string & path ); | ||||
| }; | ||||
|  | ||||
| /// Class for handling animation | ||||
|   | ||||
| @@ -155,37 +155,50 @@ typedef void (*BlitterWithRotationVal)(SDL_Surface *src,SDL_Rect srcRect, SDL_Su | ||||
| class ColorShifter | ||||
| { | ||||
| public: | ||||
| 	virtual ~ColorShifter() = default; | ||||
| 	virtual SDL_Color shiftColor(SDL_Color clr) const = 0; | ||||
| 	~ColorShifter() = default; | ||||
| 	virtual SDL_Color shiftColor(SDL_Color input) const = 0; | ||||
| }; | ||||
|  | ||||
| class ColorShifterLightBlue : public ColorShifter | ||||
| class ColorShifterAddMul : public ColorShifter | ||||
| { | ||||
| 	SDL_Color add; | ||||
| 	SDL_Color mul; | ||||
| public: | ||||
| 	SDL_Color shiftColor(SDL_Color clr) const override | ||||
|  | ||||
| 	static ColorShifterAddMul deepBlue() | ||||
| 	{ | ||||
| 		clr.b = clr.b + (255 - clr.b) / 2; | ||||
| 		return clr; | ||||
| 		return ColorShifterAddMul({0, 0, 255, 0}, {255, 255, 0, 255}); | ||||
| 	} | ||||
|  | ||||
| 	ColorShifterAddMul(SDL_Color add, SDL_Color mul) : | ||||
| 		add(add), | ||||
| 		mul(mul) | ||||
| 	{} | ||||
|  | ||||
| 	SDL_Color shiftColor(SDL_Color input) const override | ||||
| 	{ | ||||
| 		return { | ||||
| 			uint8_t(std::min(255.f, std::round(input.r * float(mul.r) / 255 + add.r))), | ||||
| 			uint8_t(std::min(255.f, std::round(input.g * float(mul.g) / 255 + add.g))), | ||||
| 			uint8_t(std::min(255.f, std::round(input.b * float(mul.b) / 255 + add.b))), | ||||
| 			uint8_t(std::min(255.f, std::round(input.a * float(mul.a) / 255 + add.a))), | ||||
| 		}; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class ColorShifterDeepBlue : public ColorShifter | ||||
| class ColorShifterAddMulExcept : public ColorShifterAddMul | ||||
| { | ||||
| 	SDL_Color ignored; | ||||
| public: | ||||
| 	SDL_Color shiftColor(SDL_Color clr) const override | ||||
| 	{ | ||||
| 		clr.b = 255; | ||||
| 		return clr; | ||||
| 	} | ||||
| }; | ||||
| 	ColorShifterAddMulExcept(SDL_Color add, SDL_Color mul, SDL_Color ignored) : | ||||
| 		ColorShifterAddMul(add, mul) | ||||
| 	{} | ||||
|  | ||||
| class ColorShifterDeepRed : public ColorShifter | ||||
| { | ||||
| public: | ||||
| 	SDL_Color shiftColor(SDL_Color clr) const override | ||||
| 	SDL_Color shiftColor(SDL_Color input) const override | ||||
| 	{ | ||||
| 		clr.r = 255; | ||||
| 		return clr; | ||||
| 		if ( input.r == ignored.r && input.g == ignored.g && input.b == ignored.b && input.a == ignored.a) | ||||
| 			return input; | ||||
| 		return ColorShifterAddMul::shiftColor(input); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -468,18 +468,18 @@ OptionsTab::PlayerOptionsEntry::PlayerOptionsEntry(const PlayerSettings & S, con | ||||
| 	else | ||||
| 		whoCanPlay = HUMAN; | ||||
|  | ||||
| 	static const char * flags[] = | ||||
| 	static std::string flags[] = | ||||
| 	{ | ||||
| 		"AOFLGBR.DEF", "AOFLGBB.DEF", "AOFLGBY.DEF", "AOFLGBG.DEF", | ||||
| 		"AOFLGBO.DEF", "AOFLGBP.DEF", "AOFLGBT.DEF", "AOFLGBS.DEF" | ||||
| 	}; | ||||
| 	static const char * bgs[] = | ||||
| 	static std::string bgs[] = | ||||
| 	{ | ||||
| 		"ADOPRPNL.bmp", "ADOPBPNL.bmp", "ADOPYPNL.bmp", "ADOPGPNL.bmp", | ||||
| 		"ADOPOPNL.bmp", "ADOPPPNL.bmp", "ADOPTPNL.bmp", "ADOPSPNL.bmp" | ||||
| 	}; | ||||
|  | ||||
| 	background = std::make_shared<CPicture>(BitmapHandler::loadBitmap(bgs[s.color.getNum()]), 0, 0, true); | ||||
| 	background = std::make_shared<CPicture>(bgs[s.color.getNum()], 0, 0); | ||||
| 	labelPlayerName = std::make_shared<CLabel>(55, 10, EFonts::FONT_SMALL, EAlignment::CENTER, Colors::WHITE, s.name); | ||||
| 	labelWhoCanPlay = std::make_shared<CMultiLineLabel>(Rect(6, 23, 45, (int)graphics->fonts[EFonts::FONT_TINY]->getLineHeight()*2), EFonts::FONT_TINY, EAlignment::CENTER, Colors::WHITE, CGI->generaltexth->arraytxt[206 + whoCanPlay]); | ||||
|  | ||||
|   | ||||
| @@ -34,10 +34,15 @@ typedef boost::optional<ui8> BattleSideOpt; | ||||
| // for battle stacks' positions | ||||
| struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design | ||||
| { | ||||
| 	// helpers for siege | ||||
| 	static const si16 CASTLE_CENTRAL_TOWER = -2; | ||||
| 	static const si16 CASTLE_BOTTOM_TOWER = -3; | ||||
| 	static const si16 CASTLE_UPPER_TOWER = -4; | ||||
|  | ||||
| 	// helpers for rendering | ||||
| 	static const si16 HEX_BEFORE_ALL = std::numeric_limits<si16>::min(); | ||||
| 	static const si16 HEX_AFTER_ALL = std::numeric_limits<si16>::max(); | ||||
|  | ||||
| 	si16 hex; | ||||
| 	static const si16 INVALID = -1; | ||||
| 	enum EDir | ||||
|   | ||||
		Reference in New Issue
	
	Block a user