mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Fixes to effects of earthquake, obstacle-creating and offensive spells
This commit is contained in:
		| @@ -980,17 +980,17 @@ CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBas | ||||
| { | ||||
| } | ||||
|  | ||||
| CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> pos, int effects): | ||||
| CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> hex, int effects): | ||||
| 	CPointEffectAnimation(_owner, sound, animationName, effects) | ||||
| { | ||||
| 	battlehexes = pos; | ||||
| 	battlehexes = hex; | ||||
| } | ||||
|  | ||||
| CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex pos, int effects): | ||||
| CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex hex, int effects): | ||||
| 	CPointEffectAnimation(_owner, sound, animationName, effects) | ||||
| { | ||||
| 	assert(pos.isValid()); | ||||
| 	battlehexes.push_back(pos); | ||||
| 	assert(hex.isValid()); | ||||
| 	battlehexes.push_back(hex); | ||||
| } | ||||
|  | ||||
| CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<Point> pos, int effects): | ||||
| @@ -1005,6 +1005,14 @@ CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBas | ||||
| 	positions.push_back(pos); | ||||
| } | ||||
|  | ||||
| CPointEffectAnimation::CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, Point pos, BattleHex hex,   int effects): | ||||
| 	CPointEffectAnimation(_owner, sound, animationName, effects) | ||||
| { | ||||
| 	assert(hex.isValid()); | ||||
| 	battlehexes.push_back(hex); | ||||
| 	positions.push_back(pos); | ||||
| } | ||||
|  | ||||
| bool CPointEffectAnimation::init() | ||||
| { | ||||
| 	if(!CBattleAnimation::checkInitialConditions()) | ||||
| @@ -1019,9 +1027,8 @@ bool CPointEffectAnimation::init() | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	if (positions.empty() && battlehexes.empty()) | ||||
| 	if (screenFill()) | ||||
| 	{ | ||||
| 		//armageddon, create screen fill | ||||
| 		for(int i=0; i * first->width() < owner->pos.w ; ++i) | ||||
| 			for(int j=0; j * first->height() < owner->pos.h ; ++j) | ||||
| 				positions.push_back(Point(i * first->width(), j * first->height())); | ||||
| @@ -1032,35 +1039,36 @@ bool CPointEffectAnimation::init() | ||||
| 	be.animation = animation; | ||||
| 	be.currentFrame = 0; | ||||
|  | ||||
| 	for ( auto const position : positions) | ||||
| 	for (size_t i = 0; i < std::max(battlehexes.size(), positions.size()); ++i) | ||||
| 	{ | ||||
| 		be.x = position.x; | ||||
| 		be.y = position.y; | ||||
| 		be.position = BattleHex::INVALID; | ||||
| 		bool hasTile = i < battlehexes.size(); | ||||
| 		bool hasPosition = i < positions.size(); | ||||
|  | ||||
| 		owner->effectsController->battleEffects.push_back(be); | ||||
| 	} | ||||
|  | ||||
| 	for ( auto const tile : battlehexes) | ||||
| 	{ | ||||
| 		const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(tile, false); | ||||
|  | ||||
| 		assert(tile.isValid()); | ||||
| 		if(!tile.isValid()) | ||||
| 			continue; | ||||
|  | ||||
| 		Rect tilePos = owner->fieldController->hexPosition(tile); | ||||
| 		be.position = tile; | ||||
| 		be.x = tilePos.x + tilePos.w/2 - first->width()/2; | ||||
|  | ||||
| 		if(destStack && destStack->doubleWide()) // Correction for 2-hex creatures. | ||||
| 			be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2; | ||||
|  | ||||
| 		if (alignToBottom()) | ||||
| 			be.y = tilePos.y + tilePos.h - first->height(); | ||||
| 		if (hasTile && !forceOnTop()) | ||||
| 			be.position = battlehexes[i]; | ||||
| 		else | ||||
| 			be.y = tilePos.y - first->height()/2; | ||||
| 			be.position = BattleHex::INVALID; | ||||
|  | ||||
| 		if (hasPosition) | ||||
| 		{ | ||||
| 			be.x = positions[i].x; | ||||
| 			be.y = positions[i].y; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(battlehexes[i], false); | ||||
| 			Rect tilePos = owner->fieldController->hexPosition(battlehexes[i]); | ||||
|  | ||||
| 			be.x = tilePos.x + tilePos.w/2 - first->width()/2; | ||||
|  | ||||
| 			if(destStack && destStack->doubleWide()) // Correction for 2-hex creatures. | ||||
| 				be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2; | ||||
|  | ||||
| 			if (alignToBottom()) | ||||
| 				be.y = tilePos.y + tilePos.h - first->height(); | ||||
| 			else | ||||
| 				be.y = tilePos.y - first->height()/2; | ||||
| 		} | ||||
| 		owner->effectsController->battleEffects.push_back(be); | ||||
| 	} | ||||
| 	return true; | ||||
| @@ -1072,7 +1080,11 @@ void CPointEffectAnimation::nextFrame() | ||||
| 	playEffect(); | ||||
|  | ||||
| 	if (soundFinished && effectFinished) | ||||
| 	{ | ||||
| 		//remove visual effect itself only if sound has finished as well - necessary for obstacles like force field | ||||
| 		clearEffect(); | ||||
| 		delete this; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CPointEffectAnimation::alignToBottom() const | ||||
| @@ -1085,10 +1097,19 @@ bool CPointEffectAnimation::waitForSound() const | ||||
| 	return effectFlags & WAIT_FOR_SOUND; | ||||
| } | ||||
|  | ||||
| bool CPointEffectAnimation::forceOnTop() const | ||||
| { | ||||
| 	return effectFlags & FORCE_ON_TOP; | ||||
| } | ||||
|  | ||||
| bool CPointEffectAnimation::screenFill() const | ||||
| { | ||||
| 	return effectFlags & SCREEN_FILL; | ||||
| } | ||||
|  | ||||
| void CPointEffectAnimation::onEffectFinished() | ||||
| { | ||||
| 	effectFinished = true; | ||||
| 	clearEffect(); | ||||
| } | ||||
|  | ||||
| void CPointEffectAnimation::onSoundFinished() | ||||
| @@ -1118,6 +1139,9 @@ void CPointEffectAnimation::playSound() | ||||
|  | ||||
| void CPointEffectAnimation::playEffect() | ||||
| { | ||||
| 	if ( effectFinished ) | ||||
| 		return; | ||||
|  | ||||
| 	for(auto & elem : owner->effectsController->battleEffects) | ||||
| 	{ | ||||
| 		if(elem.effectID == ID) | ||||
| @@ -1126,6 +1150,7 @@ void CPointEffectAnimation::playEffect() | ||||
|  | ||||
| 			if(elem.currentFrame >= elem.animation->size()) | ||||
| 			{ | ||||
| 				elem.currentFrame = elem.animation->size() - 1; | ||||
| 				onEffectFinished(); | ||||
| 				break; | ||||
| 			} | ||||
|   | ||||
| @@ -262,6 +262,19 @@ public: | ||||
| 	CCastAnimation(CBattleInterface * owner_, const CStack * attacker, BattleHex dest_, const CStack * defender, const CSpell * spell); | ||||
| }; | ||||
|  | ||||
| struct CPointEffectParameters | ||||
| { | ||||
| 	std::vector<Point> positions; | ||||
| 	std::vector<BattleHex> tiles; | ||||
| 	std::string animation; | ||||
|  | ||||
| 	soundBase::soundID sound = soundBase::invalid; | ||||
| 	BattleHex boundHex = BattleHex::INVALID; | ||||
| 	bool aligntoBottom = false; | ||||
| 	bool waitForSound = false; | ||||
| 	bool screenFill = false; | ||||
| }; | ||||
|  | ||||
| /// Class that plays effect at one or more positions along with (single) sound effect | ||||
| class CPointEffectAnimation : public CBattleAnimation | ||||
| { | ||||
| @@ -277,6 +290,8 @@ class CPointEffectAnimation : public CBattleAnimation | ||||
|  | ||||
| 	bool alignToBottom() const; | ||||
| 	bool waitForSound() const; | ||||
| 	bool forceOnTop() const; | ||||
| 	bool screenFill() const; | ||||
|  | ||||
| 	void onEffectFinished(); | ||||
| 	void onSoundFinished(); | ||||
| @@ -289,7 +304,9 @@ public: | ||||
| 	enum EEffectFlags | ||||
| 	{ | ||||
| 		ALIGN_TO_BOTTOM = 1, | ||||
| 		WAIT_FOR_SOUND  = 2 | ||||
| 		WAIT_FOR_SOUND  = 2, | ||||
| 		FORCE_ON_TOP    = 4, | ||||
| 		SCREEN_FILL     = 8, | ||||
| 	}; | ||||
|  | ||||
| 	/// Create animation with screen-wide effect | ||||
| @@ -300,8 +317,10 @@ public: | ||||
| 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<Point> pos    , int effects = 0); | ||||
|  | ||||
| 	/// Create animation positioned at certain hex(es) | ||||
| 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex pos             , int effects = 0); | ||||
| 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> pos, int effects = 0); | ||||
| 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, BattleHex hex             , int effects = 0); | ||||
| 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, std::vector<BattleHex> hex, int effects = 0); | ||||
|  | ||||
| 	CPointEffectAnimation(CBattleInterface * _owner, soundBase::soundID sound, std::string animationName, Point pos, BattleHex hex,   int effects = 0); | ||||
| 	 ~CPointEffectAnimation(); | ||||
|  | ||||
| 	bool init() override; | ||||
|   | ||||
| @@ -583,7 +583,7 @@ void CBattleInterface::displayBattleLog(const std::vector<MetaString> & battleLo | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile) | ||||
| void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit) | ||||
| { | ||||
| 	for(const CSpell::TAnimation & animation : q) | ||||
| 	{ | ||||
| @@ -591,12 +591,21 @@ void CBattleInterface::displaySpellAnimationQueue(const CSpell::TAnimationQueue | ||||
| 			stacksController->addNewAnim(new CDummyAnimation(this, animation.pause)); | ||||
| 		else | ||||
| 		{ | ||||
| 			int flags = 0; | ||||
|  | ||||
| 			if (isHit) | ||||
| 				flags |= CPointEffectAnimation::FORCE_ON_TOP; | ||||
|  | ||||
| 			if (animation.verticalPosition == VerticalPosition::BOTTOM) | ||||
| 				flags |= CPointEffectAnimation::ALIGN_TO_BOTTOM; | ||||
|  | ||||
| 			if (!destinationTile.isValid()) | ||||
| 				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName)); | ||||
| 			else if (animation.verticalPosition == VerticalPosition::BOTTOM) | ||||
| 				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile, CPointEffectAnimation::ALIGN_TO_BOTTOM)); | ||||
| 				flags |= CPointEffectAnimation::SCREEN_FILL; | ||||
|  | ||||
| 			if (!destinationTile.isValid()) | ||||
| 				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, flags)); | ||||
| 			else | ||||
| 				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile)); | ||||
| 				stacksController->addNewAnim(new CPointEffectAnimation(this, soundBase::invalid, animation.resourceName, destinationTile, flags)); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -606,7 +615,7 @@ void CBattleInterface::displaySpellCast(SpellID spellID, BattleHex destinationTi | ||||
| 	const CSpell * spell = spellID.toSpell(); | ||||
|  | ||||
| 	if(spell) | ||||
| 		displaySpellAnimationQueue(spell->animationInfo.cast, destinationTile); | ||||
| 		displaySpellAnimationQueue(spell->animationInfo.cast, destinationTile, false); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destinationTile) | ||||
| @@ -614,7 +623,7 @@ void CBattleInterface::displaySpellEffect(SpellID spellID, BattleHex destination | ||||
| 	const CSpell *spell = spellID.toSpell(); | ||||
|  | ||||
| 	if(spell) | ||||
| 		displaySpellAnimationQueue(spell->animationInfo.affect, destinationTile); | ||||
| 		displaySpellAnimationQueue(spell->animationInfo.affect, destinationTile, false); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTile) | ||||
| @@ -622,7 +631,7 @@ void CBattleInterface::displaySpellHit(SpellID spellID, BattleHex destinationTil | ||||
| 	const CSpell * spell = spellID.toSpell(); | ||||
|  | ||||
| 	if(spell) | ||||
| 		displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile); | ||||
| 		displaySpellAnimationQueue(spell->animationInfo.hit, destinationTile, true); | ||||
| } | ||||
|  | ||||
| void CBattleInterface::setAnimSpeed(int set) | ||||
|   | ||||
| @@ -166,7 +166,7 @@ public: | ||||
|  | ||||
| 	void displayBattleLog(const std::vector<MetaString> & battleLog); | ||||
|  | ||||
| 	void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile); | ||||
| 	void displaySpellAnimationQueue(const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit); | ||||
| 	void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation | ||||
| 	void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation | ||||
| 	void displaySpellHit(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation | ||||
|   | ||||
| @@ -85,15 +85,7 @@ void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		std::string defname = spellObstacle->appearAnimation; | ||||
|  | ||||
| 		//TODO: sound | ||||
| 		//soundBase::QUIKSAND | ||||
| 		//soundBase::LANDMINE | ||||
| 		//soundBase::FORCEFLD | ||||
| 		//soundBase::fireWall | ||||
|  | ||||
| 		auto animation = std::make_shared<CAnimation>(defname); | ||||
| 		auto animation = std::make_shared<CAnimation>(spellObstacle->appearAnimation); | ||||
| 		animation->preload(); | ||||
|  | ||||
| 		auto first = animation->getImage(0, 0); | ||||
| @@ -103,10 +95,14 @@ void CBattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		//TODO: sound | ||||
| 		//soundBase::QUIKSAND | ||||
| 		//soundBase::LANDMINE | ||||
|  | ||||
| 		//we assume here that effect graphics have the same size as the usual obstacle image | ||||
| 		// -> if we know how to blit obstacle, let's blit the effect in the same place | ||||
| 		Point whereTo = getObstaclePosition(first, *oi); | ||||
| 		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::QUIKSAND, defname, whereTo, CPointEffectAnimation::WAIT_FOR_SOUND)); | ||||
| 		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, spellObstacle->appearAnimation, whereTo, oi->pos, CPointEffectAnimation::WAIT_FOR_SOUND)); | ||||
|  | ||||
| 		//so when multiple obstacles are added, they show up one after another | ||||
| 		owner->waitForAnims(); | ||||
|   | ||||
| @@ -333,7 +333,7 @@ void CBattleSiegeController::stackIsCatapulting(const CatapultAttack & ca) | ||||
| 			positions.push_back(owner->stacksController->getStackPositionAtHex(attackInfo.destinationTile, nullptr) + Point(99, 120)); | ||||
|  | ||||
|  | ||||
| 		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::invalid, "SGEXPL.DEF", positions)); | ||||
| 		owner->stacksController->addNewAnim(new CPointEffectAnimation(owner, soundBase::WALLHIT, "SGEXPL.DEF", positions)); | ||||
| 	} | ||||
|  | ||||
| 	owner->waitForAnims(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user