mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 03:08:02 +00:00
Added support for AI vs AI matches
This commit is contained in:
@@ -840,9 +840,11 @@ public class GameAction {
|
||||
}
|
||||
|
||||
// ai's cannot finish their game without human yet - so terminate a game if human has left.
|
||||
/*
|
||||
if (reason == null && !Iterables.any(game.getPlayers(), Predicates.and(Player.Predicates.NOT_LOST, Player.Predicates.isType(PlayerType.HUMAN)))) {
|
||||
reason = GameEndReason.AllHumansLost;
|
||||
}
|
||||
*/
|
||||
return reason;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,8 @@ public final class GameOutcome implements Iterable<Entry<LobbyPlayer, PlayerStat
|
||||
*/
|
||||
public boolean isWinner(final LobbyPlayer who) {
|
||||
PlayerStatistics stats = playerRating.get(who);
|
||||
if ( stats == null )
|
||||
return false;
|
||||
return stats.getOutcome().hasWon();
|
||||
}
|
||||
|
||||
|
||||
@@ -171,8 +171,6 @@ public class MatchController {
|
||||
localHuman = p;
|
||||
break;
|
||||
}
|
||||
if (null == localHuman)
|
||||
throw new IllegalStateException("Cannot start a game without a human yet!");
|
||||
|
||||
FControl.SINGLETON_INSTANCE.setPlayer(localHuman);
|
||||
|
||||
|
||||
@@ -465,6 +465,9 @@ public class AiAttackController {
|
||||
}
|
||||
}
|
||||
|
||||
final boolean LOG_AI_ATTACKS = false;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Getter for the field <code>attackers</code>.
|
||||
@@ -522,7 +525,8 @@ public class AiAttackController {
|
||||
return combat;
|
||||
}
|
||||
if (bAssault) {
|
||||
System.out.println("Assault");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println("Assault");
|
||||
CardLists.sortByPowerDesc(attackersLeft);
|
||||
for (Card attacker : attackersLeft) {
|
||||
if (CombatUtil.canAttack(attacker, defender, combat) && this.isEffectiveAttacker(ai, attacker, combat)) {
|
||||
@@ -556,7 +560,8 @@ public class AiAttackController {
|
||||
}
|
||||
if (exalted) {
|
||||
CardLists.sortByPowerDesc(this.attackers);
|
||||
System.out.println("Exalted");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println("Exalted");
|
||||
this.aiAggression = 6;
|
||||
for (Card attacker : this.attackers) {
|
||||
if (CombatUtil.canAttack(attacker, defender, combat) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
|
||||
@@ -752,13 +757,16 @@ public class AiAttackController {
|
||||
} else {
|
||||
this.aiAggression = 0;
|
||||
} // stay at home to block
|
||||
System.out.println(String.valueOf(this.aiAggression) + " = ai aggression");
|
||||
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(String.valueOf(this.aiAggression) + " = ai aggression");
|
||||
|
||||
// ****************
|
||||
// Evaluation the end
|
||||
// ****************
|
||||
|
||||
System.out.println("Normal attack");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println("Normal attack");
|
||||
|
||||
attackersLeft = this.notNeededAsBlockers(ai, attackersLeft);
|
||||
attackersLeft = this.sortAttackers(attackersLeft);
|
||||
@@ -858,6 +866,7 @@ public class AiAttackController {
|
||||
boolean isWorthLessThanAllKillers = true;
|
||||
boolean canBeBlocked = false;
|
||||
int numberOfPossibleBlockers = 0;
|
||||
|
||||
|
||||
if (!this.isEffectiveAttacker(ai, attacker, combat)) {
|
||||
return false;
|
||||
@@ -921,8 +930,8 @@ public class AiAttackController {
|
||||
// if the creature cannot block and can kill all opponents they might as
|
||||
// well attack, they do nothing staying back
|
||||
if (canKillAll && isWorthLessThanAllKillers && !CombatUtil.canBlock(attacker)) {
|
||||
System.out.println(attacker.getName()
|
||||
+ " = attacking because they can't block, expecting to kill or damage player");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = attacking because they can't block, expecting to kill or damage player");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -938,16 +947,19 @@ public class AiAttackController {
|
||||
switch (this.aiAggression) {
|
||||
case 6: // Exalted: expecting to at least kill a creature of equal value or not be blocked
|
||||
if ((canKillAll && isWorthLessThanAllKillers) || !canBeBlocked) {
|
||||
System.out.println(attacker.getName() + " = attacking expecting to kill creature, or is unblockable");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = attacking expecting to kill creature, or is unblockable");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 5: // all out attacking
|
||||
System.out.println(attacker.getName() + " = all out attacking");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = all out attacking");
|
||||
return true;
|
||||
case 4: // expecting to at least trade with something
|
||||
if (canKillAll || (canKillAllDangerous && !canBeKilledByOne) || !canBeBlocked) {
|
||||
System.out.println(attacker.getName() + " = attacking expecting to at least trade with something");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = attacking expecting to at least trade with something");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -956,21 +968,23 @@ public class AiAttackController {
|
||||
if ((canKillAll && isWorthLessThanAllKillers)
|
||||
|| ((canKillAllDangerous || hasAttackEffect || hasCombatEffect) && !canBeKilledByOne)
|
||||
|| !canBeBlocked) {
|
||||
System.out.println(attacker.getName()
|
||||
+ " = attacking expecting to kill creature or cause damage, or is unblockable");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = attacking expecting to kill creature or cause damage, or is unblockable");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 2: // attack expecting to attract a group block or destroying a
|
||||
// single blocker and surviving
|
||||
if (((canKillAll || hasAttackEffect || hasCombatEffect) && !canBeKilledByOne) || !canBeBlocked) {
|
||||
System.out.println(attacker.getName() + " = attacking expecting to survive or attract group block");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = attacking expecting to survive or attract group block");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 1: // unblockable creatures only
|
||||
if (!canBeBlocked || (numberOfPossibleBlockers == 1 && canKillAll && !canBeKilledByOne)) {
|
||||
System.out.println(attacker.getName() + " = attacking expecting not to be blocked");
|
||||
if ( LOG_AI_ATTACKS )
|
||||
System.out.println(attacker.getName() + " = attacking expecting not to be blocked");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -13,6 +13,7 @@ import forge.game.GameType;
|
||||
import forge.game.MatchController;
|
||||
import forge.game.MatchStartHelper;
|
||||
import forge.game.PlayerStartConditions;
|
||||
import forge.game.player.LobbyPlayer;
|
||||
import forge.gui.SOverlayUtils;
|
||||
import forge.gui.framework.ICDoc;
|
||||
import forge.properties.ForgePreferences;
|
||||
@@ -96,14 +97,14 @@ public enum CSubmenuConstructed implements ICDoc {
|
||||
* @param gameType
|
||||
*/
|
||||
private void startGame(final GameType gameType) {
|
||||
PlayerStartConditions humanPsc = VSubmenuConstructed.SINGLETON_INSTANCE.getDcHuman().getDeck();
|
||||
PlayerStartConditions humanPsc = view.getDcHuman().getDeck();
|
||||
String humanDeckErrorMessage = gameType.getDecksFormat().getDeckConformanceProblem(humanPsc.getOriginalDeck());
|
||||
if (null != humanDeckErrorMessage) {
|
||||
JOptionPane.showMessageDialog(null, "Your deck " + humanDeckErrorMessage, "Invalid deck", JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerStartConditions aiDeck = VSubmenuConstructed.SINGLETON_INSTANCE.getDcAi().getDeck();
|
||||
PlayerStartConditions aiDeck = view.getDcAi().getDeck();
|
||||
String aiDeckErrorMessage = gameType.getDecksFormat().getDeckConformanceProblem(aiDeck.getOriginalDeck());
|
||||
if (null != aiDeckErrorMessage) {
|
||||
JOptionPane.showMessageDialog(null, "AI deck " + aiDeckErrorMessage, "Invalid deck", JOptionPane.ERROR_MESSAGE);
|
||||
@@ -115,7 +116,8 @@ public enum CSubmenuConstructed implements ICDoc {
|
||||
|
||||
final MatchStartHelper starter = new MatchStartHelper();
|
||||
Lobby lobby = Singletons.getControl().getLobby();
|
||||
starter.addPlayer(lobby.getGuiPlayer(), humanPsc);
|
||||
LobbyPlayer firstPlayer = view.getCbSpectate().isSelected() ? lobby.getAiPlayer() : lobby.getGuiPlayer();
|
||||
starter.addPlayer(firstPlayer, humanPsc);
|
||||
starter.addPlayer(lobby.getAiPlayer(), aiDeck);
|
||||
final MatchController mc = new MatchController(gameType, starter.getPlayerMap());
|
||||
|
||||
|
||||
@@ -35,13 +35,14 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
|
||||
/** */
|
||||
private final LblHeader lblTitle = new LblHeader("Sanctioned Format: Constructed");
|
||||
|
||||
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 2"));
|
||||
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 3"));
|
||||
|
||||
private final StartButton btnStart = new StartButton();
|
||||
|
||||
private final JCheckBox cbSingletons = new FCheckBox("Singleton Mode");
|
||||
private final JCheckBox cbArtifacts = new FCheckBox("Remove Artifacts");
|
||||
private final JCheckBox cbRemoveSmall = new FCheckBox("Remove Small Creatures");
|
||||
private final JCheckBox cbAiVsAi = new FCheckBox("Spectate AI vs AI match");
|
||||
|
||||
private final FDeckChooser dcHuman = new FDeckChooser("Select your deck:", PlayerType.HUMAN);
|
||||
private final FDeckChooser dcAi = new FDeckChooser("Select AI deck:", PlayerType.COMPUTER);
|
||||
@@ -51,12 +52,15 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
|
||||
lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
|
||||
|
||||
|
||||
final String strCheckboxConstraints = "h 30px!, gap 0 20px 0 0";
|
||||
final String strCheckboxConstraints = "pushy, gap 0 20px 0 0";
|
||||
final String strCheckboxConstraintsTop = "pushy, gap 0 20px 20px 0";
|
||||
pnlStart.setOpaque(false);
|
||||
pnlStart.add(cbSingletons, strCheckboxConstraints);
|
||||
pnlStart.add(btnStart, "span 1 3, growx, pushx, align center");
|
||||
pnlStart.add(cbSingletons, strCheckboxConstraintsTop);
|
||||
pnlStart.add(cbAiVsAi, strCheckboxConstraintsTop);
|
||||
pnlStart.add(btnStart, "span 1 2, growx, pushx, align center");
|
||||
pnlStart.add(cbArtifacts, strCheckboxConstraints);
|
||||
pnlStart.add(cbRemoveSmall, strCheckboxConstraints);
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -106,7 +110,7 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
|
||||
dcHuman.populate();
|
||||
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(dcAi, "w 44%!, gap 0 0 20px 20px, growy, pushy");
|
||||
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(dcHuman, "w 44%!, gap 4% 4% 20px 20px, growy, pushy");
|
||||
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(pnlStart, "span 2, gap 0 0 3.5%! 3.5%!, ax center");
|
||||
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(pnlStart, "span 2, gap 0 0 2.5%! 3.5%!, ax center");
|
||||
|
||||
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().revalidate();
|
||||
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().repaintSelf();
|
||||
@@ -134,6 +138,11 @@ public enum VSubmenuConstructed implements IVSubmenu<CSubmenuConstructed> {
|
||||
return cbRemoveSmall;
|
||||
}
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public JCheckBox getCbSpectate() {
|
||||
return cbAiVsAi;
|
||||
}
|
||||
|
||||
//========== Overridden from IVDoc
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
||||
@@ -18,11 +18,15 @@
|
||||
package forge.gui.match;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.Card;
|
||||
import forge.FThreads;
|
||||
import forge.GameEntity;
|
||||
@@ -86,29 +90,35 @@ public enum CMatchUI {
|
||||
// Instantiate all required field slots (user at 0) <-- that's not guaranteed
|
||||
final List<VField> fields = new ArrayList<VField>();
|
||||
final List<VCommand> commands = new ArrayList<VCommand>();
|
||||
|
||||
VField humanField = new VField(EDocID.valueOf("FIELD_0"), localPlayer, localPlayer);
|
||||
VCommand humanCommand = new VCommand(EDocID.COMMAND_0, localPlayer);
|
||||
fields.add(0, humanField);
|
||||
commands.add(0, humanCommand);
|
||||
setAvatar(humanField, new ImageIcon(FSkin.getAvatars().get(Integer.parseInt(indices[0]))));
|
||||
humanField.getLayoutControl().initialize();
|
||||
humanCommand.getLayoutControl().initialize();
|
||||
|
||||
int i = 1;
|
||||
for (Player p : players) {
|
||||
if (p.equals(localPlayer)) {
|
||||
continue;
|
||||
|
||||
List<Player> sortedPlayers = Lists.newArrayList(players);
|
||||
|
||||
int ixLocal = -1;
|
||||
for(int i = 0; i < players.size(); i++) {
|
||||
if( sortedPlayers.get(i) == localPlayer ) {
|
||||
ixLocal = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( ixLocal > 0 ) {
|
||||
Player p0 = sortedPlayers.remove(ixLocal);
|
||||
sortedPlayers.add(0, p0);
|
||||
}
|
||||
|
||||
|
||||
int i = 0;
|
||||
for (Player p : sortedPlayers) {
|
||||
// A field must be initialized after it's instantiated, to update player info.
|
||||
// No player, no init.
|
||||
VField f = new VField(EDocID.valueOf("FIELD_" + i), p, localPlayer);
|
||||
setAvatar(f, getPlayerAvatar(p, Integer.parseInt(indices[1])));
|
||||
f.getLayoutControl().initialize();
|
||||
fields.add(f);
|
||||
VCommand c = new VCommand(EDocID.valueOf("COMMAND_" + i), p);
|
||||
c.getLayoutControl().initialize();
|
||||
fields.add(f);
|
||||
commands.add(c);
|
||||
|
||||
//setAvatar(f, new ImageIcon(FSkin.getAvatars().get()));
|
||||
setAvatar(f, getPlayerAvatar(p, Integer.parseInt(indices[i > 2 ? 1 : 0])));
|
||||
f.getLayoutControl().initialize();
|
||||
c.getLayoutControl().initialize();
|
||||
i++;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ public class CHand implements ICDoc {
|
||||
if (initializedAlready) { return; }
|
||||
initializedAlready = true;
|
||||
|
||||
player.getZone(ZoneType.Hand).addObserver(o1);
|
||||
if ( player != null)
|
||||
player.getZone(ZoneType.Hand).addObserver(o1);
|
||||
|
||||
view.getHandArea().addMouseListener(madCardClick);
|
||||
}
|
||||
|
||||
@@ -58,8 +58,7 @@ public class VHand implements IVDoc<CHand> {
|
||||
|
||||
if (player0 == null) {
|
||||
tab.setText("NO PLAYER Hand");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
tab.setText(player0.getName() + " Hand");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user