mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
AI and test framework improved:
* Now AI can see and use special mana payments like convoke, delve, improvise pays; * Now devs can test special mana payments (disable auto-payment and use choices for mana pool and special pays); * Fixed broken TargetDiscard in tests; * Fixed broken same named targets in tests;
This commit is contained in:
parent
c2e7b02e13
commit
10cf884923
2 changed files with 88 additions and 19 deletions
|
@ -1533,10 +1533,34 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pay phyrexian life costs
|
// pay phyrexian life costs
|
||||||
if (cost instanceof PhyrexianManaCost) {
|
if (cost instanceof PhyrexianManaCost) {
|
||||||
return cost.pay(null, game, null, playerId, false, null) || permittingObject != null;
|
return cost.pay(null, game, null, playerId, false, null) || permittingObject != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pay special mana like convoke cost (tap for pay)
|
||||||
|
// GUI: user see "special" button while pay spell's cost
|
||||||
|
// TODO: AI can't prioritize special mana types to pay, e.g. it will use first available
|
||||||
|
SpecialAction specialAction = game.getState().getSpecialActions().getControlledBy(this.getId(), true)
|
||||||
|
.values().stream().findFirst().orElse(null);
|
||||||
|
ManaOptions specialMana = specialAction == null ? null : specialAction.getManaOptions(ability, game, unpaid);
|
||||||
|
if (specialMana != null) {
|
||||||
|
for (Mana netMana : specialMana) {
|
||||||
|
if (cost.testPay(netMana) || permittingObject != null) {
|
||||||
|
if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
specialAction.setUnpaidMana(unpaid);
|
||||||
|
if (activateAbility(specialAction, game)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// only one time try to pay
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1795,7 +1795,7 @@ public class TestPlayer implements Player {
|
||||||
|
|
||||||
assertAliasSupportInChoices(true);
|
assertAliasSupportInChoices(true);
|
||||||
if (!choices.isEmpty()) {
|
if (!choices.isEmpty()) {
|
||||||
List<String> usedChoices = new ArrayList<>();
|
List<Integer> usedChoices = new ArrayList<>();
|
||||||
List<UUID> usedTargets = new ArrayList<>();
|
List<UUID> usedTargets = new ArrayList<>();
|
||||||
|
|
||||||
Ability source = null;
|
Ability source = null;
|
||||||
|
@ -1883,7 +1883,8 @@ public class TestPlayer implements Player {
|
||||||
boolean targetCompleted = false;
|
boolean targetCompleted = false;
|
||||||
|
|
||||||
CheckAllChoices:
|
CheckAllChoices:
|
||||||
for (String choiceRecord : choices) {
|
for (int choiceIndex = 0; choiceIndex < choices.size(); choiceIndex++) {
|
||||||
|
String choiceRecord = choices.get(choiceIndex);
|
||||||
if (targetCompleted) {
|
if (targetCompleted) {
|
||||||
break CheckAllChoices;
|
break CheckAllChoices;
|
||||||
}
|
}
|
||||||
|
@ -1923,14 +1924,19 @@ public class TestPlayer implements Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetFound) {
|
if (targetFound) {
|
||||||
usedChoices.add(choiceRecord);
|
usedChoices.add(choiceIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply only on ALL targets or revert
|
// apply only on ALL targets or revert
|
||||||
if (usedChoices.size() > 0) {
|
if (usedChoices.size() > 0) {
|
||||||
if (target.isChosen()) {
|
if (target.isChosen()) {
|
||||||
choices.removeAll(usedChoices);
|
// remove all used choices
|
||||||
|
for (int i = choices.size(); i >= 0; i--) {
|
||||||
|
if (usedChoices.contains(i)) {
|
||||||
|
choices.remove(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
Assert.fail("Not full targets list.");
|
Assert.fail("Not full targets list.");
|
||||||
|
@ -2091,7 +2097,7 @@ public class TestPlayer implements Player {
|
||||||
if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) {
|
if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) {
|
||||||
target.addTarget(permanent.getId(), source, game);
|
target.addTarget(permanent.getId(), source, game);
|
||||||
targetFound = true;
|
targetFound = true;
|
||||||
break; // return to for (String targetName
|
break; // return to next targetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2105,18 +2111,19 @@ public class TestPlayer implements Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
// card in hand
|
// card in hand
|
||||||
if (target.getOriginalTarget() instanceof TargetCardInHand) {
|
if (target.getOriginalTarget() instanceof TargetCardInHand
|
||||||
|
|| target.getOriginalTarget() instanceof TargetDiscard) {
|
||||||
for (String targetDefinition : targets) {
|
for (String targetDefinition : targets) {
|
||||||
checkTargetDefinitionMarksSupport(target, targetDefinition, "^");
|
checkTargetDefinitionMarksSupport(target, targetDefinition, "^");
|
||||||
String[] targetList = targetDefinition.split("\\^");
|
String[] targetList = targetDefinition.split("\\^");
|
||||||
boolean targetFound = false;
|
boolean targetFound = false;
|
||||||
for (String targetName : targetList) {
|
for (String targetName : targetList) {
|
||||||
for (Card card : computerPlayer.getHand().getCards(((TargetCardInHand) target.getOriginalTarget()).getFilter(), game)) {
|
for (Card card : computerPlayer.getHand().getCards(((TargetCard) target.getOriginalTarget()).getFilter(), game)) {
|
||||||
if (hasObjectTargetNameOrAlias(card, targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { // TODO: remove set code search?
|
if (hasObjectTargetNameOrAlias(card, targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { // TODO: remove set code search?
|
||||||
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) {
|
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) {
|
||||||
target.addTarget(card.getId(), source, game);
|
target.addTarget(card.getId(), source, game);
|
||||||
targetFound = true;
|
targetFound = true;
|
||||||
break; // return to for (String targetName
|
break; // return to next targetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2141,7 +2148,7 @@ public class TestPlayer implements Player {
|
||||||
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) {
|
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) {
|
||||||
target.addTarget(card.getId(), source, game);
|
target.addTarget(card.getId(), source, game);
|
||||||
targetFound = true;
|
targetFound = true;
|
||||||
break; // return to for (String targetName
|
break; // return to next targetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2166,7 +2173,7 @@ public class TestPlayer implements Player {
|
||||||
if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !targetFull.getTargets().contains(card.getId())) {
|
if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !targetFull.getTargets().contains(card.getId())) {
|
||||||
targetFull.add(card.getId(), game);
|
targetFull.add(card.getId(), game);
|
||||||
targetFound = true;
|
targetFound = true;
|
||||||
break; // return to for (String targetName
|
break; // return to next targetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2216,7 +2223,7 @@ public class TestPlayer implements Player {
|
||||||
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) {
|
if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) {
|
||||||
target.addTarget(card.getId(), source, game);
|
target.addTarget(card.getId(), source, game);
|
||||||
targetFound = true;
|
targetFound = true;
|
||||||
break IterateGraveyards; // return to for (String targetName
|
break IterateGraveyards; // return to next targetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2243,7 +2250,7 @@ public class TestPlayer implements Player {
|
||||||
if (target.canTarget(abilityControllerId, stackObject.getId(), source, game) && !target.getTargets().contains(stackObject.getId())) {
|
if (target.canTarget(abilityControllerId, stackObject.getId(), source, game) && !target.getTargets().contains(stackObject.getId())) {
|
||||||
target.addTarget(stackObject.getId(), source, game);
|
target.addTarget(stackObject.getId(), source, game);
|
||||||
targetFound = true;
|
targetFound = true;
|
||||||
break; // return to for (String targetName
|
break; // return to next targetName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3620,38 +3627,76 @@ public class TestPlayer implements Player {
|
||||||
groupsForTargetHandling = null;
|
groupsForTargetHandling = null;
|
||||||
|
|
||||||
if (!computerPlayer.getManaPool().isAutoPayment()) {
|
if (!computerPlayer.getManaPool().isAutoPayment()) {
|
||||||
// manual pay by mana clicks/commands
|
|
||||||
if (!choices.isEmpty()) {
|
if (!choices.isEmpty()) {
|
||||||
String needColor = choices.get(0);
|
// manual pay by mana clicks/commands
|
||||||
switch (needColor) {
|
String choice = choices.get(0);
|
||||||
|
boolean choiceUsed = false;
|
||||||
|
boolean choiceRemoved = false;
|
||||||
|
switch (choice) {
|
||||||
case "White":
|
case "White":
|
||||||
Assert.assertTrue("pool must have white mana", computerPlayer.getManaPool().getWhite() > 0);
|
Assert.assertTrue("pool must have white mana", computerPlayer.getManaPool().getWhite() > 0);
|
||||||
computerPlayer.getManaPool().unlockManaType(ManaType.WHITE);
|
computerPlayer.getManaPool().unlockManaType(ManaType.WHITE);
|
||||||
|
choiceUsed = true;
|
||||||
break;
|
break;
|
||||||
case "Blue":
|
case "Blue":
|
||||||
Assert.assertTrue("pool must have blue mana", computerPlayer.getManaPool().getBlue() > 0);
|
Assert.assertTrue("pool must have blue mana", computerPlayer.getManaPool().getBlue() > 0);
|
||||||
computerPlayer.getManaPool().unlockManaType(ManaType.BLUE);
|
computerPlayer.getManaPool().unlockManaType(ManaType.BLUE);
|
||||||
|
choiceUsed = true;
|
||||||
break;
|
break;
|
||||||
case "Black":
|
case "Black":
|
||||||
Assert.assertTrue("pool must have black mana", computerPlayer.getManaPool().getBlack() > 0);
|
Assert.assertTrue("pool must have black mana", computerPlayer.getManaPool().getBlack() > 0);
|
||||||
computerPlayer.getManaPool().unlockManaType(ManaType.BLACK);
|
computerPlayer.getManaPool().unlockManaType(ManaType.BLACK);
|
||||||
|
choiceUsed = true;
|
||||||
break;
|
break;
|
||||||
case "Red":
|
case "Red":
|
||||||
Assert.assertTrue("pool must have red mana", computerPlayer.getManaPool().getRed() > 0);
|
Assert.assertTrue("pool must have red mana", computerPlayer.getManaPool().getRed() > 0);
|
||||||
computerPlayer.getManaPool().unlockManaType(ManaType.RED);
|
computerPlayer.getManaPool().unlockManaType(ManaType.RED);
|
||||||
|
choiceUsed = true;
|
||||||
break;
|
break;
|
||||||
case "Green":
|
case "Green":
|
||||||
Assert.assertTrue("pool must have green mana", computerPlayer.getManaPool().getGreen() > 0);
|
Assert.assertTrue("pool must have green mana", computerPlayer.getManaPool().getGreen() > 0);
|
||||||
computerPlayer.getManaPool().unlockManaType(ManaType.GREEN);
|
computerPlayer.getManaPool().unlockManaType(ManaType.GREEN);
|
||||||
|
choiceUsed = true;
|
||||||
|
break;
|
||||||
|
case "Colorless":
|
||||||
|
Assert.assertTrue("pool must have colorless mana", computerPlayer.getManaPool().getColorless() > 0);
|
||||||
|
computerPlayer.getManaPool().unlockManaType(ManaType.COLORLESS);
|
||||||
|
choiceUsed = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Assert.fail("Unknown choice command for mana unlock: " + needColor);
|
// go to special block
|
||||||
|
//Assert.fail("Unknown choice command for mana unlock: " + needColor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
choices.remove(0);
|
|
||||||
return true;
|
// manual pay by special actions like convoke
|
||||||
|
if (!choiceUsed) {
|
||||||
|
Map<UUID, SpecialAction> specialActions = game.getState().getSpecialActions().getControlledBy(this.getId(), true);
|
||||||
|
for (SpecialAction specialAction : specialActions.values()) {
|
||||||
|
if (specialAction.getRule(true).startsWith(choice)) {
|
||||||
|
if (specialAction.canActivate(this.getId(), game).canActivate()) {
|
||||||
|
choices.remove(0);
|
||||||
|
choiceRemoved = true;
|
||||||
|
specialAction.setUnpaidMana(unpaid);
|
||||||
|
if (activateAbility(specialAction, game)) {
|
||||||
|
choiceUsed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choiceUsed) {
|
||||||
|
if (!choiceRemoved) {
|
||||||
|
choices.remove(0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Assert.fail("Can't use choice in play mana: " + choice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Assert.fail(this.getName() + " disabled mana auto-payment, but no choices found for color unlock in pool for unpaid cost: " + unpaid.getText());
|
|
||||||
|
Assert.fail(this.getName() + " disabled mana auto-payment, but no choices found for color unlock in pool or special action for unpaid cost: " + unpaid.getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
return computerPlayer.playMana(ability, unpaid, promptText, game);
|
return computerPlayer.playMana(ability, unpaid, promptText, game);
|
||||||
|
|
Loading…
Reference in a new issue