- Basic AI for AF Learn

- Some minor tweaks and fixes for AF Learn
This commit is contained in:
Hans Mackowiak
2021-04-07 05:11:55 +00:00
committed by Michael Kamensky
parent 5b77205b77
commit 0627d37f69
36 changed files with 382 additions and 17 deletions

View File

@@ -134,7 +134,7 @@ public class GameFormat implements Comparable<GameFormat> {
if (!this.allowedSetCodes_ro.isEmpty()) {
p = Predicates.and(p, printed ?
IPaperCard.Predicates.printedInSets(this.allowedSetCodes_ro, printed) :
(Predicate<PaperCard>)(StaticData.instance().getCommonCards().wasPrintedInSets(this.allowedSetCodes_ro)));
StaticData.instance().getCommonCards().wasPrintedInSets(this.allowedSetCodes_ro));
}
if (!this.allowedRarities.isEmpty()) {
List<Predicate<? super PaperCard>> crp = Lists.newArrayList();

View File

@@ -93,6 +93,7 @@ public enum ApiType {
Haunt (HauntEffect.class),
Investigate (InvestigateEffect.class),
ImmediateTrigger (ImmediateTriggerEffect.class),
Learn (LearnEffect.class),
LookAt (LookAtEffect.class),
LoseLife (LifeLoseEffect.class),
LosesGame (GameLossEffect.class),

View File

@@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
@@ -942,6 +943,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
// for Wish cards, if the player is controlled by someone else
// they can't fetch from the outside the game/sideboard
if (player.isControlled()) {
origin.remove(ZoneType.Sideboard);
}
CardCollection fetchList;
boolean shuffleMandatory = true;
boolean searchedLibrary = false;
@@ -1179,6 +1186,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
boolean combatChanged = false;
final CardZoneTable triggerList = new CardZoneTable();
for (Player player : HiddenOriginChoicesMap.keySet()) {
boolean searchedLibrary = HiddenOriginChoicesMap.get(player).searchedLibrary;
boolean shuffleMandatory = HiddenOriginChoicesMap.get(player).shuffleMandatory;
@@ -1188,12 +1198,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
ZoneType destination = HiddenOriginChoicesMap.get(player).destination;
CardCollection movedCards = new CardCollection();
long ts = game.getNextTimestamp();
final CardZoneTable triggerList = new CardZoneTable();
boolean combatChanged = false;
Player decider = chooser;
if (decider == null) {
decider = player;
}
Player decider = ObjectUtils.firstNonNull(chooser, player);
for (final Card c : chosenCards) {
Card movedCard = null;
@@ -1423,15 +1428,15 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
registerDelayedTrigger(sa, sa.getParam("AtEOT"), movedCards);
}
if (combatChanged) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}
triggerList.triggerChangesZoneAll(game);
}
if (combatChanged) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());
}
triggerList.triggerChangesZoneAll(game);
if (sa.hasParam("UntilHostLeavesPlay")) {
source.addLeavesPlayCommand(untilHostLeavesPlayCommand(triggerList, source));
}
if (sa.hasParam("UntilHostLeavesPlay")) {
source.addLeavesPlayCommand(untilHostLeavesPlayCommand(triggerList, source));
}
}

View File

@@ -0,0 +1,27 @@
package forge.game.ability.effects;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
public class LearnEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(SpellAbility sa) {
return "Learn. (You may reveal a Lesson card you own from outside the game and put it into your hand, or discard a card to draw a card.)";
}
@Override
public void resolve(SpellAbility sa) {
final Card source = sa.getHostCard();
final Game game = source.getGame();
CardZoneTable table = new CardZoneTable();
for (Player p : getTargetPlayers(sa)) {
p.learnLesson(sa, table);
}
table.triggerChangesZoneAll(game);
}
}

View File

@@ -2667,6 +2667,11 @@ public class Player extends GameEntity implements Comparable<Player> {
return null;
}
public final boolean isControlled() {
Player ctrlPlayer = this.getControllingPlayer();
return ctrlPlayer != null && ctrlPlayer != this;
}
public void addController(long timestamp, Player pl) {
final IGameEntitiesFactory master = (IGameEntitiesFactory)pl.getLobbyPlayer();
addController(timestamp, pl, master.createMindSlaveController(pl, this), true);
@@ -3604,4 +3609,49 @@ public class Player extends GameEntity implements Comparable<Player> {
game.getAction().revealTo(revealCards, otherPlayers, Localizer.getInstance().getMessage("lblRevealFaceDownCards"));
}
}
public void learnLesson(SpellAbility sa, CardZoneTable table) {
// Replacement effects
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
repParams.put(AbilityKey.Cause, sa);
if (game.getReplacementHandler().run(ReplacementType.Learn, repParams) != ReplacementResult.NotReplaced) {
return;
}
CardCollection list = new CardCollection();
if (!isControlled()) {
list.addAll(CardLists.getType(getZone(ZoneType.Sideboard), "Lesson"));
}
list.addAll(getZone(ZoneType.Hand));
if (list.isEmpty()) {
return;
}
Card c = getController().chooseSingleCardForZoneChange(ZoneType.Hand, ImmutableList.of(ZoneType.Sideboard, ZoneType.Hand),
sa, list, null, "Learn a Lesson", true, this);
if (c == null) {
return;
}
if (c.isInZone(ZoneType.Sideboard)) { // Sideboard Lesson to Hand
Card moved = game.getAction().moveTo(ZoneType.Hand, c, sa);
table.put(ZoneType.Sideboard, ZoneType.Hand, moved);
} else if (c.isInZone(ZoneType.Hand)) { // Discard and Draw
boolean firstDiscard = getNumDiscardedThisTurn() == 0;
if (discard(c, sa, table) != null) {
// Change this if something would make multiple player learn at the same time
// Discard Trigger outside Effect
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, this);
runParams.put(AbilityKey.Cards, new CardCollection(c));
runParams.put(AbilityKey.Cause, sa);
runParams.put(AbilityKey.FirstTime, firstDiscard);
getGame().getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false);
for (Card d : drawCards(1, sa)) {
table.put(ZoneType.Library, ZoneType.Hand, d); // does a ChangesZoneAll care about moving from Library to Hand
}
}
}
}
}

View File

@@ -485,6 +485,8 @@ public class PlayerView extends GameEntityView {
return TrackableProperty.Library;
case Flashback:
return TrackableProperty.Flashback;
case Sideboard:
return TrackableProperty.Sideboard;
default:
return null; //other zones not represented
}

View File

@@ -0,0 +1,52 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.game.replacement;
import java.util.Map;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
public class ReplaceLearn extends ReplacementEffect {
public ReplaceLearn(Map<String, String> map, Card host, boolean intrinsic) {
super(map, host, intrinsic);
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
*/
@Override
public boolean canReplace(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
*/
@Override
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
}
}

View File

@@ -28,6 +28,7 @@ public enum ReplacementType {
DrawCards(ReplaceDrawCards.class),
GainLife(ReplaceGainLife.class),
GameLoss(ReplaceGameLoss.class),
Learn(ReplaceLearn.class),
Mill(ReplaceMill.class),
Moved(ReplaceMoved.class),
ProduceMana(ReplaceProduceMana.class),

View File

@@ -171,6 +171,7 @@ public enum TrackableProperty {
Graveyard(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Hand(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Library(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Sideboard(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
Mana(TrackableTypes.ManaMapType, FreezeMode.IgnoresFreeze),
IsExtraTurn(TrackableTypes.BooleanType),
ExtraTurnCount(TrackableTypes.IntegerType),