| 
					
				 | 
			
			
				@@ -4790,7 +4790,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case EActionType::CATAPULT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			//TODO: unify with spells::effects:Catapult 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			auto getCatapultHitChance = [&](EWallPart::EWallPart part, const CHeroHandler::SBallisticsLevelInfo & sbi) -> int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto getCatapultHitChance = [](EWallPart::EWallPart part, const CHeroHandler::SBallisticsLevelInfo & sbi) -> int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				switch(part) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				{ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -4811,115 +4811,105 @@ bool CGameHandler::makeBattleAction(BattleAction &ba) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			auto wrapper = wrapAction(ba); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if(target.size() < 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto getBallisticsInfo = [this, &ba] (const CStack * actor) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				complain("Destination required for catapult action."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				ok = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			auto destination = target.at(0).hexValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			CHeroHandler::SBallisticsLevelInfo stackBallisticsParameters; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if(stack->getCreature()->idNumber == CreatureID::CATAPULT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				stackBallisticsParameters = VLC->heroh->ballistics.at(attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::BALLISTICS)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if(stack->hasBonusOfType(Bonus::CATAPULT_EXTRA_SHOTS)) //by design use advanced ballistics parameters with this bonus present, upg. cyclops use advanced ballistics, nonupg. use basic in OH3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					stackBallisticsParameters = VLC->heroh->ballistics.at(2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					stackBallisticsParameters.shots = 1; //skip default "2 shots" from adv. ballistics 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if(actor->getCreature()->idNumber == CreatureID::CATAPULT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					return VLC->heroh->ballistics.at(attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::BALLISTICS)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					stackBallisticsParameters = VLC->heroh->ballistics.at(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					//by design use advanced ballistics parameters with this bonus present, upg. cyclops use advanced ballistics, nonupg. use basic in OH3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					int ballisticsLevel = actor->hasBonusOfType(Bonus::CATAPULT_EXTRA_SHOTS) ? 2 : 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				stackBallisticsParameters.shots += std::max(stack->valOfBonuses(Bonus::CATAPULT_EXTRA_SHOTS), 0); //0 is allowed minimum to let modders force advanced ballistics for "oneshotting creatures" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					auto parameters = VLC->heroh->ballistics.at(ballisticsLevel); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					parameters.shots = 1 + std::max(actor->valOfBonuses(Bonus::CATAPULT_EXTRA_SHOTS), 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			auto wallPart = gs->curB->battleHexToWallPart(destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (!gs->curB->isWallPartPotentiallyAttackable(wallPart)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					return parameters; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto isWallPartAttackable = [this] (EWallPart::EWallPart part) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				complain("catapult tried to attack non-catapultable hex!"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return (gs->curB->si.wallState[part] == EWallState::INTACT || gs->curB->si.wallState[part] == EWallState::DAMAGED); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			//in successive iterations damage is dealt but not yet subtracted from wall's HPs 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			auto ¤tHP = gs->curB->si.wallState; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			CHeroHandler::SBallisticsLevelInfo stackBallisticsParameters = getBallisticsInfo(stack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			if (currentHP.at(wallPart) == EWallState::DESTROYED  ||  currentHP.at(wallPart) == EWallState::NONE) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				complain("catapult tried to attack already destroyed wall part!"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto wrapper = wrapAction(ba); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto destination = target.empty() ? BattleHex(BattleHex::INVALID) : target.at(0).hexValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			auto desiredTarget = gs->curB->battleHexToWallPart(destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			for (int g=0; g<stackBallisticsParameters.shots; ++g) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			for (int shotNumber=0; shotNumber<stackBallisticsParameters.shots; ++shotNumber) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				bool hitSuccessfull = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				auto attackedPart = wallPart; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				auto actualTarget = EWallPart::INVALID; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				do // catapult has chance to attack desired target. Otherwise - attacks randomly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if ( isWallPartAttackable(desiredTarget) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					 getRandomGenerator().nextInt(99) < getCatapultHitChance(desiredTarget, stackBallisticsParameters)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if (currentHP.at(attackedPart) != EWallState::DESTROYED && // this part can be hit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					   currentHP.at(attackedPart) != EWallState::NONE && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					   getRandomGenerator().nextInt(99) < getCatapultHitChance(attackedPart, stackBallisticsParameters))//hit is successful 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						hitSuccessfull = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					else // select new target 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						std::vector<EWallPart::EWallPart> allowedTargets; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						for (size_t i=0; i< currentHP.size(); i++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							if(currentHP.at(i) != EWallState::DESTROYED && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								currentHP.at(i) != EWallState::NONE) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								allowedTargets.push_back(EWallPart::EWallPart(i)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						if (allowedTargets.empty()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						attackedPart = *RandomGeneratorUtil::nextItem(allowedTargets, getRandomGenerator()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					actualTarget = desiredTarget; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				while (!hitSuccessfull); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					static const std::array<EWallPart::EWallPart, 4> walls = { EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					static const std::array<EWallPart::EWallPart, 3> towers= { EWallPart::BOTTOM_TOWER, EWallPart::KEEP, EWallPart::UPPER_TOWER }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					static const EWallPart::EWallPart gates = EWallPart::GATE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (!hitSuccessfull) // break triggered - no target to shoot at 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// in H3, catapult under automatic control will attack objects in following order: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					// walls, gates, towers 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					std::vector<EWallPart::EWallPart> potentialTargets; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					for (auto & part : walls ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						if (isWallPartAttackable(part)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							potentialTargets.push_back(part); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				CatapultAttack ca; //package for clients 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				CatapultAttack::AttackInfo attack; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				attack.attackedPart = attackedPart; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				attack.destinationTile = destination; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				attack.damageDealt = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				BattleUnitsChanged removeUnits; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (potentialTargets.empty() && isWallPartAttackable(gates)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							potentialTargets.push_back(gates); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				int dmgChance[] = { stackBallisticsParameters.noDmg, stackBallisticsParameters.oneDmg, stackBallisticsParameters.twoDmg }; //dmgChance[i] - chance for doing i dmg when hit is successful 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (potentialTargets.empty()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						for (auto & part : towers ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if (isWallPartAttackable(part)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								potentialTargets.push_back(part); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (potentialTargets.empty()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						break; // everything is gone, can't attack anymore 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					actualTarget = *RandomGeneratorUtil::nextItem(potentialTargets, getRandomGenerator()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				assert(actualTarget != EWallPart::INVALID); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				std::array<int, 3> damageChances = { stackBallisticsParameters.noDmg, stackBallisticsParameters.oneDmg, stackBallisticsParameters.twoDmg }; //dmgChance[i] - chance for doing i dmg when hit is successful 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				int totalChance = std::accumulate(damageChances.begin(), damageChances.end(), 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				int damageRandom = getRandomGenerator().nextInt(totalChance - 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				int dealtDamage = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				int dmgRand = getRandomGenerator().nextInt(99); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				//accumulating dmgChance 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				dmgChance[1] += dmgChance[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				dmgChance[2] += dmgChance[1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				//calculating dealt damage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				for (int damage = 0; damage < ARRAY_COUNT(dmgChance); ++damage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				for (int damage = 0; damage < damageChances.size(); ++damage) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					if (dmgRand <= dmgChance[damage]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (damageRandom <= damageChances[damage]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						attack.damageDealt = damage; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						dealtDamage = damage; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					damageRandom -= damageChances[damage]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				// attacked tile may have changed - update destination 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				attack.destinationTile = gs->curB->wallPartToBattleHex(EWallPart::EWallPart(attack.attackedPart)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				CatapultAttack::AttackInfo attack; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				attack.attackedPart = actualTarget; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				attack.destinationTile = gs->curB->wallPartToBattleHex(actualTarget); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				attack.damageDealt = dealtDamage; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				CatapultAttack ca; //package for clients 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				ca.attacker = ba.stackNumber; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				ca.attackedParts.push_back(attack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				sendAndApply(&ca); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				logGlobal->trace("Catapult attacks %d dealing %d damage", (int)attack.attackedPart, (int)attack.damageDealt); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				//removing creatures in turrets / keep if one is destroyed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (currentHP.at(attackedPart) - attack.damageDealt <= 0 && (attackedPart == EWallPart::KEEP || //HP enum subtraction not intuitive, consider using SiegeInfo::applyDamage 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					attackedPart == EWallPart::BOTTOM_TOWER || attackedPart == EWallPart::UPPER_TOWER)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (gs->curB->si.wallState[actualTarget] <= 0 && (actualTarget == EWallPart::KEEP || actualTarget == EWallPart::BOTTOM_TOWER || actualTarget == EWallPart::UPPER_TOWER)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					int posRemove = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					switch(attackedPart) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					switch(actualTarget) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					case EWallPart::KEEP: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						posRemove = BattleHex::CASTLE_CENTRAL_TOWER; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -4936,18 +4926,13 @@ bool CGameHandler::makeBattleAction(BattleAction &ba) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						if(elem->initialPosition == posRemove) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							BattleUnitsChanged removeUnits; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							removeUnits.changedStacks.emplace_back(elem->unitId(), UnitChanges::EOperation::REMOVE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							sendAndApply(&removeUnits); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				ca.attacker = ba.stackNumber; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				ca.attackedParts.push_back(attack); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				sendAndApply(&ca); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if(!removeUnits.changedStacks.empty()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					sendAndApply(&removeUnits); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			//finish by scope guard 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			break; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -6769,8 +6754,6 @@ void CGameHandler::runBattle() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::CATAPULT)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					BattleAction attack; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					auto destination = *RandomGeneratorUtil::nextItem(attackableBattleHexes, getRandomGenerator()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					attack.aimToHex(destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					attack.actionType = EActionType::CATAPULT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					attack.side = next->side; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					attack.stackNumber = next->ID; 
			 |