* Improve logic / avoid cheating

* Fix Aggregates.random on FCollection disaster

* Fix finding wrong SA

Co-authored-by: tool4EvEr <tool4EvEr@192.168.0.59>
This commit is contained in:
tool4ever
2022-11-18 20:37:34 +01:00
committed by GitHub
parent f610e1ae40
commit 8eca58e9e4
11 changed files with 33 additions and 20 deletions

View File

@@ -2282,23 +2282,31 @@ public class ComputerUtil {
if (goodChoices.isEmpty()) { if (goodChoices.isEmpty()) {
goodChoices = validCards; goodChoices = validCards;
} }
final CardCollection dChoices = new CardCollection();
if (min == 1 && max == 1) {
if (sa.hasParam("DiscardValid")) { if (sa.hasParam("DiscardValid")) {
final String validString = sa.getParam("DiscardValid"); final String validString = sa.getParam("DiscardValid");
if (validString.contains("Creature") && !validString.contains("nonCreature")) { if (validString.contains("Creature") && !validString.contains("nonCreature")) {
final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices); final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices);
if (c != null) { if (c != null) {
dChoices.add(c); return new CardCollection(c);
} }
} }
} }
}
// not enough good choices, need to fill the rest
int minDiff = min - goodChoices.size();
if (minDiff > 0) {
goodChoices.addAll(Aggregates.random(CardLists.filter(validCards, Predicates.not(Predicates.in(goodChoices))), minDiff));
return goodChoices;
}
Collections.sort(goodChoices, CardLists.TextLenComparator); Collections.sort(goodChoices, CardLists.TextLenComparator);
CardLists.sortByCmcDesc(goodChoices); CardLists.sortByCmcDesc(goodChoices);
dChoices.add(goodChoices.get(0));
return Aggregates.random(goodChoices, min, new CardCollection()); return new CardCollection(Aggregates.random(goodChoices, max));
} }
public static CardCollection getCardsToDiscardFromFriend(Player aiChooser, Player p, SpellAbility sa, CardCollection validCards, int min, int max) { public static CardCollection getCardsToDiscardFromFriend(Player aiChooser, Player p, SpellAbility sa, CardCollection validCards, int min, int max) {

View File

@@ -59,7 +59,7 @@ public class ChooseCardEffect extends SpellAbilityEffect {
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final Game game = activator.getGame(); final Game game = activator.getGame();
final CardCollection chosen = new CardCollection(); CardCollection chosen = new CardCollection();
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
final List<Player> tgtPlayers = getTargetPlayers(sa); final List<Player> tgtPlayers = getTargetPlayers(sa);
@@ -221,7 +221,8 @@ public class ChooseCardEffect extends SpellAbilityEffect {
} else if ((tgt == null) || p.canBeTargetedBy(sa)) { } else if ((tgt == null) || p.canBeTargetedBy(sa)) {
if (sa.hasParam("AtRandom") && !choices.isEmpty()) { if (sa.hasParam("AtRandom") && !choices.isEmpty()) {
Aggregates.random(choices, validAmount, chosen); // don't pass FCollection for direct modification, the Set part would get messed up
chosen = new CardCollection(Aggregates.random(choices, validAmount));
dontRevealToOwner = false; dontRevealToOwner = false;
} else { } else {
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " ";

View File

@@ -77,7 +77,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
} }
for (SpellAbility chosenSA : chosenSAs) { for (SpellAbility chosenSA : chosenSAs) {
if (sa.hasParam("AtRandom") && sa.getParam("AtRandom").equals("Urza") && chosenSA.usesTargeting()) { if (random && sa.getParam("AtRandom").equals("Urza") && chosenSA.usesTargeting()) {
List<Card> validTargets = CardUtil.getValidCardsToTarget(chosenSA.getTargetRestrictions(), sa); List<Card> validTargets = CardUtil.getValidCardsToTarget(chosenSA.getTargetRestrictions(), sa);
if (validTargets.isEmpty()) { if (validTargets.isEmpty()) {
List <SpellAbility> newChosenSAs = Lists.newArrayList(); List <SpellAbility> newChosenSAs = Lists.newArrayList();

View File

@@ -119,7 +119,7 @@ public class DiscardEffect extends SpellAbilityEffect {
} }
} }
return sb.toString(); return sb.toString();
} // discardStackDescription() }
@Override @Override
public void resolve(SpellAbility sa) { public void resolve(SpellAbility sa) {
@@ -314,5 +314,5 @@ public class DiscardEffect extends SpellAbilityEffect {
// run trigger if something got milled // run trigger if something got milled
table.triggerChangesZoneAll(game, sa); table.triggerChangesZoneAll(game, sa);
} // discardResolve() }
} }

View File

@@ -152,7 +152,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
} }
if (sa.hasParam("Random")) { if (sa.hasParam("Random")) {
choosenToSacrifice = Aggregates.random(validTargets, Math.min(amount, validTargets.size()), new CardCollection()); choosenToSacrifice = new CardCollection(Aggregates.random(validTargets, Math.min(amount, validTargets.size())));
} else if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSacrifice"), null)) { } else if (optional && !p.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantSacrifice"), null)) {
choosenToSacrifice = CardCollection.EMPTY; choosenToSacrifice = CardCollection.EMPTY;
} else { } else {

View File

@@ -1,7 +1,7 @@
Name:Hallow Name:Hallow
ManaCost:W ManaCost:W
Types:Instant Types:Instant
A:SP$ Effect | Cost$ W | ValidTgts$ Card.inZoneStack | TgtZone$ Stack | TgtPrompt$ Select target spell to prevent damage from | ReplacementEffects$ PreventDmg | ExileOnMoved$ Stack | RememberObjects$ TargetedSource | SpellDescription$ Prevent all damage target spell would deal this turn. You gain life equal to the damage prevented this way. A:SP$ Effect | Cost$ W | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | TgtPrompt$ Select target spell to prevent damage from | ReplacementEffects$ PreventDmg | ExileOnMoved$ Stack | RememberObjects$ TargetedSource | SpellDescription$ Prevent all damage target spell would deal this turn. You gain life equal to the damage prevented this way.
SVar:PreventDmg:Event$ DamageDone | ValidSource$ Card.IsRemembered | ReplaceWith$ GainLifeYou | PreventionEffect$ True | Description$ Prevent all damage that would be dealt by targeted spell this turn. You gain life equal to the damage prevented this way. SVar:PreventDmg:Event$ DamageDone | ValidSource$ Card.IsRemembered | ReplaceWith$ GainLifeYou | PreventionEffect$ True | Description$ Prevent all damage that would be dealt by targeted spell this turn. You gain life equal to the damage prevented this way.
SVar:GainLifeYou:DB$ GainLife | Defined$ You | LifeAmount$ X SVar:GainLifeYou:DB$ GainLife | Defined$ You | LifeAmount$ X
SVar:X:ReplaceCount$DamageAmount SVar:X:ReplaceCount$DamageAmount

View File

@@ -3,7 +3,7 @@ ManaCost:5 W
Types:Creature Human Cleric Wizard Types:Creature Human Cleric Wizard
PT:2/3 PT:2/3
A:AB$ Pump | Cost$ tapXType<2/Cleric> | ValidTgts$ Creature | KW$ Prevent all damage that would be dealt by CARDNAME. | IsCurse$ True | TgtPrompt$ Select target creature | SpellDescription$ Prevent all damage target creature would deal this turn. A:AB$ Pump | Cost$ tapXType<2/Cleric> | ValidTgts$ Creature | KW$ Prevent all damage that would be dealt by CARDNAME. | IsCurse$ True | TgtPrompt$ Select target creature | SpellDescription$ Prevent all damage target creature would deal this turn.
A:AB$ Effect | Cost$ tapXType<2/Wizard> | ValidTgts$ Card.inZoneStack | TgtZone$ Stack | IsCurse$ True | TgtPrompt$ Select target spell | RememberObjects$ TargetedSource | StaticAbilities$ STNoDmg | SubAbility$ DBCleanup | SpellDescription$ Prevent all damage target spell would deal this turn. A:AB$ Effect | Cost$ tapXType<2/Wizard> | ValidTgts$ Card | TargetType$ Spell | TgtZone$ Stack | IsCurse$ True | TgtPrompt$ Select target spell | RememberObjects$ TargetedSource | StaticAbilities$ STNoDmg | SubAbility$ DBCleanup | SpellDescription$ Prevent all damage target spell would deal this turn.
SVar:STNoDmg:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield,Stack | Affected$ Card.IsRemembered | AddKeyword$ Prevent all damage that would be dealt by CARDNAME. | Description$ Prevent all damage target spell would deal this turn. SVar:STNoDmg:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield,Stack | Affected$ Card.IsRemembered | AddKeyword$ Prevent all damage that would be dealt by CARDNAME. | Description$ Prevent all damage target spell would deal this turn.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All AI:RemoveDeck:All

View File

@@ -3,6 +3,6 @@ ManaCost:RG RG
Types:Creature Goblin Shaman Types:Creature Goblin Shaman
PT:2/2 PT:2/2
K:This spell can't be countered. K:This spell can't be countered.
A:AB$ Pump | Cost$ RG | ValidTgts$ Card.inZoneStack | TgtZone$ Stack | PumpZone$ Stack | KW$ HIDDEN CARDNAME can't be countered. | SpellDescription$ Target spell can't be countered. A:AB$ Pump | Cost$ RG | ValidTgts$ Card | TgtZone$ Stack | TargetType$ Spell | PumpZone$ Stack | KW$ HIDDEN CARDNAME can't be countered. | SpellDescription$ Target spell can't be countered.
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:This spell can't be countered.\n{R/G}: Target spell can't be countered. Oracle:This spell can't be countered.\n{R/G}: Target spell can't be countered.

View File

@@ -114,7 +114,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
int c = cost.getAbilityAmount(ability); int c = cost.getAbilityAmount(ability);
if (discardType.equals("Random")) { if (discardType.equals("Random")) {
CardCollectionView randomSubset = Aggregates.random(hand, c, new CardCollection()); CardCollectionView randomSubset = new CardCollection(Aggregates.random(hand, c));
if (randomSubset.size() > 1 && ability.getActivatingPlayer() != null) { if (randomSubset.size() > 1 && ability.getActivatingPlayer() != null) {
randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability); randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability);
} }

View File

@@ -477,7 +477,7 @@ public class HumanPlay {
return false; return false;
} }
((CostDiscard)part).payAsDecided(p, PaymentDecision.card(Aggregates.random(p.getCardsIn(ZoneType.Hand), amount, new CardCollection())), sourceAbility, true); ((CostDiscard)part).payAsDecided(p, PaymentDecision.card(Aggregates.random(p.getCardsIn(ZoneType.Hand), amount)), sourceAbility, true);
} else { } else {
CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), part.getType(), p, source, sourceAbility); CardCollectionView list = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), part.getType(), p, source, sourceAbility);
boolean hasPaid = payCostPart(controller, p, sourceAbility, hcd.isEffect(), (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lbldiscard") + orString); boolean hasPaid = payCostPart(controller, p, sourceAbility, hcd.isEffect(), (CostPartWithList)part, amount, list, Localizer.getInstance().getMessage("lbldiscard") + orString);

View File

@@ -298,6 +298,10 @@ public class TargetSelection {
// By peeking at stack item, target is set to its SI state. So set it back before adding targets // By peeking at stack item, target is set to its SI state. So set it back before adding targets
ability.resetTargets(); ability.resetTargets();
} }
// make sure we're not accidentally finding a cast trigger of this card first
if (!abilityOnStack.isSpell()) {
continue;
}
if (abilityOnStack.getHostCard().getView().equals(chosen)) { if (abilityOnStack.getHostCard().getView().equals(chosen)) {
ability.getTargets().add(abilityOnStack); ability.getTargets().add(abilityOnStack);
break; break;