Răsfoiți Sursa

Extract method for death stare / accurate shot, fix translation key

M 1 an în urmă
părinte
comite
bf7c6a4c3f

+ 2 - 1
Mods/vcmi/config/vcmi/english.json

@@ -184,8 +184,9 @@
 	"vcmi.battleWindow.damageEstimation.kills" : "%d will perish",
 	"vcmi.battleWindow.damageEstimation.kills.1" : "%d will perish",
 	"vcmi.battleWindow.killed" : "Killed",
-	"vcmi.battleWindow.accurateShot.resultDescription" : "%d %s were killed by accurate shots!",
+	"vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s were killed by accurate shots!",
 	"vcmi.battleWindow.accurateShot.resultDescription.1" : "1 %s was killed with an accurate shot!",
+	"vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s were killed by accurate shots!",
 
 	"vcmi.battleResultsWindow.applyResultsLabel" : "Apply battle result",
 

+ 69 - 63
server/battles/BattleActionProcessor.cpp

@@ -1245,85 +1245,91 @@ void BattleActionProcessor::handleAttackBeforeCasting(const CBattleInfoCallback
 	attackCasting(battle, ranged, BonusType::SPELL_BEFORE_ATTACK, attacker, defender); //no death stare / acid breath needed?
 }
 
-void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender)
+void BattleActionProcessor::HandleDeathStareAndPirateShot(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender)
 {
-	if(!attacker->alive() || !defender->alive()) // can be already dead
-		return;
+	// mechanics of Death Stare as in H3:
+	// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
+	//original formula x = min(x, (gorgons_count + 9)/10);
+
+	/* mechanics of Accurate Shot as in HotA:
+		* each creature in an attacking stack has a X% chance of killing a creature in the attacked squad,
+		* but the total number of killed creatures cannot be more than (number of creatures in an attacking squad) * X/100 (rounded up).
+		* X = 3 multiplier for shooting without penalty and X = 2 if shooting with penalty. Ability doesn't work if shooting at creatures behind walls.
+		*/
 
-	attackCasting(battle, ranged, BonusType::SPELL_AFTER_ATTACK, attacker, defender);
+	auto bonus = attacker->getBonus(Selector::type()(BonusType::DEATH_STARE));
+	if(bonus == nullptr)
+		bonus = attacker->getBonus(Selector::type()(BonusType::ACCURATE_SHOT));
 
-	if(!defender->alive())
+	if(bonus->type == BonusType::ACCURATE_SHOT && (!ranged || battle.battleHasWallPenalty(attacker, attacker->getPosition(), defender->getPosition())))
+		return; //should not work from behind walls, except being defender or under effect of golden bow etc.
+
+
+	int singleCreatureKillChancePercent;
+	if(bonus->type == BonusType::ACCURATE_SHOT)
 	{
-		//don't try death stare or acid breath on dead stack (crash!)
-		return;
+		singleCreatureKillChancePercent = attacker->valOfBonuses(BonusType::ACCURATE_SHOT);
+		if(battle.battleHasDistancePenalty(attacker, attacker->getPosition(), defender->getPosition()))
+			singleCreatureKillChancePercent = (singleCreatureKillChancePercent * 2) / 3;
 	}
+	else //DEATH_STARE
+		singleCreatureKillChancePercent = attacker->valOfBonuses(BonusType::DEATH_STARE, BonusCustomSubtype::deathStareGorgon);
 
-	if(attacker->hasBonusOfType(BonusType::DEATH_STARE) || attacker->hasBonusOfType(BonusType::ACCURATE_SHOT))
-	{
-		// mechanics of Death Stare as in H3:
-		// each gorgon have 10% chance to kill (counted separately in H3) -> binomial distribution
-		//original formula x = min(x, (gorgons_count + 9)/10);
+	double chanceToKill = singleCreatureKillChancePercent / 100.0;
+	vstd::amin(chanceToKill, 1); //cap at 100%
+	std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
+	int killedCreatures = distribution(gameHandler->getRandomGenerator().getStdGenerator());
 
-		/* mechanics of Accurate Shot as in HotA:
-		 * each creature in an attacking stack has a X% chance of killing a creature in the attacked squad,
-		 * but the total number of killed creatures cannot be more than (number of creatures in an attacking squad) * X/100 (rounded up).
-		 * X = 3 multiplier for shooting without penalty and X = 2 if shooting with penalty. Ability doesn't work if shooting at creatures behind walls.
-		*/
-
-		auto bonus = attacker->getBonus(Selector::type()(BonusType::DEATH_STARE));
-		if(bonus == nullptr)
-			bonus = attacker->getBonus(Selector::type()(BonusType::ACCURATE_SHOT));
+	if(bonus->type == BonusType::DEATH_STARE)
+	{
+		double cap = 1 / std::max(chanceToKill, (double)(0.01));//don't divide by 0
+		int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
+		vstd::amin(killedCreatures, maxToKill);
 
-		if(bonus->type == BonusType::ACCURATE_SHOT && (!ranged || battle.battleHasWallPenalty(attacker, attacker->getPosition(), defender->getPosition())))
-			return; //should not work from behind walls, except being defender or under effect of golden bow etc.
+		killedCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusCustomSubtype::deathStareCommander)) / defender->level();
+	}
+	else //ACCURATE_SHOT
+	{
+		bool isMaxToKillRounded = attacker->getCount() * singleCreatureKillChancePercent % 100 == 0;
+		int maxToKill = attacker->getCount() * singleCreatureKillChancePercent / 100 + (isMaxToKillRounded ? 0 : 1);
+		vstd::amin(killedCreatures, maxToKill);
+	}
 
