Browse Source

FIRST_STRIKE now supports ranged / melee subtypes, BLOCKS_RETALIATION
will properly block FIRST_STRIKE

Ivan Savenko 1 year ago
parent
commit
fc6a9924ee
3 changed files with 16 additions and 4 deletions
  1. 5 0
      docs/modders/Bonus/Bonus_Types.md
  2. 1 0
      lib/JsonNode.cpp
  3. 10 4
      server/battles/BattleActionProcessor.cpp

+ 5 - 0
docs/modders/Bonus/Bonus_Types.md

@@ -587,6 +587,11 @@ Affected unit will attack units on all hexes that surround attacked hex
 
 
 Affected unit will retaliate before enemy attacks, if able
 Affected unit will retaliate before enemy attacks, if able
 
 
+- subtype: 
+	- damageTypeMelee: only melee attacks affected
+	- damageTypeRanged: only ranged attacks affected. Note that unit also requires ability to retaliate in ranged, such as RANGED_RETALIATION bonus
+	- damageTypeAll: any attacks are affected
+
 ### SHOOTS_ALL_ADJACENT
 ### SHOOTS_ALL_ADJACENT
 
 
 Affected unit will attack units on all hexes that surround attacked hex in ranged attacks
 Affected unit will attack units on all hexes that surround attacked hex in ranged attacks

+ 1 - 0
lib/JsonNode.cpp

@@ -537,6 +537,7 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
 		case BonusType::NEGATE_ALL_NATURAL_IMMUNITIES:
 		case BonusType::NEGATE_ALL_NATURAL_IMMUNITIES:
 		case BonusType::CREATURE_DAMAGE:
 		case BonusType::CREATURE_DAMAGE:
 		case BonusType::FLYING:
 		case BonusType::FLYING:
+		case BonusType::FIRST_STRIKE:
 		case BonusType::GENERAL_DAMAGE_REDUCTION:
 		case BonusType::GENERAL_DAMAGE_REDUCTION:
 		case BonusType::PERCENTAGE_DAMAGE_BOOST:
 		case BonusType::PERCENTAGE_DAMAGE_BOOST:
 		case BonusType::SOUL_STEAL:
 		case BonusType::SOUL_STEAL:

+ 10 - 4
server/battles/BattleActionProcessor.cpp

@@ -268,7 +268,9 @@ bool BattleActionProcessor::doAttackAction(const CBattleInfoCallback & battle, c
 		totalAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, BonusSubtypeID(stack->creatureId()));
 		totalAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, BonusSubtypeID(stack->creatureId()));
 	}
 	}
 
 
-	const bool firstStrike = destinationStack->hasBonusOfType(BonusType::FIRST_STRIKE);
+	static const auto firstStrikeSelector = Selector::typeSubtype(BonusType::FIRST_STRIKE, BonusCustomSubtype::damageTypeAll).Or(Selector::typeSubtype(BonusType::FIRST_STRIKE, BonusCustomSubtype::damageTypeMelee));
+	const bool firstStrike = destinationStack->hasBonus(firstStrikeSelector);
+
 	const bool retaliation = destinationStack->ableToRetaliate();
 	const bool retaliation = destinationStack->ableToRetaliate();
 	bool ferocityApplied = false;
 	bool ferocityApplied = false;
 	int32_t defenderInitialQuantity = destinationStack->getCount();
 	int32_t defenderInitialQuantity = destinationStack->getCount();
@@ -276,7 +278,7 @@ bool BattleActionProcessor::doAttackAction(const CBattleInfoCallback & battle, c
 	for (int i = 0; i < totalAttacks; ++i)
 	for (int i = 0; i < totalAttacks; ++i)
 	{
 	{
 		//first strike
 		//first strike
-		if(i == 0 && firstStrike && retaliation)
+		if(i == 0 && firstStrike && retaliation && !stack->hasBonusOfType(BonusType::BLOCKS_RETALIATION))
 		{
 		{
 			makeAttack(battle, destinationStack, stack, 0, stack->getPosition(), true, false, true);
 			makeAttack(battle, destinationStack, stack, 0, stack->getPosition(), true, false, true);
 		}
 		}
@@ -353,7 +355,11 @@ bool BattleActionProcessor::doShootAction(const CBattleInfoCallback & battle, co
 		return false;
 		return false;
 	}
 	}
 
 
-	makeAttack(battle, stack, destinationStack, 0, destination, true, true, false);
+	static const auto firstStrikeSelector = Selector::typeSubtype(BonusType::FIRST_STRIKE, BonusCustomSubtype::damageTypeAll).Or(Selector::typeSubtype(BonusType::FIRST_STRIKE, BonusCustomSubtype::damageTypeRanged));
+	const bool firstStrike = destinationStack->hasBonus(firstStrikeSelector);
+
+	if (!firstStrike)
+		makeAttack(battle, stack, destinationStack, 0, destination, true, true, false);
 
 
 	//ranged counterattack
 	//ranged counterattack
 	if (destinationStack->hasBonusOfType(BonusType::RANGED_RETALIATION)
 	if (destinationStack->hasBonusOfType(BonusType::RANGED_RETALIATION)
@@ -375,7 +381,7 @@ bool BattleActionProcessor::doShootAction(const CBattleInfoCallback & battle, co
 		totalRangedAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, BonusSubtypeID(stack->creatureId()));
 		totalRangedAttacks += attackingHero->valOfBonuses(BonusType::HERO_GRANTS_ATTACKS, BonusSubtypeID(stack->creatureId()));
 	}
 	}
 
 
-	for(int i = 1; i < totalRangedAttacks; ++i)
+	for(int i = firstStrike ? 0:1; i < totalRangedAttacks; ++i)
 	{
 	{
 		if(
 		if(
 			stack->alive()
 			stack->alive()