mirror of
https://github.com/correl/mage.git
synced 2024-11-28 19:19:55 +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.common.SimpleStaticAbility;
|
||||
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.OneShotEffect;
|
||||
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.CardSetInfo;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceCreatureType;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
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 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 {
|
||||
|
||||
|
@ -56,25 +60,67 @@ enum CallerOfTheHuntAdjuster implements CostAdjuster {
|
|||
|
||||
@Override
|
||||
public void adjustCosts(Ability ability, Game game) {
|
||||
MageObject mageObject = game.getObject(ability.getSourceId());
|
||||
Effect effect = new ChooseCreatureTypeEffect(Outcome.Benefit);
|
||||
if (mageObject != null) {
|
||||
effect.apply(game, ability);
|
||||
if (game.inCheckPlayableState()) {
|
||||
return;
|
||||
}
|
||||
if (mageObject != null) {
|
||||
SubType typeChoice = (SubType) game.getState().getValue(mageObject.getId() + "_type");
|
||||
if (typeChoice != null) {
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen creature type");
|
||||
filter.add(typeChoice.getPredicate());
|
||||
ContinuousEffect effectPowerToughness = new SetPowerToughnessSourceEffect(
|
||||
new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame);
|
||||
effectPowerToughness.setText("");
|
||||
SimpleStaticAbility setPT = new SimpleStaticAbility(Zone.ALL, effectPowerToughness);
|
||||
GainAbilityTargetEffect gainAbility = new GainAbilityTargetEffect(setPT, Duration.EndOfGame);
|
||||
gainAbility.setTargetPointer(new FixedTarget(ability.getSourceId()));
|
||||
game.getState().addEffect(gainAbility, ability);
|
||||
|
||||
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.apply(game, ability);
|
||||
}
|
||||
typeChoice = (SubType) game.getState().getValue(sourceObject.getId() + "_type");
|
||||
if (typeChoice == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// apply boost
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen creature type");
|
||||
filter.add(typeChoice.getPredicate());
|
||||
ContinuousEffect effectPowerToughness = new SetPowerToughnessSourceEffect(
|
||||
new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame);
|
||||
effectPowerToughness.setText("");
|
||||
SimpleStaticAbility setPT = new SimpleStaticAbility(Zone.ALL, effectPowerToughness);
|
||||
GainAbilityTargetEffect gainAbility = new GainAbilityTargetEffect(setPT, Duration.EndOfGame);
|
||||
gainAbility.setTargetPointer(new FixedTarget(ability.getSourceId()));
|
||||
game.getState().addEffect(gainAbility, ability);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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