-		int singleCreatureKillChancePercent;
-		if(bonus->type == BonusType::ACCURATE_SHOT)
-		{
-			singleCreatureKillChancePercent = attacker->valOfBonuses(BonusType::ACCURATE_SHOT);
-			if(battle.battleHasDistancePenalty(attacker, attacker->getPosition(), defender->getPosition()))
-				singleCreatureKillChancePercent = (singleCreatureKillChancePercent * 2) / 3;
-		}
-		else //DEATH_STARE
-			singleCreatureKillChancePercent = attacker->valOfBonuses(BonusType::DEATH_STARE, BonusCustomSubtype::deathStareGorgon);
+	if(killedCreatures)
+	{
+		//TODO: death stare or accurate shot was not originally available for multiple-hex attacks, but...
 
-		double chanceToKill = singleCreatureKillChancePercent / 100.0;
-		vstd::amin(chanceToKill, 1); //cap at 100%
-		std::binomial_distribution<> distribution(attacker->getCount(), chanceToKill);
-		int killedCreatures = distribution(gameHandler->getRandomGenerator().getStdGenerator());
+		SpellID spellID = SpellID(SpellID::DEATH_STARE); //also used as fallback spell for ACCURATE_SHOT
+		if(bonus->type == BonusType::ACCURATE_SHOT && bonus->subtype.as<SpellID>() != SpellID::NONE)
+			spellID = bonus->subtype.as<SpellID>();
 
-		if(bonus->type == BonusType::DEATH_STARE)
-		{
-			double cap = 1 / std::max(chanceToKill, (double)(0.01));//don't divide by 0
-			int maxToKill = static_cast<int>((attacker->getCount() + cap - 1) / cap); //not much more than chance * count
-			vstd::amin(killedCreatures, maxToKill);
+		const CSpell * spell = spellID.toSpell();
+		spells::AbilityCaster caster(attacker, 0);
 
-			killedCreatures += (attacker->level() * attacker->valOfBonuses(BonusType::DEATH_STARE, BonusCustomSubtype::deathStareCommander)) / defender->level();
-		}
-		else //ACCURATE_SHOT
-		{
-			bool isMaxToKillRounded = attacker->getCount() * singleCreatureKillChancePercent % 100 == 0;
-			int maxToKill = attacker->getCount() * singleCreatureKillChancePercent / 100 + (isMaxToKillRounded ? 0 : 1);
-			vstd::amin(killedCreatures, maxToKill);
-		}
+		spells::BattleCast parameters(&battle, &caster, spells::Mode::PASSIVE, spell);
+		spells::Target target;
+		target.emplace_back(defender);
+		parameters.setEffectValue(killedCreatures);
+		parameters.cast(gameHandler->spellEnv, target);
+	}
+}
 
-		if(killedCreatures)
-		{
-			//TODO: death stare or accurate shot was not originally available for multiple-hex attacks, but...
+void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender)
+{
+	if(!attacker->alive() || !defender->alive()) // can be already dead
+		return;
 
-			SpellID spellID = SpellID(SpellID::DEATH_STARE); //also used as fallback spell for ACCURATE_SHOT
-			if(bonus->type == BonusType::ACCURATE_SHOT && bonus->subtype.as<SpellID>() != SpellID::NONE)
-				spellID = bonus->subtype.as<SpellID>();
+	attackCasting(battle, ranged, BonusType::SPELL_AFTER_ATTACK, attacker, defender);
 
-			const CSpell * spell = spellID.toSpell();
-			spells::AbilityCaster caster(attacker, 0);
+	if(!defender->alive())
+	{
+		//don't try death stare or acid breath on dead stack (crash!)
+		return;
+	}
 
-			spells::BattleCast parameters(&battle, &caster, spells::Mode::PASSIVE, spell);
-			spells::Target target;
-			target.emplace_back(defender);
-			parameters.setEffectValue(killedCreatures);
-			parameters.cast(gameHandler->spellEnv, target);
-		}
+	if(attacker->hasBonusOfType(BonusType::DEATH_STARE) || attacker->hasBonusOfType(BonusType::ACCURATE_SHOT))
+	{
+		HandleDeathStareAndPirateShot(battle, ranged, attacker, defender);
 	}
 
 	if(!defender->alive())

+ 3 - 0
server/battles/BattleActionProcessor.h

@@ -44,6 +44,9 @@ class BattleActionProcessor : boost::noncopyable
 	void makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
 
 	void handleAttackBeforeCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender);
+
+	void HandleDeathStareAndPirateShot(const CBattleInfoCallback &battle, bool ranged, const CStack *attacker, const CStack *defender);
+
 	void handleAfterAttackCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender);
 	void attackCasting(const CBattleInfoCallback & battle, bool ranged, BonusType attackMode, const battle::Unit * attacker, const CStack * defender);