* Caller of the Hunt - fixed rollback error on usage, added AI support for the card;

This commit is contained in:
Oleg Agafonov 2021-03-07 23:41:52 +04:00
parent 2906f86324
commit 53a2021a12
2 changed files with 129 additions and 23 deletions

View file

@ -4,26 +4,30 @@ import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.CostAdjuster;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.choices.Choice; import mage.choices.Choice;
import mage.choices.ChoiceCreatureType; import mage.choices.ChoiceCreatureType;
import mage.constants.*; import mage.constants.*;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/** /**
* @author jeffwadsworth * @author jeffwadsworth, JayDi85
*/ */
public final class CallerOfTheHunt extends CardImpl { public final class CallerOfTheHunt extends CardImpl {
@ -56,14 +60,58 @@ enum CallerOfTheHuntAdjuster implements CostAdjuster {
@Override @Override
public void adjustCosts(Ability ability, Game game) { public void adjustCosts(Ability ability, Game game) {
MageObject mageObject = game.getObject(ability.getSourceId()); if (game.inCheckPlayableState()) {
return;
}
Player controller = game.getPlayer(ability.getControllerId());
if (controller == null) {
return;
}
MageObject sourceObject = game.getObject(ability.getSourceId());
if (sourceObject == null) {
return;
}
// AI hint - find best creature type with max permanents, all creature type supports too
Map<SubType, Integer> usedSubTypeStats = new HashMap<>();
game.getBattlefield().getActivePermanents(ability.getControllerId(), game)
.stream()
.map(permanent -> permanent.getSubtype(game))
.flatMap(Collection::stream)
.distinct()
.forEach(subType -> {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(subType.getPredicate());
int amount = new PermanentsOnBattlefieldCount(filter).calculate(game, ability, null);
usedSubTypeStats.put(subType, amount);
});
int maxAmount = 0;
SubType maxSubType = null;
for (Map.Entry<SubType, Integer> entry : usedSubTypeStats.entrySet()) {
if (entry.getValue() > maxAmount) {
maxSubType = entry.getKey();
maxAmount = entry.getValue();
}
}
// choose creature type
SubType typeChoice;
if (controller.isComputer()) {
// AI hint - simulate type choose
game.getState().setValue(sourceObject.getId() + "_type", maxSubType);
} else {
// human choose
Effect effect = new ChooseCreatureTypeEffect(Outcome.Benefit); Effect effect = new ChooseCreatureTypeEffect(Outcome.Benefit);
if (mageObject != null) {
effect.apply(game, ability); effect.apply(game, ability);
} }
if (mageObject != null) { typeChoice = (SubType) game.getState().getValue(sourceObject.getId() + "_type");
SubType typeChoice = (SubType) game.getState().getValue(mageObject.getId() + "_type"); if (typeChoice == null) {
if (typeChoice != null) { return;
}
// apply boost
FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen creature type"); FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen creature type");
filter.add(typeChoice.getPredicate()); filter.add(typeChoice.getPredicate());
ContinuousEffect effectPowerToughness = new SetPowerToughnessSourceEffect( ContinuousEffect effectPowerToughness = new SetPowerToughnessSourceEffect(
@ -74,8 +122,6 @@ enum CallerOfTheHuntAdjuster implements CostAdjuster {
gainAbility.setTargetPointer(new FixedTarget(ability.getSourceId())); gainAbility.setTargetPointer(new FixedTarget(ability.getSourceId()));
game.getState().addEffect(gainAbility, ability); game.getState().addEffect(gainAbility, ability);
} }
}
}
} }
class ChooseCreatureTypeEffect extends OneShotEffect { class ChooseCreatureTypeEffect extends OneShotEffect {

View file

@ -0,0 +1,60 @@
package org.mage.test.cards.single.mmq;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
/**
* @author JayDi85
*/
public class CallerOfTheHuntTest extends CardTestPlayerBaseWithAIHelps {
@Test
public void test_Play_Manual() {
// As an additional cost to cast Caller of the Hunt, choose a creature type.
// Caller of the Hunt's power and toughness are each equal to the number of creatures of the chosen type on the battlefield.
addCard(Zone.HAND, playerA, "Caller of the Hunt"); // {2}{G}
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
//
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2);
addCard(Zone.BATTLEFIELD, playerB, "Goblin Archaeologist", 2);
// cast Caller of the Hunt and choose bear as a type (+3 boost)
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Caller of the Hunt");
setChoice(playerA, "Bear");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Caller of the Hunt", 1);
assertPowerToughness(playerA, "Caller of the Hunt", 3, 3); // +3 boost
}
@Test
public void test_Play_AI() {
// As an additional cost to cast Caller of the Hunt, choose a creature type.
// Caller of the Hunt's power and toughness are each equal to the number of creatures of the chosen type on the battlefield.
addCard(Zone.HAND, playerA, "Caller of the Hunt"); // {2}{G}
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
//
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1);
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2);
addCard(Zone.BATTLEFIELD, playerB, "Goblin Archaeologist", 2);
// ai must cast Caller of the Hunt and choose bear as a type (+3 boost)
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Caller of the Hunt", 1);
assertPowerToughness(playerA, "Caller of the Hunt", 3, 3); // +3 boost
}
}