mirror of
https://github.com/correl/mage.git
synced 2024-11-29 03:00:12 +00:00
* Caller of the Hunt - fixed rollback error on usage, added AI support for the card;
This commit is contained in:
parent
2906f86324
commit
53a2021a12
2 changed files with 129 additions and 23 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue