mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Huge update to the GUI codebase.
- Make match screen in gui-desktop non-singleton, allowing multiple games to be played simultaneously. - Separate global gui commands (IGuiBase) from game-specific gui commands (IGuiGame), allowing games to send their commands to the correct gui.
This commit is contained in:
@@ -18,7 +18,6 @@ import forge.game.Game;
|
||||
import forge.game.GameType;
|
||||
import forge.game.player.Player;
|
||||
import forge.interfaces.IComboBox;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgeConstants;
|
||||
@@ -35,9 +34,9 @@ public abstract class AchievementCollection implements Iterable<Achievement> {
|
||||
FileUtil.ensureDirectoryExists(ForgeConstants.ACHIEVEMENTS_DIR);
|
||||
}
|
||||
|
||||
public static void updateAll(PlayerControllerHuman controller) {
|
||||
//don't update achievements if player cheated during game or if it's not just a single human player
|
||||
if (controller.hasCheated() || MatchUtil.getHumanCount() != 1) {
|
||||
public static void updateAll(final PlayerControllerHuman controller) {
|
||||
//don't update achievements if player cheated during game
|
||||
if (controller.hasCheated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
@@ -17,7 +17,6 @@ import forge.game.card.CounterType;
|
||||
import forge.item.InventoryItemFromSet;
|
||||
import forge.item.PreconDeck;
|
||||
import forge.item.SealedProduct;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.util.Lang;
|
||||
|
||||
public class CardDetailUtil {
|
||||
@@ -477,8 +476,10 @@ public class CardDetailUtil {
|
||||
}
|
||||
|
||||
//show current storm count for storm cards
|
||||
// TODO add Storm
|
||||
/*
|
||||
if (state.hasStorm()) {
|
||||
GameView gameView = MatchUtil.getGameView();
|
||||
GameView gameView = HostedMatch.getGameView();
|
||||
if (gameView != null) {
|
||||
if (area.length() != 0) {
|
||||
area.append("\n\n");
|
||||
@@ -486,6 +487,7 @@ public class CardDetailUtil {
|
||||
area.append("Current Storm Count: " + gameView.getStormCount());
|
||||
}
|
||||
}
|
||||
*/
|
||||
return area.toString();
|
||||
}
|
||||
}
|
||||
|
||||
522
forge-gui/src/main/java/forge/card/CardScriptParser.java
Normal file
522
forge-gui/src/main/java/forge/card/CardScriptParser.java
Normal file
@@ -0,0 +1,522 @@
|
||||
package forge.card;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.trigger.TriggerType;
|
||||
|
||||
public final class CardScriptParser {
|
||||
|
||||
private final String script;
|
||||
private final Set<String> sVars = Sets.newTreeSet(), sVarAbilities = Sets.newTreeSet();
|
||||
public CardScriptParser(final String script) {
|
||||
this.script = script;
|
||||
|
||||
final String[] lines = StringUtils.split(script, "\r\n");
|
||||
for (final String line : lines) {
|
||||
if (StringUtils.isEmpty(line)) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("SVar:")) {
|
||||
final String[] sVarParts = StringUtils.split(line, ':');
|
||||
if (sVarParts.length != 3) {
|
||||
continue;
|
||||
}
|
||||
sVars.add(sVarParts[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasErrors() {
|
||||
return !getErrorRegions(true).isEmpty();
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getErrorRegions() {
|
||||
return getErrorRegions(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all erroneous regions of this script.
|
||||
*
|
||||
* @param quick
|
||||
* if {@code true}, stop when the first region is found.
|
||||
* @return a {@link Map} mapping the starting index of each error region to
|
||||
* the length of that region.
|
||||
*/
|
||||
private Map<Integer, Integer> getErrorRegions(final boolean quick) {
|
||||
final Map<Integer, Integer> result = Maps.newTreeMap();
|
||||
|
||||
final String[] lines = StringUtils.split(script, '\n');
|
||||
int index = 0;
|
||||
for (final String line : lines) {
|
||||
final String trimLine = line.trim();
|
||||
if (StringUtils.isEmpty(line)) {
|
||||
continue;
|
||||
}
|
||||
boolean bad = false;
|
||||
if (trimLine.startsWith("Name:") && trimLine.length() > "Name:".length()) {
|
||||
// whatever, nonempty name is always ok!
|
||||
} else if (trimLine.startsWith("ManaCost:")) {
|
||||
if (!isManaCostLegal(trimLine.substring("ManaCost:".length()))) {
|
||||
bad = true;
|
||||
}
|
||||
} else if (trimLine.startsWith("Types:")) {
|
||||
if (!isTypeLegal(trimLine.substring("Types:".length()))) {
|
||||
bad = true;
|
||||
}
|
||||
} else if (trimLine.startsWith("A:")) {
|
||||
result.putAll(getActivatedAbilityErrors(trimLine.substring("A:".length()), index + "A:".length()));
|
||||
} else if (trimLine.startsWith("T:")) {
|
||||
result.putAll(getTriggerErrors(trimLine.substring("T:".length()), index + "T:".length()));
|
||||
} else if (trimLine.startsWith("SVar:")) {
|
||||
final String[] sVarParts = trimLine.split(":", 3);
|
||||
if (sVarParts.length != 3) {
|
||||
bad = true;
|
||||
}
|
||||
if (sVarAbilities.contains(sVarParts[1])) {
|
||||
result.putAll(getSubAbilityErrors(sVarParts[2], index + "SVar:".length() + 1 + sVarParts[1].length() + 1));
|
||||
}
|
||||
}
|
||||
if (bad) {
|
||||
result.put(index, trimLine.length());
|
||||
}
|
||||
index += line.length() + 1;
|
||||
if (quick && !result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isManaCostLegal(final String manaCost) {
|
||||
if (manaCost.equals("no cost")) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.isEmpty(manaCost) || StringUtils.isWhitespace(manaCost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (final String part : StringUtils.split(manaCost, ' ')) {
|
||||
if (StringUtils.isNumeric(part) || part.equals("X")) {
|
||||
continue;
|
||||
}
|
||||
return isManaCostPart(part);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isManaCostPart(final String part) {
|
||||
if (part.length() == 1) {
|
||||
return isManaSymbol(part.charAt(0));
|
||||
} else if (part.length() == 2) {
|
||||
if (!(part.startsWith("P") || part.startsWith("2") || isManaSymbol(part.charAt(0)))) {
|
||||
return false;
|
||||
}
|
||||
if ((!isManaSymbol(part.charAt(1))) || part.charAt(0) == part.charAt(1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean isManaSymbol(final char c) {
|
||||
return c == 'W' || c == 'U' || c == 'B' || c == 'R' || c == 'G';
|
||||
}
|
||||
|
||||
private static boolean isTypeLegal(final String type) {
|
||||
for (final String t : StringUtils.split(type, ' ')) {
|
||||
if (!isSingleTypeLegal(t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private static boolean isSingleTypeLegal(final String type) {
|
||||
return CardType.isACardType(type) || CardType.isASupertype(type) || CardType.isASubType(type);
|
||||
}
|
||||
|
||||
private static List<KeyValuePair> getParams(final String ability, final int offset, final Map<Integer, Integer> errorRegions) {
|
||||
final String[] parts = StringUtils.split(ability, '|');
|
||||
final List<KeyValuePair> params = Lists.newArrayList();
|
||||
int currentIndex = offset;
|
||||
for (final String part : parts) {
|
||||
final String[] subParts = StringUtils.split(part, '$');
|
||||
if (subParts.length > 0) {
|
||||
params.add(new KeyValuePair(subParts[0], subParts.length > 1 ? subParts[1] : "", currentIndex));
|
||||
} else {
|
||||
errorRegions.put(currentIndex, part.length());
|
||||
}
|
||||
currentIndex += part.length() + 1;
|
||||
}
|
||||
|
||||
// Check spacing
|
||||
for (final KeyValuePair param : params) {
|
||||
if (!param.getKey().startsWith(" ") && param.startIndex() != offset) {
|
||||
errorRegions.put(param.startIndex() - 1, 2);
|
||||
}
|
||||
if (!param.getValue().startsWith(" ")) {
|
||||
errorRegions.put(param.startIndexValue() - 1, 2);
|
||||
}
|
||||
if (!param.getValue().endsWith(" ") && param.endIndex() != offset + ability.length()) {
|
||||
errorRegions.put(param.endIndex() - 1, 2);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
private Map<Integer, Integer> getActivatedAbilityErrors(final String ability, final int offset) {
|
||||
return getAbilityErrors(ability, offset, true);
|
||||
}
|
||||
private Map<Integer, Integer> getSubAbilityErrors(final String ability, final int offset) {
|
||||
return getAbilityErrors(ability, offset, false);
|
||||
}
|
||||
private Map<Integer, Integer> getAbilityErrors(final String ability, final int offset, final boolean requireCost) {
|
||||
final Map<Integer, Integer> result = Maps.newTreeMap();
|
||||
final List<KeyValuePair> params = getParams(ability, offset, result);
|
||||
|
||||
// First parameter should be Api declaration
|
||||
if (!isAbilityApiDeclarerLegal(params.get(0).getKey())) {
|
||||
result.put(params.get(0).startIndex(), params.get(0).length());
|
||||
}
|
||||
// If present, second parameter should be cost
|
||||
if (requireCost && !params.get(1).getKey().trim().equals("Cost")) {
|
||||
result.put(params.get(1).startIndex(), params.get(1).length());
|
||||
}
|
||||
|
||||
// Now, check all parameters
|
||||
for (final KeyValuePair param : params) {
|
||||
boolean isBadValue = false;
|
||||
final String trimKey = param.getKey().trim(), trimValue = param.getValue().trim();
|
||||
if (isAbilityApiDeclarerLegal(trimKey)) {
|
||||
if (!isAbilityApiLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("Cost")) {
|
||||
if (!isCostLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("ValidTgts") || trimKey.equals("ValidCards")) {
|
||||
if (!isValidLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("Defined")) {
|
||||
if (!isDefinedLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("TgtPrompt") || trimKey.equals("StackDescription") || trimKey.equals("SpellDescription")) {
|
||||
if (trimValue.isEmpty()) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("SubAbility")) {
|
||||
if (sVars.contains(trimValue)) {
|
||||
sVarAbilities.add(trimValue);
|
||||
} else {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else {
|
||||
result.put(param.startIndex(), param.keyLength());
|
||||
}
|
||||
if (isBadValue) {
|
||||
result.put(param.startIndexValue(), param.valueLength());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<Integer, Integer> getTriggerErrors(final String trigger, final int offset) {
|
||||
final Map<Integer, Integer> result = Maps.newTreeMap();
|
||||
final List<KeyValuePair> params = getParams(trigger, offset, result);
|
||||
|
||||
// Check all parameters
|
||||
for (final KeyValuePair param : params) {
|
||||
boolean isBadValue = false;
|
||||
final String trimKey = param.getKey().trim(), trimValue = param.getValue().trim();
|
||||
if (trimKey.equals("Mode")) {
|
||||
if (!isTriggerApiLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("Cost")) {
|
||||
if (!isCostLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("Execute")) {
|
||||
if (sVars.contains(trimValue)) {
|
||||
sVarAbilities.add(trimValue);
|
||||
} else {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("TriggerDescription")) {
|
||||
if (trimValue.isEmpty()) {
|
||||
//isBadValue = true;
|
||||
}
|
||||
} else if (trimKey.equals("ValidCard")) {
|
||||
if (!isValidLegal(trimValue)) {
|
||||
isBadValue = true;
|
||||
}
|
||||
} else {
|
||||
result.put(param.startIndex(), param.keyLength());
|
||||
}
|
||||
if (isBadValue) {
|
||||
result.put(param.startIndexValue(), param.valueLength());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isCostLegal(final String cost) {
|
||||
return isManaCostLegal(cost.trim()); // TODO include other costs (tap, sacrifice, etc.)
|
||||
}
|
||||
|
||||
private static boolean isAbilityApiDeclarerLegal(final String declarer) {
|
||||
final String tDeclarer = declarer.trim();
|
||||
return tDeclarer.equals("AB") || tDeclarer.equals("DB") || tDeclarer.equals("SP");
|
||||
}
|
||||
private static boolean isAbilityApiLegal(final String api) {
|
||||
try {
|
||||
return ApiType.smartValueOf(api.trim()) != null;
|
||||
} catch (final RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private static boolean isTriggerApiLegal(final String api) {
|
||||
try {
|
||||
return TriggerType.smartValueOf(api.trim()) != null;
|
||||
} catch (final RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Predicate<String> startsWith(final String s) {
|
||||
return new Predicate<String>() {
|
||||
public boolean apply(final String input) {
|
||||
return s.startsWith(input);
|
||||
}};
|
||||
}
|
||||
|
||||
/**
|
||||
* Literal defined strings for cards and spellabilities.
|
||||
*/
|
||||
private static final Set<String> DEFINED_CARDS = ImmutableSortedSet.of(
|
||||
"Self", "OriginalHost", "EffectSource", "Equipped", "Enchanted",
|
||||
"TopOfLibrary", "BottomOfLibrary", "Targeted", "ThisTargetedCard",
|
||||
"ParentTarget", "Remembered", "DirectRemembered",
|
||||
"DelayTriggerRemembered", "FirstRemembered", "Clones", "Imprinted",
|
||||
"ChosenCard", "SacrificedCards", "Sacrificed", "DiscardedCards",
|
||||
"Discarded", "ExiledCards", "Exiled", "TappedCards", "Tapped",
|
||||
"UntappedCards", "Untapped", "Parent", "SourceFirstSpell");
|
||||
/**
|
||||
* Defined starting strings for cards and spellabilities.
|
||||
*/
|
||||
private static final Set<String> DEFINED_CARDS_STARTSWITH = ImmutableSortedSet
|
||||
.of("Triggered", "Replaced", "ThisTurnEntered");
|
||||
/**
|
||||
* Literal defined strings for players.
|
||||
*/
|
||||
private static final Set<String> DEFINED_PLAYERS = ImmutableSortedSet.of(
|
||||
"Targeted", "TargetedPlayer", "ParentTarget", "TargetedController",
|
||||
"TargetedOwner", "TargetedAndYou", "ParentTargetedController",
|
||||
"Remembered", "DelayTriggerRemembered", "RememberedOpponents",
|
||||
"RememberedController", "RememberedOwner", "ImprintedController",
|
||||
"ImprintedOwner", "EnchantedController", "EnchantedOwner",
|
||||
"EnchantedPlayer", "AttackingPlayer", "DefendingPlayer",
|
||||
"ChosenPlayer", "ChosenAndYou", "SourceController", "CardOwner",
|
||||
"ActivePlayer", "You", "Each", "Opponent");
|
||||
/**
|
||||
* Defined starting strings for players.
|
||||
*/
|
||||
private static final Set<String> DEFINED_PLAYERS_STARTSWITH = ImmutableSortedSet
|
||||
.of("Triggered", "OppNonTriggered", "Replaced");
|
||||
|
||||
private static boolean isDefinedLegal(final String defined) {
|
||||
return isDefinedCardOrSaLegal(defined) || isDefinedPlayerLegal(defined);
|
||||
}
|
||||
private static boolean isDefinedCardOrSaLegal(final String defined) {
|
||||
if (defined.startsWith("Valid")) {
|
||||
return isValidLegal(defined.substring("Valid".length()));
|
||||
}
|
||||
if (DEFINED_CARDS.contains(defined)) {
|
||||
return true;
|
||||
}
|
||||
if (Iterables.any(DEFINED_CARDS_STARTSWITH, startsWith(defined))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean isDefinedPlayerLegal(final String defined) {
|
||||
final boolean non = defined.startsWith("Non"), flipped = defined.startsWith("Flipped");
|
||||
if (non || flipped) {
|
||||
String newDefined = null;
|
||||
if (non) {
|
||||
newDefined = defined.substring("Non".length());
|
||||
} else if (flipped) {
|
||||
newDefined = defined.substring("Flipped".length());
|
||||
}
|
||||
return isDefinedPlayerLegal(newDefined);
|
||||
}
|
||||
if (DEFINED_PLAYERS.contains(defined)) {
|
||||
return true;
|
||||
}
|
||||
if (Iterables.any(DEFINED_PLAYERS_STARTSWITH, startsWith(defined))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final Set<String> VALID_INCLUSIVE = ImmutableSortedSet.of(
|
||||
"Spell", "Permanent", "Card");
|
||||
private static boolean isValidLegal(final String valid) {
|
||||
String remaining = valid;
|
||||
if (remaining.charAt(0) == '!') {
|
||||
remaining = valid.substring(1);
|
||||
}
|
||||
final String[] splitDot = remaining.split("\\.");
|
||||
if (!(VALID_INCLUSIVE.contains(splitDot[0]) || isSingleTypeLegal(splitDot[0]))) {
|
||||
return false;
|
||||
}
|
||||
if (splitDot.length < 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String[] splitPlus = StringUtils.split(splitDot[1], '+');
|
||||
for (final String excl : splitPlus) {
|
||||
if (!isValidExclusive(excl)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final Set<String> VALID_EXCLUSIVE = ImmutableSortedSet.of(
|
||||
"sameName", "namedCard", "NamedByRememberedPlayer", "Permanent",
|
||||
"ChosenCard", "nonChosenCard", "White", "Blue", "Black", "Red",
|
||||
"Green", "nonWhite", "nonBlue", "nonBlack", "nonRed", "nonGreen",
|
||||
"Colorless", "nonColorless", "Multicolor", "nonMulticolor",
|
||||
"Monocolor", "nonMonocolor", "ChosenColor", "AllChosenColors",
|
||||
"AnyChosenColor", "DoubleFaced", "Flip", "YouCtrl", "YouDontCtrl",
|
||||
"OppCtrl", "ChosenCtrl", "DefenderCtrl",
|
||||
"DefenderCtrlForRemembered", "DefendingPlayerCtrl",
|
||||
"EnchantedPlayerCtrl", "EnchantedControllerCtrl",
|
||||
"RememberedPlayer", "RememberedPlayerCtrl",
|
||||
"nonRememberedPlayerCtrl", "TargetedPlayerCtrl",
|
||||
"TargetedControllerCtrl", "ActivePlayerCtrl",
|
||||
"NonActivePlayerCtrl", "YouOwn", "YouDontOwn", "OppOwn",
|
||||
"TargetedPlayerOwn", "OwnerDoesntControl", "Other", "Self",
|
||||
"AttachedBy", "Attached", "NameNotEnchantingEnchantedPlayer",
|
||||
"NotAttachedTo", "Enchanted", "CanEnchantRemembered",
|
||||
"CanEnchantSource", "CanBeEnchantedBy", "CanBeEnchantedByTargeted",
|
||||
"CanBeEnchantedByAllRemembered", "EquippedBy",
|
||||
"EquippedByTargeted", "EquippedByEnchanted", "FortifiedBy",
|
||||
"CanBeEquippedBy", "Equipped", "Fortified", "HauntedBy",
|
||||
"notTributed", "madness", "Paired", "NotPaired", "PairedWith",
|
||||
"Above", "DirectlyAbove", "TopGraveyardCreature",
|
||||
"BottomGraveyard", "TopLibrary", "Cloned", "DamagedBy", "Damaged",
|
||||
"IsTargetingSource", "sharesPermanentTypeWith",
|
||||
"canProduceSameManaTypeWith", "SecondSpellCastThisTurn",
|
||||
"ThisTurnCast", "withFlashback", "tapped", "untapped", "faceDown",
|
||||
"faceUp", "hasLevelUp", "DrawnThisTurn",
|
||||
"enteredBattlefieldThisTurn", "notEnteredBattlefieldThisTurn",
|
||||
"firstTurnControlled", "notFirstTurnControlled",
|
||||
"startedTheTurnUntapped", "attackedOrBlockedSinceYourLastUpkeep",
|
||||
"blockedOrBeenBlockedSinceYourLastUpkeep",
|
||||
"dealtDamageToYouThisTurn", "dealtDamageToOppThisTurn",
|
||||
"controllerWasDealtCombatDamageByThisTurn",
|
||||
"controllerWasDealtDamageByThisTurn", "wasDealtDamageThisTurn",
|
||||
"wasDealtDamageByHostThisTurn", "wasDealtDamageByEquipeeThisTurn",
|
||||
"wasDealtDamageByEnchantedThisTurn", "dealtDamageThisTurn",
|
||||
"attackedThisTurn", "attackedLastTurn", "blockedThisTurn",
|
||||
"gotBlockedThisTurn", "notAttackedThisTurn", "notAttackedLastTurn",
|
||||
"notBlockedThisTurn", "greatestPower", "yardGreatestPower",
|
||||
"leastPower", "leastToughness", "greatestCMC",
|
||||
"greatestRememberedCMC", "lowestRememberedCMC", "lowestCMC",
|
||||
"enchanted", "unenchanted", "enchanting", "equipped", "unequipped",
|
||||
"equipping", "token", "nonToken", "hasXCost", "suspended",
|
||||
"delved", "attacking", "attackingYou", "notattacking",
|
||||
"attackedBySourceThisCombat", "blocking", "blockingSource",
|
||||
"blockingCreatureYouCtrl", "blockingRemembered",
|
||||
"sharesBlockingAssignmentWith", "notblocking", "blocked",
|
||||
"blockedBySource", "blockedThisTurn", "blockedByThisTurn",
|
||||
"blockedBySourceThisTurn", "blockedSource",
|
||||
"isBlockedByRemembered", "blockedRemembered",
|
||||
"blockedByRemembered", "unblocked", "attackersBandedWith",
|
||||
"kicked", "kicked1", "kicked2", "notkicked", "evoked",
|
||||
"HasDevoured", "HasNotDevoured", "IsMonstrous", "IsNotMonstrous",
|
||||
"CostsPhyrexianMana", "IsRemembered", "IsNotRemembered",
|
||||
"IsImprinted", "IsNotImprinted", "hasActivatedAbilityWithTapCost",
|
||||
"hasActivatedAbility", "hasManaAbility",
|
||||
"hasNonManaActivatedAbility", "NoAbilities", "HasCounters",
|
||||
"wasNotCast", "ChosenType", "IsNotChosenType", "IsCommander");
|
||||
private static final Set<String> VALID_EXCLUSIVE_STARTSWITH = ImmutableSortedSet
|
||||
.of("named", "notnamed", "OwnedBy", "ControlledBy",
|
||||
"ControllerControls", "AttachedTo", "EnchantedBy",
|
||||
"NotEnchantedBy", "TopGraveyard", "SharesColorWith",
|
||||
"MostProminentColor", "notSharesColorWith",
|
||||
"sharesCreatureTypeWith", "sharesCardTypeWith",
|
||||
"sharesNameWith", "doesNotShareNameWith",
|
||||
"sharesControllerWith", "sharesOwnerWith",
|
||||
"ThisTurnEntered", "ControlledByPlayerInTheDirection",
|
||||
"sharesTypeWith", "hasKeyword", "with",
|
||||
"greatestPowerControlledBy", "greatestCMCControlledBy",
|
||||
"power", "toughness", "cmc", "totalPT", "counters", "non",
|
||||
"RememberMap", "wasCastFrom", "wasNotCastFrom", "set",
|
||||
"inZone", "HasSVar");
|
||||
|
||||
private static boolean isValidExclusive(final String valid) {
|
||||
if (VALID_EXCLUSIVE.contains(valid)) {
|
||||
return true;
|
||||
}
|
||||
if (Iterables.any(VALID_EXCLUSIVE_STARTSWITH, startsWith(valid))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final class KeyValuePair {
|
||||
private final String key, value;
|
||||
private final int index;
|
||||
|
||||
private KeyValuePair(final String key, final String value, final int index) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
private String getKey() {
|
||||
return key;
|
||||
}
|
||||
private String getValue() {
|
||||
return value;
|
||||
}
|
||||
private int length() {
|
||||
return keyLength() + 1 + valueLength();
|
||||
}
|
||||
private int keyLength() {
|
||||
return key.length();
|
||||
}
|
||||
private int valueLength() {
|
||||
return value.length();
|
||||
}
|
||||
private int startIndex() {
|
||||
return index;
|
||||
}
|
||||
private int endIndexKey() {
|
||||
return startIndex() + key.length();
|
||||
}
|
||||
private int startIndexValue() {
|
||||
return endIndexKey() + 1;
|
||||
}
|
||||
private int endIndex() {
|
||||
return startIndex() + length();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
@@ -50,24 +51,21 @@ import forge.game.player.PlayerView;
|
||||
import forge.game.zone.PlayerZone;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.IMatchController;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.input.ButtonUtil;
|
||||
import forge.match.input.InputBase;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.model.FModel;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.Lang;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
private final PlayerControllerHuman humanController;
|
||||
private final HashSet<CardView> cardsUpdate = new HashSet<CardView>();
|
||||
private final HashSet<CardView> cardsRefreshDetails = new HashSet<CardView>();
|
||||
private final HashSet<PlayerView> livesUpdate = new HashSet<PlayerView>();
|
||||
private final HashSet<PlayerView> manaPoolUpdate = new HashSet<PlayerView>();
|
||||
private final ArrayList<Pair<PlayerView, ZoneType>> zonesUpdate = new ArrayList<Pair<PlayerView, ZoneType>>();
|
||||
private final IGuiGame matchController;
|
||||
private final Set<CardView> cardsUpdate = new HashSet<CardView>();
|
||||
private final Set<CardView> cardsRefreshDetails = new HashSet<CardView>();
|
||||
private final Set<PlayerView> livesUpdate = new HashSet<PlayerView>();
|
||||
private final Set<PlayerView> manaPoolUpdate = new HashSet<PlayerView>();
|
||||
private final List<Pair<PlayerView, ZoneType>> zonesUpdate = new ArrayList<Pair<PlayerView, ZoneType>>();
|
||||
|
||||
private boolean processEventsQueued, needPhaseUpdate, needCombatUpdate, needStackUpdate, needPlayerControlUpdate;
|
||||
private boolean gameOver, gameFinished;
|
||||
@@ -75,6 +73,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
public FControlGameEventHandler(final PlayerControllerHuman humanController0) {
|
||||
humanController = humanController0;
|
||||
matchController = humanController.getGui();
|
||||
}
|
||||
|
||||
private final Runnable processEvents = new Runnable() {
|
||||
@@ -82,68 +81,69 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
public void run() {
|
||||
processEventsQueued = false;
|
||||
|
||||
IMatchController controller = MatchUtil.getController();
|
||||
synchronized (cardsUpdate) {
|
||||
if (!cardsUpdate.isEmpty()) {
|
||||
MatchUtil.updateCards(cardsUpdate);
|
||||
for (final CardView c : cardsUpdate) {
|
||||
matchController.updateSingleCard(c);
|
||||
}
|
||||
cardsUpdate.clear();
|
||||
}
|
||||
}
|
||||
synchronized (cardsRefreshDetails) {
|
||||
if (!cardsRefreshDetails.isEmpty()) {
|
||||
controller.refreshCardDetails(cardsRefreshDetails);
|
||||
matchController.updateCards(cardsRefreshDetails);
|
||||
cardsRefreshDetails.clear();
|
||||
}
|
||||
}
|
||||
synchronized (livesUpdate) {
|
||||
if (!livesUpdate.isEmpty()) {
|
||||
controller.updateLives(livesUpdate);
|
||||
matchController.updateLives(livesUpdate);
|
||||
livesUpdate.clear();
|
||||
}
|
||||
}
|
||||
synchronized (manaPoolUpdate) {
|
||||
if (!manaPoolUpdate.isEmpty()) {
|
||||
controller.updateManaPool(manaPoolUpdate);
|
||||
matchController.updateManaPool(manaPoolUpdate);
|
||||
manaPoolUpdate.clear();
|
||||
}
|
||||
}
|
||||
if (turnUpdate != null) {
|
||||
controller.updateTurn(turnUpdate);
|
||||
matchController.updateTurn(turnUpdate);
|
||||
turnUpdate = null;
|
||||
}
|
||||
if (needPhaseUpdate) {
|
||||
needPhaseUpdate = false;
|
||||
controller.updatePhase();
|
||||
matchController.updatePhase();
|
||||
}
|
||||
if (needCombatUpdate) {
|
||||
needCombatUpdate = false;
|
||||
controller.showCombat();
|
||||
matchController.showCombat();
|
||||
}
|
||||
if (needStackUpdate) {
|
||||
needStackUpdate = false;
|
||||
controller.updateStack();
|
||||
matchController.updateStack();
|
||||
}
|
||||
if (needPlayerControlUpdate) {
|
||||
needPlayerControlUpdate = false;
|
||||
controller.updatePlayerControl();
|
||||
matchController.updatePlayerControl();
|
||||
}
|
||||
synchronized (zonesUpdate) {
|
||||
if (!zonesUpdate.isEmpty()) {
|
||||
controller.updateZones(zonesUpdate);
|
||||
matchController.updateZones(zonesUpdate);
|
||||
zonesUpdate.clear();
|
||||
}
|
||||
}
|
||||
if (gameOver) {
|
||||
gameOver = false;
|
||||
MatchUtil.onGameOver(true); // this will unlock any game threads waiting for inputs to complete
|
||||
humanController.getInputQueue().onGameOver(true); // this will unlock any game threads waiting for inputs to complete
|
||||
}
|
||||
if (gameFinished) {
|
||||
gameFinished = false;
|
||||
PlayerView localPlayer = humanController.getLocalPlayerView();
|
||||
InputBase.cancelAwaitNextInput(); //ensure "Waiting for opponent..." doesn't appear behind WinLo
|
||||
controller.showPromptMessage(localPlayer, ""); //clear prompt behind WinLose overlay
|
||||
ButtonUtil.update(localPlayer, "", "", false, false, false);
|
||||
controller.finishGame();
|
||||
final PlayerView localPlayer = humanController.getLocalPlayerView();
|
||||
humanController.cancelAwaitNextInput(); //ensure "Waiting for opponent..." doesn't appear behind WinLo
|
||||
matchController.showPromptMessage(localPlayer, ""); //clear prompt behind WinLose overlay
|
||||
matchController.updateButtons(localPlayer, "", "", false, false, false);
|
||||
matchController.finishGame();
|
||||
humanController.updateAchievements();
|
||||
}
|
||||
}
|
||||
@@ -161,13 +161,13 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Void processCard(Card card, HashSet<CardView> list) {
|
||||
private Void processCard(Card card, Set<CardView> list) {
|
||||
synchronized (list) {
|
||||
list.add(card.getView());
|
||||
}
|
||||
return processEvent();
|
||||
}
|
||||
private Void processCards(Collection<Card> cards, HashSet<CardView> list) {
|
||||
private Void processCards(Collection<Card> cards, Set<CardView> list) {
|
||||
if (cards.isEmpty()) { return null; }
|
||||
|
||||
synchronized (list) {
|
||||
@@ -177,7 +177,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
}
|
||||
return processEvent();
|
||||
}
|
||||
private Void processPlayer(Player player, HashSet<PlayerView> list) {
|
||||
private Void processPlayer(Player player, Set<PlayerView> list) {
|
||||
synchronized (list) {
|
||||
list.add(player.getView());
|
||||
}
|
||||
@@ -233,7 +233,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
|
||||
options.add(fakeCard);
|
||||
options.add(kv.getValue().getView());
|
||||
}
|
||||
SGuiChoose.reveal("These cards were chosen to ante", options);
|
||||
humanController.getGui().reveal("These cards were chosen to ante", options);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.event.GameEvent;
|
||||
@@ -20,8 +19,6 @@ import forge.game.event.GameEventSpellAbilityCast;
|
||||
import forge.game.event.GameEventSpellResolved;
|
||||
import forge.game.event.GameEventTurnPhase;
|
||||
import forge.game.event.IGameEventVisitor;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.input.InputPlaybackControl;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
|
||||
@@ -33,7 +30,15 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
private final PlayerControllerHuman humanController;
|
||||
public FControlGamePlayback(final PlayerControllerHuman humanController0) {
|
||||
humanController = humanController0;
|
||||
this.humanController = humanController0;
|
||||
}
|
||||
|
||||
public final PlayerControllerHuman getController() {
|
||||
return humanController;
|
||||
}
|
||||
|
||||
public InputPlaybackControl getInput() {
|
||||
return inputPlayback;
|
||||
}
|
||||
|
||||
private Game game;
|
||||
@@ -42,7 +47,7 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
return game;
|
||||
}
|
||||
|
||||
public void setGame(Game game0) {
|
||||
public void setGame(final Game game0) {
|
||||
game = game0;
|
||||
inputPlayback = new InputPlaybackControl(game, this);
|
||||
}
|
||||
@@ -57,17 +62,17 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
private boolean fasterPlayback = false;
|
||||
|
||||
private void pauseForEvent(int delay) {
|
||||
private void pauseForEvent(final int delay) {
|
||||
try {
|
||||
Thread.sleep(fasterPlayback ? delay / 10 : delay);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
} catch (final InterruptedException e) {
|
||||
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventBlockersDeclared event) {
|
||||
public Void visit(final GameEventBlockersDeclared event) {
|
||||
pauseForEvent(combatDelay);
|
||||
return super.visit(event);
|
||||
}
|
||||
@@ -76,8 +81,9 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventTurnPhase)
|
||||
*/
|
||||
@Override
|
||||
public Void visit(GameEventTurnPhase ev) {
|
||||
boolean isUiToStop = MatchUtil.getController().stopAtPhase(PlayerView.get(ev.playerTurn), ev.phase);
|
||||
public Void visit(final GameEventTurnPhase ev) {
|
||||
try {
|
||||
final boolean isUiToStop = !humanController.getGui().isUiSetToSkipPhase(ev.playerTurn.getView(), ev.phase);
|
||||
|
||||
switch(ev.phase) {
|
||||
case COMBAT_END:
|
||||
@@ -93,6 +99,9 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -101,19 +110,19 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventDuelFinished)
|
||||
*/
|
||||
@Override
|
||||
public Void visit(GameEventGameFinished event) {
|
||||
public Void visit(final GameEventGameFinished event) {
|
||||
humanController.getInputQueue().removeInput(inputPlayback);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventGameStarted event) {
|
||||
public Void visit(final GameEventGameStarted event) {
|
||||
humanController.getInputQueue().setInput(inputPlayback);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(GameEventLandPlayed event) {
|
||||
public Void visit(final GameEventLandPlayed event) {
|
||||
pauseForEvent(resolveDelay);
|
||||
return super.visit(event);
|
||||
}
|
||||
@@ -123,7 +132,7 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GuiBase.getInterface().setCard(CardView.get(event.spell.getHostCard()));
|
||||
humanController.getGui().setCard(CardView.get(event.spell.getHostCard()));
|
||||
}
|
||||
});
|
||||
pauseForEvent(resolveDelay);
|
||||
@@ -138,7 +147,7 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GuiBase.getInterface().setCard(CardView.get(event.sa.getHostCard()));
|
||||
humanController.getGui().setCard(CardView.get(event.sa.getHostCard()));
|
||||
}
|
||||
});
|
||||
pauseForEvent(castDelay);
|
||||
@@ -149,17 +158,17 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
* @see forge.game.event.IGameEventVisitor.Base#visit(forge.game.event.GameEventPlayerPriority)
|
||||
*/
|
||||
@Override
|
||||
public Void visit(GameEventPlayerPriority event) {
|
||||
public Void visit(final GameEventPlayerPriority event) {
|
||||
inputPlayback.updateTurnMessage();
|
||||
if (paused.get()) {
|
||||
try {
|
||||
gameThreadPauser.await();
|
||||
gameThreadPauser.reset();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
catch (final InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (BrokenBarrierException e) {
|
||||
catch (final BrokenBarrierException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -175,17 +184,16 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
|
||||
private void releaseGameThread() {
|
||||
// just need to run another thread through the barrier... not edt preferrably :)
|
||||
|
||||
getGame().getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
gameThreadPauser.await();
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
} catch (final InterruptedException e) {
|
||||
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
} catch (BrokenBarrierException e) {
|
||||
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
} catch (final BrokenBarrierException e) {
|
||||
// Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -205,11 +213,7 @@ public class FControlGamePlayback extends IGameEventVisitor.Base<Void> {
|
||||
releaseGameThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this method.
|
||||
* @param isFast
|
||||
*/
|
||||
public void setSpeed(boolean isFast) {
|
||||
public void setSpeed(final boolean isFast) {
|
||||
fasterPlayback = isFast;
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,19 @@ import java.util.List;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.input.Input;
|
||||
import forge.match.input.InputPlaybackControl;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
|
||||
public class WatchLocalGame extends PlayerControllerHuman {
|
||||
public WatchLocalGame(Game game0, Player p, LobbyPlayer lp) {
|
||||
super(game0, p, lp);
|
||||
public WatchLocalGame(final Game game0, final LobbyPlayer lp, final IGuiGame gui) {
|
||||
super(game0, null, lp);
|
||||
setGui(gui);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,11 +78,14 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectPlayer(final PlayerView player, final ITriggerEvent triggerEvent) {
|
||||
public void selectPlayer(final PlayerView player,
|
||||
final ITriggerEvent triggerEvent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean selectCard(final CardView card, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
|
||||
public boolean selectCard(final CardView card,
|
||||
final List<CardView> otherCardViewsToSelect,
|
||||
final ITriggerEvent triggerEvent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -93,49 +97,13 @@ public class WatchLocalGame extends PlayerControllerHuman {
|
||||
public void alphaStrike() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> getAutoYields() {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public boolean shouldAutoYield(final String key) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void setShouldAutoYield(final String key, final boolean autoYield) {
|
||||
}
|
||||
@Override
|
||||
public boolean shouldAlwaysAcceptTrigger(final Integer trigger) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean shouldAlwaysDeclineTrigger(final Integer trigger) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean shouldAlwaysAskTrigger(final Integer trigger) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public void setShouldAlwaysAcceptTrigger(final Integer trigger) {
|
||||
}
|
||||
@Override
|
||||
public void setShouldAlwaysDeclineTrigger(final Integer trigger) {
|
||||
}
|
||||
@Override
|
||||
public void setShouldAlwaysAskTrigger(final Integer trigger) {
|
||||
}
|
||||
@Override
|
||||
public void autoPassCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DevModeCheats cheat() {
|
||||
return null;
|
||||
public IDevModeCheats cheat() {
|
||||
return DevModeCheats.NO_CHEAT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ package forge.events;
|
||||
public interface IUiEventVisitor<T> {
|
||||
T visit(UiEventBlockerAssigned event);
|
||||
T visit(UiEventAttackerDeclared event);
|
||||
T visit(UiEventNextGameDecision event);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package forge.events;
|
||||
|
||||
import forge.game.event.Event;
|
||||
|
||||
public abstract class UiEvent {
|
||||
public abstract class UiEvent extends Event {
|
||||
|
||||
public abstract <T> T visit(IUiEventVisitor<T> visitor);
|
||||
}
|
||||
@@ -3,11 +3,10 @@ package forge.events;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
|
||||
|
||||
public class UiEventAttackerDeclared extends UiEvent {
|
||||
public final CardView attacker;
|
||||
public final GameEntityView defender;
|
||||
|
||||
|
||||
public UiEventAttackerDeclared(final CardView card, final GameEntityView currentDefender) {
|
||||
attacker = card;
|
||||
defender = currentDefender;
|
||||
@@ -17,7 +16,7 @@ public class UiEventAttackerDeclared extends UiEvent {
|
||||
public <T> T visit(final IUiEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package forge.events;
|
||||
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
|
||||
public final class UiEventNextGameDecision extends UiEvent {
|
||||
|
||||
private final PlayerControllerHuman controller;
|
||||
private final NextGameDecision decision;
|
||||
|
||||
public UiEventNextGameDecision(final PlayerControllerHuman controller, final NextGameDecision decision) {
|
||||
this.controller = controller;
|
||||
this.decision = decision;
|
||||
}
|
||||
|
||||
public PlayerControllerHuman getController() {
|
||||
return controller;
|
||||
}
|
||||
public NextGameDecision getDecision() {
|
||||
return decision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T visit(IUiEventVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.Deck;
|
||||
@@ -12,13 +13,14 @@ import forge.game.GameView;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IWinLoseView;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
|
||||
public abstract class GauntletWinLoseController {
|
||||
private final GameView lastGame;
|
||||
private HostedMatch hostedMatch = null;
|
||||
private final IWinLoseView<? extends IButton> view;
|
||||
private final GameView lastGame;
|
||||
|
||||
public GauntletWinLoseController(IWinLoseView<? extends IButton> view0, final GameView game0) {
|
||||
view = view0;
|
||||
@@ -111,17 +113,21 @@ public abstract class GauntletWinLoseController {
|
||||
public final boolean actionOnContinue() {
|
||||
if (lastGame.isMatchOver()) {
|
||||
// To change the AI deck, we have to create a new match.
|
||||
GauntletData gd = FModel.getGauntletData();
|
||||
Deck aiDeck = gd.getDecks().get(gd.getCompleted());
|
||||
List<RegisteredPlayer> players = Lists.newArrayList();
|
||||
players.add(new RegisteredPlayer(gd.getUserDeck()).setPlayer(GamePlayerUtil.getGuiPlayer()));
|
||||
final GauntletData gd = FModel.getGauntletData();
|
||||
final RegisteredPlayer human = new RegisteredPlayer(gd.getUserDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
|
||||
final Deck aiDeck = gd.getDecks().get(gd.getCompleted());
|
||||
final List<RegisteredPlayer> players = Lists.newArrayList();
|
||||
players.add(human);
|
||||
players.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
|
||||
|
||||
view.hide();
|
||||
saveOptions();
|
||||
MatchUtil.endCurrentGame();
|
||||
if (hostedMatch != null) {
|
||||
hostedMatch.endCurrentGame();
|
||||
}
|
||||
|
||||
MatchUtil.startMatch(GameType.Gauntlet, players);
|
||||
hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.startMatch(GameType.Gauntlet, null, players, human, GuiBase.getInterface().getNewGuiGame());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
87
forge-gui/src/main/java/forge/interfaces/IDevModeCheats.java
Normal file
87
forge-gui/src/main/java/forge/interfaces/IDevModeCheats.java
Normal file
@@ -0,0 +1,87 @@
|
||||
package forge.interfaces;
|
||||
|
||||
public interface IDevModeCheats {
|
||||
|
||||
void setCanPlayUnlimitedLands(boolean canPlayUnlimitedLands0);
|
||||
|
||||
void setViewAllCards(boolean canViewAll);
|
||||
|
||||
void generateMana();
|
||||
|
||||
void dumpGameState();
|
||||
|
||||
void setupGameState();
|
||||
|
||||
void tutorForCard();
|
||||
|
||||
void addCountersToPermanent();
|
||||
|
||||
void tapPermanents();
|
||||
|
||||
void untapPermanents();
|
||||
|
||||
void setPlayerLife();
|
||||
|
||||
void winGame();
|
||||
|
||||
void addCardToHand();
|
||||
|
||||
void addCardToBattlefield();
|
||||
|
||||
void riggedPlanarRoll();
|
||||
|
||||
void planeswalkTo();
|
||||
|
||||
/**
|
||||
* Implementation of {@link IDevModeCheats} that disallows cheating by
|
||||
* performing no action whatsoever when any of its methods is called.
|
||||
*/
|
||||
public static final IDevModeCheats NO_CHEAT = new IDevModeCheats() {
|
||||
@Override
|
||||
public void winGame() {
|
||||
}
|
||||
@Override
|
||||
public void untapPermanents() {
|
||||
}
|
||||
@Override
|
||||
public void tutorForCard() {
|
||||
}
|
||||
@Override
|
||||
public void tapPermanents() {
|
||||
}
|
||||
@Override
|
||||
public void setupGameState() {
|
||||
}
|
||||
@Override
|
||||
public void setViewAllCards(final boolean canViewAll) {
|
||||
}
|
||||
@Override
|
||||
public void setPlayerLife() {
|
||||
}
|
||||
@Override
|
||||
public void setCanPlayUnlimitedLands(final boolean canPlayUnlimitedLands0) {
|
||||
}
|
||||
@Override
|
||||
public void riggedPlanarRoll() {
|
||||
}
|
||||
@Override
|
||||
public void planeswalkTo() {
|
||||
}
|
||||
@Override
|
||||
public void generateMana() {
|
||||
}
|
||||
@Override
|
||||
public void dumpGameState() {
|
||||
}
|
||||
@Override
|
||||
public void addCountersToPermanent() {
|
||||
}
|
||||
@Override
|
||||
public void addCardToHand() {
|
||||
}
|
||||
@Override
|
||||
public void addCardToBattlefield() {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public interface IGameController {
|
||||
|
||||
boolean mayLookAtAllCards();
|
||||
|
||||
boolean canPlayUnlimitedLands();
|
||||
|
||||
void concede();
|
||||
|
||||
void alphaStrike();
|
||||
|
||||
boolean useMana(byte color);
|
||||
|
||||
void selectButtonOk();
|
||||
|
||||
void selectButtonCancel();
|
||||
|
||||
boolean passPriority();
|
||||
|
||||
boolean passPriorityUntilEndOfTurn();
|
||||
|
||||
void selectPlayer(PlayerView playerView, ITriggerEvent triggerEvent);
|
||||
|
||||
boolean selectCard(CardView cardView,
|
||||
List<CardView> otherCardViewsToSelect, ITriggerEvent triggerEvent);
|
||||
|
||||
void selectAbility(SpellAbility sa);
|
||||
|
||||
boolean tryUndoLastAction();
|
||||
|
||||
IDevModeCheats cheat();
|
||||
|
||||
void nextGameDecision(NextGameDecision decision);
|
||||
|
||||
String getActivateDescription(CardView card);
|
||||
}
|
||||
@@ -1,34 +1,28 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.assets.ISkinImage;
|
||||
import forge.deck.CardPool;
|
||||
import forge.download.GuiDownloadService;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.item.PaperCard;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.sound.IAudioClip;
|
||||
import forge.sound.IAudioMusic;
|
||||
import forge.util.Callback;
|
||||
import forge.util.FCollectionView;
|
||||
|
||||
public interface IGuiBase {
|
||||
boolean isRunningOnDesktop();
|
||||
String getCurrentVersion();
|
||||
String getAssetsDir();
|
||||
void invokeInEdtLater(Runnable runnable);
|
||||
void invokeInEdtAndWait(final Runnable proc);
|
||||
void invokeInEdtAndWait(Runnable proc);
|
||||
boolean isGuiThread();
|
||||
IGuiTimer createGuiTimer(Runnable proc, int interval);
|
||||
ISkinImage getSkinIcon(FSkinProp skinProp);
|
||||
@@ -38,27 +32,23 @@ public interface IGuiBase {
|
||||
void showBugReportDialog(String title, String text, boolean showExitAppBtn);
|
||||
void showImageDialog(ISkinImage image, String message, String title);
|
||||
int showOptionDialog(String message, String title, FSkinProp icon, String[] options, int defaultOption);
|
||||
int showCardOptionDialog(CardView card, String message, String title, FSkinProp icon, String[] options, int defaultOption);
|
||||
String showInputDialog(String message, String title, FSkinProp icon, String initialInput, String[] inputOptions);
|
||||
<T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices, final T selected, final Function<T, String> display);
|
||||
<T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax,
|
||||
final List<T> sourceChoices, final List<T> destChoices, final CardView referenceCard, final boolean sideboardingMode);
|
||||
List<PaperCard> sideboard(CardPool sideboard, CardPool main);
|
||||
GameEntityView chooseSingleEntityForEffect(String title, FCollectionView<? extends GameEntity> optionList, DelayedReveal delayedReveal, boolean isOptional, PlayerControllerHuman controller);
|
||||
<T> List<T> getChoices(String message, int min, int max, Collection<T> choices, T selected, Function<T, String> display);
|
||||
<T> List<T> order(String title, String top, int remainingObjectsMin, int remainingObjectsMax, List<T> sourceChoices, List<T> destChoices);
|
||||
String showFileDialog(String title, String defaultDir);
|
||||
File getSaveFile(File defaultFile);
|
||||
void download(GuiDownloadService service, Callback<Boolean> callback);
|
||||
void showCardList(final String title, final String message, final List<PaperCard> list);
|
||||
boolean showBoxedProduct(final String title, final String message, final List<PaperCard> list);
|
||||
void setCard(CardView card);
|
||||
void showCardList(String title, String message, List<PaperCard> list);
|
||||
boolean showBoxedProduct(String title, String message, List<PaperCard> list);
|
||||
int getAvatarCount();
|
||||
void copyToClipboard(String text);
|
||||
void browseToUrl(String url) throws Exception;
|
||||
void browseToUrl(String url) throws IOException, URISyntaxException;
|
||||
IAudioClip createAudioClip(String filename);
|
||||
IAudioMusic createAudioMusic(String filename);
|
||||
void startAltSoundSystem(String filename, boolean isSynchronized);
|
||||
void clearImageCache();
|
||||
void showSpellShop();
|
||||
void showBazaar();
|
||||
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
||||
IGuiGame getNewGuiGame();
|
||||
HostedMatch hostMatch();
|
||||
}
|
||||
196
forge-gui/src/main/java/forge/interfaces/IGuiGame.java
Normal file
196
forge-gui/src/main/java/forge/interfaces/IGuiGame.java
Normal file
@@ -0,0 +1,196 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.deck.CardPool;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.IHasIcon;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public interface IGuiGame {
|
||||
void setGameView(GameView gameView);
|
||||
void setGameController(PlayerView player, IGameController gameController);
|
||||
boolean resetForNewGame();
|
||||
void openView(FCollectionView<PlayerView> myPlayers);
|
||||
void afterGameEnd();
|
||||
void showCombat();
|
||||
void showPromptMessage(PlayerView playerView, String message);
|
||||
boolean stopAtPhase(PlayerView playerTurn, PhaseType phase);
|
||||
IButton getBtnOK(PlayerView playerView);
|
||||
IButton getBtnCancel(PlayerView playerView);
|
||||
void focusButton(IButton button);
|
||||
void flashIncorrectAction();
|
||||
void updatePhase();
|
||||
void updateTurn(PlayerView player);
|
||||
void updatePlayerControl();
|
||||
void enableOverlay();
|
||||
void disableOverlay();
|
||||
void finishGame();
|
||||
Object showManaPool(PlayerView player);
|
||||
void hideManaPool(PlayerView player, Object zoneToRestore);
|
||||
void updateStack();
|
||||
void updateZones(List<Pair<PlayerView, ZoneType>> zonesToUpdate);
|
||||
void updateSingleCard(CardView card);
|
||||
void updateCards(Iterable<CardView> cards);
|
||||
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
||||
void updateLives(Iterable<PlayerView> livesUpdate);
|
||||
void setPanelSelection(CardView hostCard);
|
||||
void hear(LobbyPlayer player, String message);
|
||||
SpellAbility getAbilityToPlay(List<SpellAbility> abilities,
|
||||
ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignDamage(CardView attacker,
|
||||
List<CardView> blockers, int damage, GameEntityView defender,
|
||||
boolean overrideOrder);
|
||||
|
||||
void message(String message);
|
||||
void message(String message, String title);
|
||||
|
||||
void showErrorDialog(String message);
|
||||
void showErrorDialog(String message, String title);
|
||||
|
||||
boolean showConfirmDialog(String message);
|
||||
boolean showConfirmDialog(String message, String title);
|
||||
boolean showConfirmDialog(String message, String title, boolean defaultYes);
|
||||
boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText);
|
||||
boolean showConfirmDialog(String message, String title, String yesButtonText, String noButtonText, boolean defaultYes);
|
||||
|
||||
int showOptionDialog(String message, String title, FSkinProp icon,
|
||||
String[] options, int defaultOption);
|
||||
int showCardOptionDialog(CardView card, String message, String title,
|
||||
FSkinProp icon, String[] options, int defaultOption);
|
||||
|
||||
String showInputDialog(String message, String title);
|
||||
String showInputDialog(String message, String title, FSkinProp icon);
|
||||
String showInputDialog(String message, String title, FSkinProp icon,
|
||||
String initialInput);
|
||||
String showInputDialog(String message, String title, FSkinProp icon,
|
||||
String initialInput, String[] inputOptions);
|
||||
|
||||
boolean confirm(CardView c, String question);
|
||||
boolean confirm(CardView c, String question, boolean defaultChoice);
|
||||
boolean confirm(CardView c, String question, String[] options);
|
||||
boolean confirm(CardView c, String question, boolean defaultIsYes, String[] options);
|
||||
|
||||
<T> List<T> getChoices(String message, int min, int max, T[] choices);
|
||||
<T> List<T> getChoices(String message, int min, int max,
|
||||
Collection<T> choices);
|
||||
<T> List<T> getChoices(String message, int min, int max,
|
||||
Collection<T> choices, T selected, Function<T, String> display);
|
||||
|
||||
// Get Integer in range
|
||||
Integer getInteger(String message);
|
||||
Integer getInteger(String message, int min);
|
||||
Integer getInteger(String message, int min, int max);
|
||||
Integer getInteger(String message, int min, int max, boolean sortDesc);
|
||||
Integer getInteger(String message, int min, int max, int cutoff);
|
||||
|
||||
/**
|
||||
* Convenience for getChoices(message, 0, 1, choices).
|
||||
*
|
||||
* @param <T>
|
||||
* is automatically inferred.
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @param choices
|
||||
* a T object.
|
||||
* @return null if choices is missing, empty, or if the users' choices are
|
||||
* empty; otherwise, returns the first item in the List returned by
|
||||
* getChoices.
|
||||
* @see #getChoices(String, int, int, Object...)
|
||||
*/
|
||||
<T> T oneOrNone(String message, T[] choices);
|
||||
<T> T oneOrNone(String message, Collection<T> choices);
|
||||
|
||||
// returned Object will never be null
|
||||
/**
|
||||
* <p>
|
||||
* getChoice.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* a T object.
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @param choices
|
||||
* a T object.
|
||||
* @return a T object.
|
||||
*/
|
||||
<T> T one(String message, T[] choices);
|
||||
<T> T one(String message, Collection<T> choices);
|
||||
<T> List<T> noneOrMany(String message, Collection<T> choices);
|
||||
|
||||
<T> void reveal(String message, T item);
|
||||
<T> void reveal(String message, T[] items);
|
||||
<T> void reveal(String message, Collection<T> items);
|
||||
|
||||
<T> List<T> many(String title, String topCaption, int min, int max,
|
||||
List<T> sourceChoices);
|
||||
<T> List<T> many(String title, String topCaption, int cnt,
|
||||
List<T> sourceChoices);
|
||||
<T> List<T> many(String title, String topCaption, int cnt,
|
||||
List<T> sourceChoices, CardView c);
|
||||
<T> List<T> many(String title, String topCaption, int min, int max,
|
||||
List<T> sourceChoices, CardView c);
|
||||
|
||||
<T> List<T> order(String title, String top, List<T> sourceChoices);
|
||||
<T> List<T> order(String title, String top, List<T> sourceChoices, CardView c);
|
||||
<T> List<T> order(String title, String top, int remainingObjectsMin,
|
||||
int remainingObjectsMax, List<T> sourceChoices,
|
||||
List<T> destChoices, CardView referenceCard,
|
||||
boolean sideboardingMode);
|
||||
<T> List<T> insertInList(String title, T newItem, List<T> oldItems);
|
||||
|
||||
List<PaperCard> sideboard(CardPool sideboard, CardPool main);
|
||||
GameEntityView chooseSingleEntityForEffect(String title,
|
||||
FCollectionView<? extends GameEntity> optionList,
|
||||
DelayedReveal delayedReveal, boolean isOptional,
|
||||
PlayerControllerHuman controller);
|
||||
void setCard(CardView card);
|
||||
void setPlayerAvatar(LobbyPlayer player, IHasIcon ihi);
|
||||
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
||||
void restoreOldZones(Map<PlayerView, Object> playersToRestoreZonesFor);
|
||||
void updateButtons(PlayerView owner, boolean okEnabled,
|
||||
boolean cancelEnabled, boolean focusOk);
|
||||
void updateButtons(PlayerView owner, String okLabel, String cancelLabel,
|
||||
boolean okEnabled, boolean cancelEnabled, boolean focusOk);
|
||||
void setHighlighted(PlayerView pv, boolean b);
|
||||
void setUsedToPay(CardView card, boolean value);
|
||||
|
||||
void awaitNextInput();
|
||||
void cancelAwaitNextInput();
|
||||
|
||||
boolean isUiSetToSkipPhase(PlayerView playerTurn, PhaseType phase);
|
||||
void autoPassUntilEndOfTurn(PlayerView player);
|
||||
boolean mayAutoPass(PlayerView player);
|
||||
void autoPassCancel(PlayerView player);
|
||||
void updateAutoPassPrompt();
|
||||
boolean shouldAutoYield(String key);
|
||||
void setShouldAutoYield(String key, boolean autoYield);
|
||||
boolean shouldAlwaysAcceptTrigger(int trigger);
|
||||
boolean shouldAlwaysDeclineTrigger(int trigger);
|
||||
boolean shouldAlwaysAskTrigger(int trigger);
|
||||
void setShouldAlwaysAcceptTrigger(int trigger);
|
||||
void setShouldAlwaysDeclineTrigger(int trigger);
|
||||
void setShouldAlwaysAskTrigger(int trigger);
|
||||
|
||||
void setCurrentPlayer(PlayerView player);
|
||||
}
|
||||
36
forge-gui/src/main/java/forge/interfaces/IMayViewCards.java
Normal file
36
forge-gui/src/main/java/forge/interfaces/IMayViewCards.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
|
||||
/**
|
||||
* Interface that receives requests on whether a {@link Card} can be shown.
|
||||
*/
|
||||
public interface IMayViewCards {
|
||||
|
||||
/**
|
||||
* @param c
|
||||
* a {@link CardView}
|
||||
* @return whether {@code c} can be shown.
|
||||
*/
|
||||
boolean mayView(CardView c);
|
||||
|
||||
/**
|
||||
* @param c
|
||||
* a {@link CardView}
|
||||
* @return whether the flip side of {@code c} can be shown.
|
||||
*/
|
||||
boolean mayFlip(CardView c);
|
||||
|
||||
/** {@link IMayViewCards} that lets you view all cards unconditionally. */
|
||||
public static final IMayViewCards ALL = new IMayViewCards() {
|
||||
@Override
|
||||
public boolean mayView(final CardView c) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayFlip(final CardView c) {
|
||||
return c.hasAlternateState();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -20,10 +20,11 @@ package forge.limited;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.GameType;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.util.Aggregates;
|
||||
@@ -38,6 +39,7 @@ import forge.util.Aggregates;
|
||||
* @since 1.2.xx
|
||||
*/
|
||||
public class GauntletMini {
|
||||
private HostedMatch hostedMatch = null;
|
||||
private int rounds;
|
||||
private Deck humanDeck;
|
||||
private int currentRound;
|
||||
@@ -76,14 +78,17 @@ public class GauntletMini {
|
||||
* Advances the tournament to the next round.
|
||||
*/
|
||||
public void nextRound() {
|
||||
// System.out.println("Moving from round " + currentRound + " to round " + currentRound + 1 + " of " + rounds);
|
||||
if (hostedMatch == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentRound >= rounds) {
|
||||
currentRound = rounds - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
currentRound++;
|
||||
MatchUtil.endCurrentGame();
|
||||
hostedMatch.endCurrentGame();
|
||||
startRound();
|
||||
}
|
||||
|
||||
@@ -129,18 +134,19 @@ public class GauntletMini {
|
||||
}
|
||||
|
||||
resetCurrentRound();
|
||||
startRound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the tournament.
|
||||
*/
|
||||
private void startRound() {
|
||||
List<RegisteredPlayer> starter = new ArrayList<RegisteredPlayer>();
|
||||
starter.add(new RegisteredPlayer(humanDeck).setPlayer(GamePlayerUtil.getGuiPlayer()));
|
||||
final List<RegisteredPlayer> starter = new ArrayList<RegisteredPlayer>();
|
||||
final RegisteredPlayer human = new RegisteredPlayer(humanDeck).setPlayer(GamePlayerUtil.getGuiPlayer());
|
||||
starter.add(human);
|
||||
starter.add(aiOpponents.get(currentRound - 1).setPlayer(GamePlayerUtil.createAiPlayer()));
|
||||
|
||||
MatchUtil.startMatch(gauntletType, starter);
|
||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.startMatch(gauntletType, null, starter, human, GuiBase.getInterface().getNewGuiGame());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
648
forge-gui/src/main/java/forge/match/AbstractGuiGame.java
Normal file
648
forge-gui/src/main/java/forge/match/AbstractGuiGame.java
Normal file
@@ -0,0 +1,648 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.GameView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.interfaces.IMayViewCards;
|
||||
import forge.util.FCollectionView;
|
||||
|
||||
public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
private FCollectionView<PlayerView> localPlayers;
|
||||
private PlayerView currentPlayer = null;
|
||||
|
||||
protected final void setLocalPlayers(final FCollectionView<PlayerView> players) {
|
||||
this.localPlayers = players;
|
||||
}
|
||||
public final boolean hasLocalPlayers() {
|
||||
return localPlayers != null && !localPlayers.isEmpty();
|
||||
}
|
||||
public final FCollectionView<PlayerView> getLocalPlayers() {
|
||||
return localPlayers;
|
||||
}
|
||||
public final int getLocalPlayerCount() {
|
||||
return localPlayers == null ? 0 : localPlayers.size();
|
||||
}
|
||||
public final boolean isLocalPlayer(final PlayerView player) {
|
||||
return hasLocalPlayers() && localPlayers.contains(player);
|
||||
}
|
||||
|
||||
public final PlayerView getCurrentPlayer() {
|
||||
return currentPlayer;
|
||||
}
|
||||
@Override
|
||||
public final void setCurrentPlayer(final PlayerView player) {
|
||||
this.currentPlayer = player;
|
||||
updateCurrentPlayer(player);
|
||||
}
|
||||
protected abstract void updateCurrentPlayer(PlayerView player);
|
||||
|
||||
private GameView gameView = null;
|
||||
public final GameView getGameView() {
|
||||
return gameView;
|
||||
}
|
||||
public void setGameView(final GameView gameView) {
|
||||
this.gameView = gameView;
|
||||
}
|
||||
|
||||
private final Map<PlayerView, IGameController> gameControllers = Maps.newHashMap();
|
||||
public final IGameController getGameController() {
|
||||
return gameControllers.get(currentPlayer);
|
||||
}
|
||||
public final Collection<IGameController> getGameControllers() {
|
||||
return gameControllers.values();
|
||||
}
|
||||
@Override
|
||||
public void setGameController(final PlayerView player, final IGameController gameController) {
|
||||
this.gameControllers.put(player, gameController);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCards(final Iterable<CardView> cards) {
|
||||
for (final CardView card : cards) {
|
||||
updateSingleCard(card);
|
||||
}
|
||||
}
|
||||
|
||||
public String getCardImageKey(final CardStateView csv) {
|
||||
if (getCurrentPlayer() == null) { return csv.getImageKey(null); } //if not in game, card can be shown
|
||||
return csv.getImageKey(getCurrentPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayView(final CardView c) {
|
||||
if (!hasLocalPlayers()) {
|
||||
return true; //if not in game, card can be shown
|
||||
}
|
||||
if (getGameController().mayLookAtAllCards()) {
|
||||
return true;
|
||||
}
|
||||
return Iterables.any(localPlayers, new Predicate<PlayerView>() {
|
||||
@Override public boolean apply(final PlayerView input) { return c.canBeShownTo(input); };
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayFlip(final CardView cv) {
|
||||
if (cv == null) { return false; }
|
||||
|
||||
CardStateView altState = cv.getAlternateState();
|
||||
if (altState == null) { return false; }
|
||||
|
||||
switch (altState.getState()) {
|
||||
case Original:
|
||||
CardStateView currentState = cv.getCurrentState();
|
||||
if (currentState.getState() == CardStateName.FaceDown) {
|
||||
return getCurrentPlayer() == null || cv.canFaceDownBeShownTo(getCurrentPlayer());
|
||||
}
|
||||
return true; //original can always be shown if not a face down that can't be shown
|
||||
case Flipped:
|
||||
case Transformed:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<PlayerView> highlightedPlayers = Sets.newHashSet();
|
||||
@Override
|
||||
public void setHighlighted(final PlayerView pv, final boolean b) {
|
||||
if (b) {
|
||||
highlightedPlayers.add(pv);
|
||||
} else {
|
||||
highlightedPlayers.remove(pv);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHighlighted(PlayerView player) {
|
||||
return highlightedPlayers.contains(player);
|
||||
}
|
||||
|
||||
private Set<CardView> highlightedCards = Sets.newHashSet();
|
||||
// used to highlight cards in UI
|
||||
@Override
|
||||
public void setUsedToPay(CardView card, boolean value) {
|
||||
boolean hasChanged = value ? highlightedCards.add(card) : highlightedCards.remove(card);
|
||||
if (hasChanged) { // since we are in UI thread, may redraw the card right now
|
||||
updateSingleCard(card);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUsedToPay(CardView card) {
|
||||
return highlightedCards.contains(card);
|
||||
}
|
||||
|
||||
/** Concede game, bring up WinLose UI. */
|
||||
public void concede() {
|
||||
final String userPrompt =
|
||||
"This will end the current game and you will not be able to resume.\n\n" +
|
||||
"Concede anyway?";
|
||||
if (hasLocalPlayers() && showConfirmDialog(userPrompt, "Concede Game?", "Concede", "Cancel")) {
|
||||
for (final IGameController c : getGameControllers()) {
|
||||
// Concede each player on this Gui
|
||||
c.concede();
|
||||
}
|
||||
/*
|
||||
if (humanCount == 0) { // no human? then all players surrender!
|
||||
for (Player p : game.getPlayers()) {
|
||||
p.concede();
|
||||
}
|
||||
}
|
||||
else {
|
||||
getCurrentPlayer().concede();
|
||||
}
|
||||
|
||||
Player priorityPlayer = game.getPhaseHandler().getPriorityPlayer();
|
||||
boolean humanHasPriority = priorityPlayer == null || priorityPlayer.getLobbyPlayer() instanceof LobbyPlayerHuman;
|
||||
|
||||
if (humanCount > 0 && humanHasPriority) {
|
||||
game.getAction().checkGameOverCondition();
|
||||
}
|
||||
else {
|
||||
game.isGameOver(); // this is synchronized method - it's used to make Game-0 thread see changes made here
|
||||
onGameOver(false); //release any waiting input, effectively passing priority
|
||||
}
|
||||
|
||||
if (playbackControl != null) {
|
||||
playbackControl.onGameStopRequested();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButtons(final PlayerView owner, final boolean okEnabled, final boolean cancelEnabled, final boolean focusOk) {
|
||||
updateButtons(owner, "OK", "Cancel", okEnabled, cancelEnabled, focusOk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButtons(final PlayerView owner, final String okLabel, final String cancelLabel, final boolean okEnabled, final boolean cancelEnabled, final boolean focusOk) {
|
||||
final IButton btnOk = getBtnOK(owner);
|
||||
final IButton btnCancel = getBtnCancel(owner);
|
||||
|
||||
btnOk.setText(okLabel);
|
||||
btnCancel.setText(cancelLabel);
|
||||
btnOk.setEnabled(okEnabled);
|
||||
btnCancel.setEnabled(cancelEnabled);
|
||||
if (okEnabled && focusOk) {
|
||||
focusButton(btnOk);
|
||||
} else if (cancelEnabled) {
|
||||
focusButton(btnCancel);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-yield and other input-related code
|
||||
|
||||
private final Set<PlayerView> autoPassUntilEndOfTurn = Sets.newHashSet();
|
||||
|
||||
/**
|
||||
* Automatically pass priority until reaching the Cleanup phase of the
|
||||
* current turn.
|
||||
*/
|
||||
@Override
|
||||
public final void autoPassUntilEndOfTurn(final PlayerView player) {
|
||||
autoPassUntilEndOfTurn.add(player);
|
||||
updateAutoPassPrompt();
|
||||
}
|
||||
|
||||
public final void autoPassCancel(final PlayerView player) {
|
||||
if (!autoPassUntilEndOfTurn.remove(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//prevent prompt getting stuck on yielding message while actually waiting for next input opportunity
|
||||
final PlayerView playerView = getCurrentPlayer();
|
||||
showPromptMessage(playerView, "");
|
||||
updateButtons(playerView, false, false, false);
|
||||
awaitNextInput();
|
||||
}
|
||||
|
||||
public final boolean mayAutoPass(final PlayerView player) {
|
||||
return autoPassUntilEndOfTurn.contains(player);
|
||||
}
|
||||
|
||||
private final Timer awaitNextInputTimer = new Timer();
|
||||
private TimerTask awaitNextInputTask;
|
||||
|
||||
@Override
|
||||
public final void awaitNextInput() {
|
||||
//delay updating prompt to await next input briefly so buttons don't flicker disabled then enabled
|
||||
awaitNextInputTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (awaitNextInputTimer) {
|
||||
if (awaitNextInputTask != null) {
|
||||
updatePromptForAwait(getCurrentPlayer());
|
||||
awaitNextInputTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
awaitNextInputTimer.schedule(awaitNextInputTask, 250);
|
||||
}
|
||||
|
||||
protected final void updatePromptForAwait(final PlayerView playerView) {
|
||||
showPromptMessage(playerView, "Waiting for opponent...");
|
||||
updateButtons(playerView, false, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void cancelAwaitNextInput() {
|
||||
synchronized (awaitNextInputTimer) { //ensure task doesn't reset awaitNextInputTask during this block
|
||||
if (awaitNextInputTask != null) {
|
||||
try {
|
||||
awaitNextInputTask.cancel(); //cancel timer once next input shown if needed
|
||||
} catch (final Exception ex) {} //suppress any exception thrown by cancel()
|
||||
awaitNextInputTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void updateAutoPassPrompt() {
|
||||
if (!autoPassUntilEndOfTurn.isEmpty()) {
|
||||
//allow user to cancel auto-pass
|
||||
cancelAwaitNextInput(); //don't overwrite prompt with awaiting opponent
|
||||
showPromptMessage(getCurrentPlayer(), "Yielding until end of turn.\nYou may cancel this yield to take an action.");
|
||||
updateButtons(getCurrentPlayer(), false, true, false);
|
||||
}
|
||||
}
|
||||
// End auto-yield/input code
|
||||
|
||||
// Abilities to auto-yield to
|
||||
private final Set<String> autoYields = Sets.newHashSet();
|
||||
public final Iterable<String> getAutoYields() {
|
||||
return autoYields;
|
||||
}
|
||||
@Override
|
||||
public final boolean shouldAutoYield(final String key) {
|
||||
return !getDisableAutoYields() && autoYields.contains(key);
|
||||
}
|
||||
@Override
|
||||
public final void setShouldAutoYield(final String key, final boolean autoYield) {
|
||||
if (autoYield) {
|
||||
autoYields.add(key);
|
||||
}
|
||||
else {
|
||||
autoYields.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean disableAutoYields;
|
||||
public final boolean getDisableAutoYields() {
|
||||
return disableAutoYields;
|
||||
}
|
||||
public final void setDisableAutoYields(final boolean b0) {
|
||||
disableAutoYields = b0;
|
||||
}
|
||||
|
||||
// Triggers preliminary choice: ask, decline or play
|
||||
private final Map<Integer, Boolean> triggersAlwaysAccept = Maps.newTreeMap();
|
||||
|
||||
@Override
|
||||
public final boolean shouldAlwaysAcceptTrigger(final int trigger) { return Boolean.TRUE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger))); }
|
||||
@Override
|
||||
public final boolean shouldAlwaysDeclineTrigger(final int trigger) { return Boolean.FALSE.equals(triggersAlwaysAccept.get(Integer.valueOf(trigger))); }
|
||||
@Override
|
||||
public final boolean shouldAlwaysAskTrigger(final int trigger) { return !triggersAlwaysAccept.containsKey(Integer.valueOf(trigger)); }
|
||||
|
||||
@Override
|
||||
public final void setShouldAlwaysAcceptTrigger(final int trigger) { triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.TRUE); }
|
||||
@Override
|
||||
public final void setShouldAlwaysDeclineTrigger(final int trigger) { triggersAlwaysAccept.put(Integer.valueOf(trigger), Boolean.FALSE); }
|
||||
@Override
|
||||
public final void setShouldAlwaysAskTrigger(final int trigger) { triggersAlwaysAccept.remove(Integer.valueOf(trigger)); }
|
||||
|
||||
// End of Triggers preliminary choice
|
||||
|
||||
// Start of Choice code
|
||||
|
||||
/**
|
||||
* Convenience for getChoices(message, 0, 1, choices).
|
||||
*
|
||||
* @param <T>
|
||||
* is automatically inferred.
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @param choices
|
||||
* a T object.
|
||||
* @return null if choices is missing, empty, or if the users' choices are
|
||||
* empty; otherwise, returns the first item in the List returned by
|
||||
* getChoices.
|
||||
* @see #getChoices(String, int, int, Object...)
|
||||
*/
|
||||
@Override
|
||||
public <T> T oneOrNone(final String message, final T[] choices) {
|
||||
if ((choices == null) || (choices.length == 0)) {
|
||||
return null;
|
||||
}
|
||||
final List<T> choice = getChoices(message, 0, 1, choices);
|
||||
return choice.isEmpty() ? null : choice.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T oneOrNone(final String message, final Collection<T> choices) {
|
||||
if ((choices == null) || choices.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final List<T> choice = getChoices(message, 0, 1, choices);
|
||||
return choice.isEmpty() ? null : choice.get(0);
|
||||
}
|
||||
|
||||
// returned Object will never be null
|
||||
/**
|
||||
* <p>
|
||||
* getChoice.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* a T object.
|
||||
* @param message
|
||||
* a {@link java.lang.String} object.
|
||||
* @param choices
|
||||
* a T object.
|
||||
* @return a T object.
|
||||
*/
|
||||
@Override
|
||||
public <T> T one(final String message, final T[] choices) {
|
||||
final List<T> choice = getChoices(message, 1, 1, choices);
|
||||
assert choice.size() == 1;
|
||||
return choice.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T one(final String message, final Collection<T> choices) {
|
||||
if (choices == null || choices.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (choices.size() == 1) {
|
||||
return Iterables.getFirst(choices, null);
|
||||
}
|
||||
|
||||
final List<T> choice = getChoices(message, 1, 1, choices);
|
||||
assert choice.size() == 1;
|
||||
return choice.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> noneOrMany(final String message, final Collection<T> choices) {
|
||||
return getChoices(message, 0, choices.size(), choices, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
// Nothing to choose here. Code uses this to just reveal one or more items
|
||||
public <T> void reveal(final String message, final T item) {
|
||||
List<T> items = new ArrayList<T>();
|
||||
items.add(item);
|
||||
reveal(message, items);
|
||||
}
|
||||
@Override
|
||||
public <T> void reveal(final String message, final T[] items) {
|
||||
getChoices(message, -1, -1, items);
|
||||
}
|
||||
@Override
|
||||
public <T> void reveal(final String message, final Collection<T> items) {
|
||||
getChoices(message, -1, -1, items);
|
||||
}
|
||||
|
||||
// Get Integer in range
|
||||
@Override
|
||||
public Integer getInteger(final String message) {
|
||||
return getInteger(message, 0, Integer.MAX_VALUE, false);
|
||||
}
|
||||
@Override
|
||||
public Integer getInteger(final String message, int min) {
|
||||
return getInteger(message, min, Integer.MAX_VALUE, false);
|
||||
}
|
||||
@Override
|
||||
public Integer getInteger(final String message, int min, int max) {
|
||||
return getInteger(message, min, max, false);
|
||||
}
|
||||
@Override
|
||||
public Integer getInteger(final String message, final int min, final int max, final boolean sortDesc) {
|
||||
if (max <= min) { return min; } //just return min if max <= min
|
||||
|
||||
//force cutting off after 100 numbers at most
|
||||
if (max == Integer.MAX_VALUE) {
|
||||
return getInteger(message, min, max, min + 99);
|
||||
}
|
||||
int count = max - min + 1;
|
||||
if (count > 100) {
|
||||
return getInteger(message, min, max, min + 99);
|
||||
}
|
||||
|
||||
final Integer[] choices = new Integer[count];
|
||||
if (sortDesc) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
choices[count - i - 1] = Integer.valueOf(i + min);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
choices[i] = Integer.valueOf(i + min);
|
||||
}
|
||||
}
|
||||
return oneOrNone(message, choices);
|
||||
}
|
||||
@Override
|
||||
public Integer getInteger(final String message, final int min, final int max, final int cutoff) {
|
||||
if (max <= min || cutoff < min) {
|
||||
return min; //just return min if max <= min or cutoff < min
|
||||
}
|
||||
|
||||
if (cutoff >= max) { //fallback to regular integer prompt if cutoff at or after max
|
||||
return getInteger(message, min, max);
|
||||
}
|
||||
|
||||
final List<Object> choices = new ArrayList<Object>();
|
||||
for (int i = min; i <= cutoff; i++) {
|
||||
choices.add(Integer.valueOf(i));
|
||||
}
|
||||
choices.add("Other...");
|
||||
|
||||
final Object choice = oneOrNone(message, choices);
|
||||
if (choice instanceof Integer || choice == null) {
|
||||
return (Integer)choice;
|
||||
}
|
||||
|
||||
//if Other option picked, prompt for number input
|
||||
String prompt = "Enter a number";
|
||||
if (min != Integer.MIN_VALUE) {
|
||||
if (max != Integer.MAX_VALUE) {
|
||||
prompt += " between " + min + " and " + max;
|
||||
} else {
|
||||
prompt += " greater than or equal to " + min;
|
||||
}
|
||||
} else if (max != Integer.MAX_VALUE) {
|
||||
prompt += " less than or equal to " + max;
|
||||
}
|
||||
prompt += ":";
|
||||
|
||||
while (true) {
|
||||
final String str = showInputDialog(prompt, message);
|
||||
if (str == null) { return null; } // that is 'cancel'
|
||||
|
||||
if (StringUtils.isNumeric(str)) {
|
||||
final Integer val = Integer.valueOf(str);
|
||||
if (val >= min && val <= max) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returned Object will never be null
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final T[] choices) {
|
||||
return getChoices(message, min, max, Arrays.asList(choices), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getChoices(final String message, final int min, final int max, final Collection<T> choices) {
|
||||
return getChoices(message, min, max, choices, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> many(final String title, final String topCaption, int cnt, final List<T> sourceChoices) {
|
||||
return many(title, topCaption, cnt, sourceChoices, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> many(final String title, final String topCaption, final int cnt, final List<T> sourceChoices, final CardView c) {
|
||||
return many(title, topCaption, cnt, cnt, sourceChoices, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> many(final String title, final String topCaption, final int min, final int max, final List<T> sourceChoices) {
|
||||
return many(title, topCaption, min, max, sourceChoices, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> many(final String title, final String topCaption, int min, int max, final List<T> sourceChoices, final CardView c) {
|
||||
final int m2 = min >= 0 ? sourceChoices.size() - min : -1;
|
||||
final int m1 = max >= 0 ? sourceChoices.size() - max : -1;
|
||||
return order(title, topCaption, m1, m2, sourceChoices, null, c, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> order(final String title, final String top, final List<T> sourceChoices) {
|
||||
return order(title, top, sourceChoices, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> order(final String title, final String top, final List<T> sourceChoices, final CardView c) {
|
||||
return order(title, top, 0, 0, sourceChoices, null, c, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the user to insert an object into a list of other objects. The
|
||||
* current implementation requires the user to cancel in order to get the
|
||||
* new item to be the first item in the resulting list.
|
||||
*
|
||||
* @param title the dialog title.
|
||||
* @param newItem the object to insert.
|
||||
* @param oldItems the list of objects.
|
||||
* @return A shallow copy of the list of objects, with newItem inserted.
|
||||
*/
|
||||
@Override
|
||||
public <T> List<T> insertInList(final String title, final T newItem, final List<T> oldItems) {
|
||||
final T placeAfter = oneOrNone(title, oldItems);
|
||||
final int indexAfter = (placeAfter == null ? 0 : oldItems.indexOf(placeAfter) + 1);
|
||||
final List<T> result = Lists.newArrayListWithCapacity(oldItems.size() + 1);
|
||||
result.addAll(oldItems);
|
||||
result.add(indexAfter, newItem);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String showInputDialog(final String message, final String title) {
|
||||
return showInputDialog(message, title, null, "", null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String showInputDialog(final String message, final String title, final FSkinProp icon) {
|
||||
return showInputDialog(message, title, icon, "", null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String showInputDialog(final String message, final String title, final FSkinProp icon, final String initialInput) {
|
||||
return showInputDialog(message, title, icon, initialInput, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirm(final CardView c, final String question) {
|
||||
return confirm(c, question, true, null);
|
||||
}
|
||||
@Override
|
||||
public boolean confirm(final CardView c, final String question, final boolean defaultChoice) {
|
||||
return confirm(c, question, defaultChoice, null);
|
||||
}
|
||||
@Override
|
||||
public boolean confirm(final CardView c, final String question, String[] options) {
|
||||
return confirm(c, question, true, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void message(final String message) {
|
||||
message(message, "Forge");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showErrorDialog(final String message) {
|
||||
showErrorDialog(message, "Error");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(final String message) {
|
||||
return showConfirmDialog(message, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(final String message, final String title) {
|
||||
return showConfirmDialog(message, title, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(final String message, final String title,
|
||||
final boolean defaultYes) {
|
||||
return showConfirmDialog(message, title, "Yes", "No");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showConfirmDialog(final String message, final String title,
|
||||
final String yesButtonText, final String noButtonText) {
|
||||
return showConfirmDialog(message, title, yesButtonText, noButtonText, true);
|
||||
}
|
||||
|
||||
// End of Choice code
|
||||
}
|
||||
358
forge-gui/src/main/java/forge/match/HostedMatch.java
Normal file
358
forge-gui/src/main/java/forge/match/HostedMatch.java
Normal file
@@ -0,0 +1,358 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.control.FControlGameEventHandler;
|
||||
import forge.control.FControlGamePlayback;
|
||||
import forge.control.WatchLocalGame;
|
||||
import forge.events.IUiEventVisitor;
|
||||
import forge.events.UiEvent;
|
||||
import forge.events.UiEventAttackerDeclared;
|
||||
import forge.events.UiEventBlockerAssigned;
|
||||
import forge.events.UiEventNextGameDecision;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameView;
|
||||
import forge.game.Match;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.player.LobbyPlayerHuman;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.quest.QuestController;
|
||||
import forge.sound.MusicPlaylist;
|
||||
import forge.sound.SoundSystem;
|
||||
import forge.util.CollectionSuppliers;
|
||||
import forge.util.FCollection;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.maps.HashMapOfLists;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
public class HostedMatch {
|
||||
private Match match;
|
||||
private Game game;
|
||||
private String title;
|
||||
private final List<PlayerControllerHuman> humanControllers = Lists.newArrayList();
|
||||
private Map<RegisteredPlayer, IGuiGame> guis;
|
||||
private int humanCount;
|
||||
private FControlGamePlayback playbackControl = null;
|
||||
private final MatchUiEventVisitor visitor = new MatchUiEventVisitor();
|
||||
private final Map<PlayerControllerHuman, NextGameDecision> nextGameDecisions = Maps.newHashMap();
|
||||
|
||||
public HostedMatch() {
|
||||
}
|
||||
|
||||
private static GameRules getDefaultRules(final GameType gameType) {
|
||||
final GameRules gameRules = new GameRules(gameType);
|
||||
gameRules.setPlayForAnte(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE));
|
||||
gameRules.setMatchAnteRarity(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY));
|
||||
gameRules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
|
||||
gameRules.canCloneUseTargetsImage = FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE);
|
||||
return gameRules;
|
||||
}
|
||||
|
||||
public void startMatch(final GameType gameType, final Set<GameType> appliedVariants, final List<RegisteredPlayer> players, final RegisteredPlayer human, final IGuiGame gui) {
|
||||
startMatch(getDefaultRules(gameType), appliedVariants, players, human, gui);
|
||||
}
|
||||
public void startMatch(final GameType gameType, final Set<GameType> appliedVariants, final List<RegisteredPlayer> players, final Map<RegisteredPlayer, IGuiGame> guis) {
|
||||
startMatch(getDefaultRules(gameType), appliedVariants, players, guis);
|
||||
}
|
||||
public void startMatch(final GameRules gameRules, final Set<GameType> appliedVariants, final List<RegisteredPlayer> players, final RegisteredPlayer human, final IGuiGame gui) {
|
||||
startMatch(gameRules, appliedVariants, players, human == null || gui == null ? null : ImmutableMap.of(human, gui));
|
||||
}
|
||||
public void startMatch(final GameRules gameRules, final Set<GameType> appliedVariants, final List<RegisteredPlayer> players, final Map<RegisteredPlayer, IGuiGame> guis) {
|
||||
if (gameRules == null || gameRules.getGameType() == null || players == null || players.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.guis = guis == null ? ImmutableMap.<RegisteredPlayer, IGuiGame>of() : guis;
|
||||
final boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
|
||||
for (final RegisteredPlayer rp : players) {
|
||||
rp.setRandomFoil(useRandomFoil);
|
||||
}
|
||||
|
||||
if (appliedVariants != null && !appliedVariants.isEmpty()) {
|
||||
gameRules.setAppliedVariants(appliedVariants);
|
||||
}
|
||||
|
||||
if (players.size() == 2) {
|
||||
title = String.format("%s vs %s", players.get(0).getPlayer().getName(), players.get(1).getPlayer().getName());
|
||||
} else {
|
||||
title = String.format("Multiplayer Game (%d players)", players.size());
|
||||
}
|
||||
this.match = new Match(gameRules, players, title);
|
||||
startGame();
|
||||
}
|
||||
|
||||
public void continueMatch() {
|
||||
endCurrentGame();
|
||||
startGame();
|
||||
}
|
||||
|
||||
public void restartMatch() {
|
||||
endCurrentGame();
|
||||
this.match = new Match(match.getRules(), match.getPlayers(), this.title);
|
||||
startGame();
|
||||
}
|
||||
|
||||
public void startGame() {
|
||||
nextGameDecisions.clear();
|
||||
SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MATCH);
|
||||
|
||||
game = match.createGame();
|
||||
|
||||
if (game.getRules().getGameType() == GameType.Quest) {
|
||||
QuestController qc = FModel.getQuest();
|
||||
// Reset new list when the Match round starts, not when each game starts
|
||||
if (game.getMatch().getPlayedGames().isEmpty()) {
|
||||
qc.getCards().resetNewList();
|
||||
}
|
||||
game.subscribeToEvents(qc); // this one listens to player's mulligans ATM
|
||||
}
|
||||
|
||||
game.subscribeToEvents(SoundSystem.instance);
|
||||
game.subscribeToEvents(visitor);
|
||||
|
||||
final String[] indices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
|
||||
// Instantiate all required field slots (user at 0)
|
||||
final List<Player> sortedPlayers = Lists.newArrayList(game.getRegisteredPlayers());
|
||||
Collections.sort(sortedPlayers, new Comparator<Player>() {
|
||||
@Override
|
||||
public int compare(final Player p1, final Player p2) {
|
||||
final int v1 = p1.getController() instanceof PlayerControllerHuman ? 0 : 1;
|
||||
final int v2 = p2.getController() instanceof PlayerControllerHuman ? 0 : 1;
|
||||
return Integer.compare(v1, v2);
|
||||
}
|
||||
});
|
||||
|
||||
final GameView gameView = getGameView();
|
||||
|
||||
int i = 0;
|
||||
int avatarIndex = 0;
|
||||
humanCount = 0;
|
||||
final MapOfLists<IGuiGame, PlayerView> playersPerGui = new HashMapOfLists<IGuiGame, PlayerView>(CollectionSuppliers.<PlayerView>arrayLists());
|
||||
for (final Player p : sortedPlayers) {
|
||||
if (i < indices.length) {
|
||||
avatarIndex = Integer.parseInt(indices[i]);
|
||||
i++;
|
||||
}
|
||||
p.getLobbyPlayer().setAvatarIndex(avatarIndex);
|
||||
p.updateAvatar();
|
||||
|
||||
if (p.getController() instanceof PlayerControllerHuman) {
|
||||
final PlayerControllerHuman humanController = (PlayerControllerHuman) p.getController();
|
||||
final IGuiGame gui = guis.get(p.getRegisteredPlayer());
|
||||
humanController.setGui(gui);
|
||||
gui.setGameView(gameView);
|
||||
gui.setGameController(p.getView(), humanController);
|
||||
|
||||
game.subscribeToEvents(new FControlGameEventHandler(humanController));
|
||||
playersPerGui.add(gui, p.getView());
|
||||
humanControllers.add(humanController);
|
||||
humanCount++;
|
||||
}
|
||||
}
|
||||
for (final Entry<IGuiGame, Collection<PlayerView>> e : playersPerGui.entrySet()) {
|
||||
e.getKey().openView(new FCollection<PlayerView>(e.getValue()));
|
||||
}
|
||||
|
||||
if (humanCount == 0) { //watch game but do not participate
|
||||
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
|
||||
gui.setGameView(gameView);
|
||||
|
||||
final PlayerControllerHuman humanController = new WatchLocalGame(game, new LobbyPlayerHuman("Spectator"), gui);
|
||||
game.subscribeToEvents(new FControlGameEventHandler(humanController));
|
||||
humanControllers.add(humanController);
|
||||
gui.setGameController(null, humanController);
|
||||
|
||||
gui.openView(null);
|
||||
} else if (humanCount == sortedPlayers.size()) {
|
||||
//if there are no AI's, allow all players to see all cards (hotseat mode).
|
||||
for (final PlayerControllerHuman humanController : humanControllers) {
|
||||
humanController.setMayLookAtAllCards(true);
|
||||
}
|
||||
}
|
||||
|
||||
//prompt user for player one name if needed
|
||||
if (StringUtils.isBlank(FModel.getPreferences().getPref(FPref.PLAYER_NAME)) && humanCount == 1) {
|
||||
GamePlayerUtil.setPlayerName();
|
||||
}
|
||||
|
||||
//ensure opponents set properly
|
||||
for (final Player p : sortedPlayers) {
|
||||
p.updateOpponentsForView();
|
||||
}
|
||||
|
||||
// It's important to run match in a different thread to allow GUI inputs to be invoked from inside game.
|
||||
// Game is set on pause while gui player takes decisions
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override public void run() {
|
||||
if (humanCount == 0) {
|
||||
// Create FControlGamePlayback in game thread to allow pausing
|
||||
playbackControl = new FControlGamePlayback(humanControllers.get(0));
|
||||
playbackControl.setGame(game);
|
||||
game.subscribeToEvents(playbackControl);
|
||||
}
|
||||
|
||||
// Actually start the game!
|
||||
match.startGame(game);
|
||||
|
||||
// After game is over...
|
||||
if (humanCount == 0) {
|
||||
// ... if no human players, let AI decide next game
|
||||
addNextGameDecision(null, match.isMatchOver() ? NextGameDecision.QUIT : NextGameDecision.CONTINUE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void registerSpectator(final LobbyPlayer lobbyPlayer, final IGuiGame gui) {
|
||||
final PlayerControllerHuman humanController = new WatchLocalGame(game, null, gui);
|
||||
gui.setGameController(null, humanController);
|
||||
gui.openView(null);
|
||||
|
||||
game.subscribeToEvents(new FControlGameEventHandler(humanController));
|
||||
humanControllers.add(humanController);
|
||||
}
|
||||
|
||||
public Game getGame() {
|
||||
return game;
|
||||
}
|
||||
public GameView getGameView() {
|
||||
return game == null ? null : game.getView();
|
||||
}
|
||||
|
||||
public void endCurrentGame() {
|
||||
if (game == null) { return; }
|
||||
|
||||
game = null;
|
||||
|
||||
for (final PlayerControllerHuman humanController : humanControllers) {
|
||||
humanController.getGui().afterGameEnd();
|
||||
}
|
||||
humanControllers.clear();
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
final ForgePreferences prefs = FModel.getPreferences();
|
||||
if (prefs == null) { return; } //do nothing if prefs haven't been initialized yet
|
||||
|
||||
SoundSystem.instance.pause();
|
||||
//pause playback if needed
|
||||
if (prefs.getPrefBoolean(FPref.UI_PAUSE_WHILE_MINIMIZED) && playbackControl != null) {
|
||||
playbackControl.getInput().pause();
|
||||
}
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
SoundSystem.instance.resume();
|
||||
}
|
||||
|
||||
/** Returns a random name from the supplied list. */
|
||||
public static String getRandomName() {
|
||||
final String playerName = GuiDisplayUtil.getPlayerName();
|
||||
final String aiName = NameGenerator.getRandomName("Any", "Generic", playerName);
|
||||
return aiName;
|
||||
}
|
||||
|
||||
private final class MatchUiEventVisitor implements IUiEventVisitor<Void> {
|
||||
@Override
|
||||
public Void visit(final UiEventBlockerAssigned event) {
|
||||
for (final PlayerControllerHuman humanController : humanControllers) {
|
||||
humanController.getGui().updateSingleCard(event.blocker);
|
||||
final PlayerView p = humanController.getPlayer().getView();
|
||||
if (event.attackerBeingBlocked.getController().equals(p)) {
|
||||
humanController.getGui().autoPassCancel(p);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(final UiEventAttackerDeclared event) {
|
||||
for (final PlayerControllerHuman humanController : humanControllers) {
|
||||
humanController.getGui().updateSingleCard(event.attacker);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(final UiEventNextGameDecision event) {
|
||||
addNextGameDecision(event.getController(), event.getDecision());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void receiveEvent(final UiEvent evt) {
|
||||
evt.visit(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void addNextGameDecision(final PlayerControllerHuman controller, final NextGameDecision decision) {
|
||||
if (decision == NextGameDecision.QUIT) {
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
endCurrentGame();
|
||||
}
|
||||
});
|
||||
return; // if any player chooses quit, quit the match
|
||||
}
|
||||
|
||||
nextGameDecisions.put(controller, decision);
|
||||
if (nextGameDecisions.size() < humanControllers.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int newMatch = 0, continueMatch = 0;
|
||||
for (final NextGameDecision dec : nextGameDecisions.values()) {
|
||||
switch (dec) {
|
||||
case CONTINUE:
|
||||
continueMatch++;
|
||||
break;
|
||||
case NEW:
|
||||
newMatch++;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if (continueMatch >= newMatch) {
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
continueMatch();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override public void run() {
|
||||
restartMatch();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.Match;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
public interface IMatchController {
|
||||
void startNewMatch(Match match);
|
||||
boolean resetForNewGame();
|
||||
boolean hotSeatMode();
|
||||
void openView(List<Player> sortedPlayers);
|
||||
void afterGameEnd();
|
||||
void showCombat();
|
||||
void showPromptMessage(PlayerView playerView, String message);
|
||||
boolean stopAtPhase(PlayerView playerTurn, PhaseType phase);
|
||||
IButton getBtnOK(PlayerView playerView);
|
||||
IButton getBtnCancel(PlayerView playerView);
|
||||
void focusButton(IButton button);
|
||||
void flashIncorrectAction();
|
||||
void updatePhase();
|
||||
void updateTurn(PlayerView player);
|
||||
void updatePlayerControl();
|
||||
void enableOverlay();
|
||||
void disableOverlay();
|
||||
void finishGame();
|
||||
Object showManaPool(PlayerView player);
|
||||
void hideManaPool(PlayerView player, Object zoneToRestore);
|
||||
boolean openZones(Collection<ZoneType> zones, Map<PlayerView, Object> players);
|
||||
void restoreOldZones(Map<PlayerView, Object> playersToRestoreZonesFor);
|
||||
void updateStack();
|
||||
void updateZones(List<Pair<PlayerView, ZoneType>> zonesToUpdate);
|
||||
void updateSingleCard(CardView card);
|
||||
void refreshCardDetails(Iterable<CardView> cards);
|
||||
void updateManaPool(Iterable<PlayerView> manaPoolUpdate);
|
||||
void updateLives(Iterable<PlayerView> livesUpdate);
|
||||
void setPanelSelection(CardView hostCard);
|
||||
void hear(LobbyPlayer player, String message);
|
||||
SpellAbility getAbilityToPlay(List<SpellAbility> abilities, ITriggerEvent triggerEvent);
|
||||
Map<CardView, Integer> assignDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder);
|
||||
}
|
||||
@@ -1,459 +0,0 @@
|
||||
package forge.match;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import forge.LobbyPlayer;
|
||||
import forge.ai.LobbyPlayerAi;
|
||||
import forge.card.CardStateName;
|
||||
import forge.control.FControlGameEventHandler;
|
||||
import forge.control.FControlGamePlayback;
|
||||
import forge.control.WatchLocalGame;
|
||||
import forge.events.IUiEventVisitor;
|
||||
import forge.events.UiEvent;
|
||||
import forge.events.UiEventAttackerDeclared;
|
||||
import forge.events.UiEventBlockerAssigned;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntityView;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameView;
|
||||
import forge.game.Match;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.match.input.InputPlaybackControl;
|
||||
import forge.match.input.InputQueue;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.player.LobbyPlayerHuman;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.quest.QuestController;
|
||||
import forge.sound.MusicPlaylist;
|
||||
import forge.sound.SoundSystem;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
import forge.util.NameGenerator;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
public class MatchUtil {
|
||||
private static IMatchController controller;
|
||||
private static Game game;
|
||||
private static Player currentPlayer;
|
||||
private static final List<PlayerControllerHuman> humanControllers = new ArrayList<PlayerControllerHuman>();
|
||||
private static int humanCount;
|
||||
private static final EventBus uiEvents;
|
||||
private static FControlGamePlayback playbackControl;
|
||||
private static final MatchUiEventVisitor visitor = new MatchUiEventVisitor();
|
||||
|
||||
static {
|
||||
uiEvents = new EventBus("ui events");
|
||||
uiEvents.register(SoundSystem.instance);
|
||||
uiEvents.register(visitor);
|
||||
}
|
||||
|
||||
public static IMatchController getController() {
|
||||
return controller;
|
||||
}
|
||||
public static void setController(IMatchController controller0) {
|
||||
controller = controller0;
|
||||
}
|
||||
|
||||
public static void startMatch(GameType gameType, List<RegisteredPlayer> players) {
|
||||
startMatch(gameType, null, players);
|
||||
}
|
||||
public static void startMatch(GameType gameType, Set<GameType> appliedVariants, List<RegisteredPlayer> players) {
|
||||
boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
|
||||
for (RegisteredPlayer rp : players) {
|
||||
rp.setRandomFoil(useRandomFoil);
|
||||
}
|
||||
|
||||
GameRules rules = new GameRules(gameType);
|
||||
if (appliedVariants != null && !appliedVariants.isEmpty()) {
|
||||
rules.setAppliedVariants(appliedVariants);
|
||||
}
|
||||
rules.setPlayForAnte(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE));
|
||||
rules.setMatchAnteRarity(FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY));
|
||||
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
|
||||
rules.canCloneUseTargetsImage = FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE);
|
||||
|
||||
controller.startNewMatch(new Match(rules, players));
|
||||
}
|
||||
|
||||
public static void continueMatch() {
|
||||
final Match match = game.getMatch();
|
||||
endCurrentGame();
|
||||
startGame(match);
|
||||
}
|
||||
|
||||
public static void restartMatch() {
|
||||
final Match match = game.getMatch();
|
||||
endCurrentGame();
|
||||
match.clearGamesPlayed();
|
||||
startGame(match);
|
||||
}
|
||||
|
||||
public static void startGame(final Match match) {
|
||||
if (!controller.resetForNewGame()) { return; }
|
||||
|
||||
SoundSystem.instance.setBackgroundMusic(MusicPlaylist.MATCH);
|
||||
|
||||
game = match.createGame();
|
||||
|
||||
if (game.getRules().getGameType() == GameType.Quest) {
|
||||
QuestController qc = FModel.getQuest();
|
||||
// Reset new list when the Match round starts, not when each game starts
|
||||
if (game.getMatch().getPlayedGames().isEmpty()) {
|
||||
qc.getCards().resetNewList();
|
||||
}
|
||||
game.subscribeToEvents(qc); // this one listens to player's mulligans ATM
|
||||
}
|
||||
|
||||
game.subscribeToEvents(SoundSystem.instance);
|
||||
|
||||
final String[] indices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
|
||||
|
||||
// Instantiate all required field slots (user at 0)
|
||||
final List<Player> sortedPlayers = new ArrayList<Player>(game.getRegisteredPlayers());
|
||||
Collections.sort(sortedPlayers, new Comparator<Player>() {
|
||||
@Override
|
||||
public int compare(Player p1, Player p2) {
|
||||
int v1 = p1.getController() instanceof PlayerControllerHuman ? 0 : 1;
|
||||
int v2 = p2.getController() instanceof PlayerControllerHuman ? 0 : 1;
|
||||
return Integer.compare(v1, v2);
|
||||
}
|
||||
});
|
||||
|
||||
int i = 0;
|
||||
int avatarIndex = 0;
|
||||
humanCount = 0;
|
||||
for (Player p : sortedPlayers) {
|
||||
if (i < indices.length) {
|
||||
avatarIndex = Integer.parseInt(indices[i]);
|
||||
i++;
|
||||
}
|
||||
p.getLobbyPlayer().setAvatarIndex(avatarIndex);
|
||||
p.updateAvatar();
|
||||
|
||||
if (p.getController() instanceof PlayerControllerHuman) {
|
||||
final PlayerControllerHuman humanController = (PlayerControllerHuman) p.getController();
|
||||
if (humanCount == 0) {
|
||||
currentPlayer = p;
|
||||
game.subscribeToEvents(new FControlGameEventHandler(humanController));
|
||||
}
|
||||
humanControllers.add(humanController);
|
||||
humanCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (humanCount == 0) { //watch game but do not participate
|
||||
currentPlayer = sortedPlayers.get(0);
|
||||
PlayerControllerHuman humanController = new WatchLocalGame(game, currentPlayer, currentPlayer.getLobbyPlayer());
|
||||
game.subscribeToEvents(new FControlGameEventHandler(humanController));
|
||||
humanControllers.add(humanController);
|
||||
}
|
||||
else if (humanCount == sortedPlayers.size() && controller.hotSeatMode()) {
|
||||
//if there are no AI's, allow all players to see all cards (hotseat mode).
|
||||
for (Player p : sortedPlayers) {
|
||||
((PlayerControllerHuman) p.getController()).setMayLookAtAllCards(true);
|
||||
}
|
||||
}
|
||||
|
||||
controller.openView(sortedPlayers);
|
||||
|
||||
if (humanCount == 0) {
|
||||
playbackControl = new FControlGamePlayback(getHumanController());
|
||||
playbackControl.setGame(game);
|
||||
game.subscribeToEvents(playbackControl);
|
||||
}
|
||||
|
||||
//ensure opponents set properly
|
||||
for (Player p : sortedPlayers) {
|
||||
p.updateOpponentsForView();
|
||||
}
|
||||
|
||||
// It's important to run match in a different thread to allow GUI inputs to be invoked from inside game.
|
||||
// Game is set on pause while gui player takes decisions
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
//prompt user for player one name if needed
|
||||
if (StringUtils.isBlank(FModel.getPreferences().getPref(FPref.PLAYER_NAME))) {
|
||||
boolean isPlayerOneHuman = match.getPlayers().get(0).getPlayer() instanceof LobbyPlayerHuman;
|
||||
boolean isPlayerTwoComputer = match.getPlayers().get(1).getPlayer() instanceof LobbyPlayerAi;
|
||||
if (isPlayerOneHuman && isPlayerTwoComputer) {
|
||||
GamePlayerUtil.setPlayerName();
|
||||
}
|
||||
}
|
||||
match.startGame(game);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Game getGame() {
|
||||
return game;
|
||||
}
|
||||
public static GameView getGameView() {
|
||||
return game == null ? null : game.getView();
|
||||
}
|
||||
|
||||
public static PlayerControllerHuman getHumanController() {
|
||||
return getHumanController(currentPlayer);
|
||||
}
|
||||
public static PlayerControllerHuman getHumanController(Player player) {
|
||||
switch (humanControllers.size()) {
|
||||
case 1:
|
||||
return humanControllers.get(0);
|
||||
case 0:
|
||||
return null;
|
||||
default:
|
||||
return humanControllers.get(player.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public static int getHumanCount() {
|
||||
return humanCount;
|
||||
}
|
||||
|
||||
public static PlayerControllerHuman getOtherHumanController() {
|
||||
//return other game view besides current game view
|
||||
if (humanControllers.size() < 2) {
|
||||
return null;
|
||||
}
|
||||
PlayerControllerHuman humanController = getHumanController();
|
||||
if (humanController == humanControllers.get(0)) {
|
||||
return humanControllers.get(1);
|
||||
}
|
||||
return humanControllers.get(0);
|
||||
}
|
||||
|
||||
public static InputQueue getInputQueue() {
|
||||
PlayerControllerHuman humanController = getHumanController();
|
||||
if (humanController != null) {
|
||||
return humanController.getInputQueue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void endCurrentTurn() {
|
||||
getHumanController().passPriorityUntilEndOfTurn();
|
||||
}
|
||||
|
||||
public static Player getCurrentPlayer() {
|
||||
return currentPlayer;
|
||||
}
|
||||
public static void setCurrentPlayer(Player currentPlayer0) {
|
||||
if (currentPlayer == currentPlayer0) { return; }
|
||||
currentPlayer = currentPlayer0;
|
||||
if (humanControllers.size() > 1) {
|
||||
//TODO: ensure card views updated when current player changes to account for changes in card visibility
|
||||
}
|
||||
}
|
||||
|
||||
public static void alphaStrike() {
|
||||
getHumanController().alphaStrike();
|
||||
}
|
||||
|
||||
public static Map<CardView, Integer> getDamageToAssign(final CardView attacker, final List<CardView> blockers, final int damage, final GameEntityView defender, final boolean overrideOrder) {
|
||||
if (damage <= 0) {
|
||||
return new HashMap<CardView, Integer>();
|
||||
}
|
||||
|
||||
// If the first blocker can absorb all of the damage, don't show the Assign Damage dialog
|
||||
CardView firstBlocker = blockers.get(0);
|
||||
if (!overrideOrder && !attacker.getCurrentState().hasDeathtouch() && firstBlocker.getLethalDamage() >= damage) {
|
||||
Map<CardView, Integer> res = new HashMap<CardView, Integer>();
|
||||
res.put(firstBlocker, damage);
|
||||
return res;
|
||||
}
|
||||
|
||||
return controller.assignDamage(attacker, blockers, damage, defender, overrideOrder);
|
||||
}
|
||||
|
||||
public static String getCardImageKey(CardStateView csv) {
|
||||
if (currentPlayer == null) { return csv.getImageKey(null); } //if not in game, card can be shown
|
||||
return csv.getImageKey(currentPlayer.getView());
|
||||
}
|
||||
|
||||
public static boolean canCardBeShown(CardView cv) {
|
||||
if (currentPlayer == null) { return true; } //if not in game, card can be shown
|
||||
if (currentPlayer.getController() instanceof PlayerControllerHuman && ((PlayerControllerHuman) currentPlayer.getController()).mayLookAtAllCards()) {
|
||||
return true;
|
||||
}
|
||||
return cv.canBeShownTo(currentPlayer.getView());
|
||||
}
|
||||
|
||||
public static boolean canCardBeFlipped(CardView cv) {
|
||||
if (cv == null) { return false; }
|
||||
|
||||
CardStateView altState = cv.getAlternateState();
|
||||
if (altState == null) { return false; }
|
||||
|
||||
switch (altState.getState()) {
|
||||
case Original:
|
||||
CardStateView currentState = cv.getCurrentState();
|
||||
if (currentState.getState() == CardStateName.FaceDown) {
|
||||
return currentPlayer == null || cv.canFaceDownBeShownTo(currentPlayer.getView());
|
||||
}
|
||||
return true; //original can always be shown if not a face down that can't be shown
|
||||
case Flipped:
|
||||
case Transformed:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<PlayerView> highlightedPlayers = new HashSet<PlayerView>();
|
||||
public static void setHighlighted(PlayerView pv, boolean b) {
|
||||
if (b) {
|
||||
highlightedPlayers.add(pv);
|
||||
}
|
||||
else {
|
||||
highlightedPlayers.remove(pv);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isHighlighted(PlayerView player) {
|
||||
return highlightedPlayers.contains(player);
|
||||
}
|
||||
|
||||
private static Set<CardView> highlightedCards = new HashSet<CardView>();
|
||||
// used to highlight cards in UI
|
||||
public static void setUsedToPay(CardView card, boolean value) {
|
||||
boolean hasChanged = value ? highlightedCards.add(card) : highlightedCards.remove(card);
|
||||
if (hasChanged) { // since we are in UI thread, may redraw the card right now
|
||||
controller.updateSingleCard(card);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isUsedToPay(CardView card) {
|
||||
return highlightedCards.contains(card);
|
||||
}
|
||||
|
||||
public static void updateCards(Iterable<CardView> cardsToUpdate) {
|
||||
for (CardView c : cardsToUpdate) {
|
||||
controller.updateSingleCard(c);
|
||||
}
|
||||
}
|
||||
|
||||
/** Concede game, bring up WinLose UI. */
|
||||
public static void concede() {
|
||||
String userPrompt =
|
||||
"This will end the current game and you will not be able to resume.\n\n" +
|
||||
"Concede anyway?";
|
||||
if (SOptionPane.showConfirmDialog(userPrompt, "Concede Game?", "Concede", "Cancel")) {
|
||||
if (humanCount == 0) { // no human? then all players surrender!
|
||||
for (Player p : game.getPlayers()) {
|
||||
p.concede();
|
||||
}
|
||||
}
|
||||
else {
|
||||
getCurrentPlayer().concede();
|
||||
}
|
||||
|
||||
Player priorityPlayer = game.getPhaseHandler().getPriorityPlayer();
|
||||
boolean humanHasPriority = priorityPlayer == null || priorityPlayer.getLobbyPlayer() instanceof LobbyPlayerHuman;
|
||||
|
||||
if (humanCount > 0 && humanHasPriority) {
|
||||
game.getAction().checkGameOverCondition();
|
||||
}
|
||||
else {
|
||||
game.isGameOver(); // this is synchronized method - it's used to make Game-0 thread see changes made here
|
||||
onGameOver(false); //release any waiting input, effectively passing priority
|
||||
}
|
||||
|
||||
if (playbackControl != null) {
|
||||
playbackControl.onGameStopRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void onGameOver(boolean releaseAllInputs) {
|
||||
for (PlayerControllerHuman humanController : humanControllers) {
|
||||
humanController.getInputQueue().onGameOver(releaseAllInputs);
|
||||
}
|
||||
}
|
||||
|
||||
public static void endCurrentGame() {
|
||||
if (game == null) { return; }
|
||||
|
||||
game = null;
|
||||
currentPlayer = null;
|
||||
humanControllers.clear();
|
||||
|
||||
controller.afterGameEnd();
|
||||
}
|
||||
|
||||
public static void pause() {
|
||||
ForgePreferences prefs = FModel.getPreferences();
|
||||
if (prefs == null) { return; } //do nothing if prefs haven't been initialized yet
|
||||
|
||||
SoundSystem.instance.pause();
|
||||
//pause playback if needed
|
||||
if (prefs.getPrefBoolean(FPref.UI_PAUSE_WHILE_MINIMIZED)) {
|
||||
InputQueue inputQueue = getInputQueue();
|
||||
if (inputQueue != null && inputQueue.getInput() instanceof InputPlaybackControl) {
|
||||
((InputPlaybackControl) inputQueue.getInput()).pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void resume() {
|
||||
SoundSystem.instance.resume();
|
||||
}
|
||||
|
||||
private final static boolean LOG_UIEVENTS = false;
|
||||
|
||||
// UI-related events should arrive here
|
||||
public static void fireEvent(UiEvent uiEvent) {
|
||||
if (LOG_UIEVENTS) {
|
||||
//System.out.println("UI: " + uiEvent.toString() + " \t\t " + FThreads.debugGetStackTraceItem(4, true));
|
||||
}
|
||||
uiEvents.post(uiEvent);
|
||||
}
|
||||
|
||||
/** Returns a random name from the supplied list. */
|
||||
public static String getRandomName() {
|
||||
String playerName = GuiDisplayUtil.getPlayerName();
|
||||
String aiName = NameGenerator.getRandomName("Any", "Generic", playerName);
|
||||
return aiName;
|
||||
}
|
||||
|
||||
public final static LobbyPlayer getGuiPlayer() {
|
||||
return GamePlayerUtil.getGuiPlayer();
|
||||
}
|
||||
|
||||
private static class MatchUiEventVisitor implements IUiEventVisitor<Void> {
|
||||
@Override
|
||||
public Void visit(UiEventBlockerAssigned event) {
|
||||
controller.updateSingleCard(event.blocker);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(UiEventAttackerDeclared event) {
|
||||
controller.updateSingleCard(event.attacker);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void receiveEvent(UiEvent evt) {
|
||||
evt.visit(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package forge.match;
|
||||
|
||||
public enum NextGameDecision {
|
||||
NEW,
|
||||
CONTINUE,
|
||||
QUIT;
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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.match.input;
|
||||
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.match.MatchUtil;
|
||||
|
||||
/**
|
||||
* Manages match UI OK/Cancel button enabling and focus
|
||||
*/
|
||||
public class ButtonUtil {
|
||||
public static void update(PlayerView owner, boolean okEnabled, boolean cancelEnabled, boolean focusOk) {
|
||||
update(owner, "OK", "Cancel", okEnabled, cancelEnabled, focusOk);
|
||||
}
|
||||
public static void update(PlayerView owner, String okLabel, String cancelLabel, boolean okEnabled, boolean cancelEnabled, boolean focusOk) {
|
||||
IButton btnOk = MatchUtil.getController().getBtnOK(owner);
|
||||
IButton btnCancel = MatchUtil.getController().getBtnCancel(owner);
|
||||
|
||||
btnOk.setText(okLabel);
|
||||
btnCancel.setText(cancelLabel);
|
||||
btnOk.setEnabled(okEnabled);
|
||||
btnCancel.setEnabled(cancelEnabled);
|
||||
if (okEnabled && focusOk) {
|
||||
MatchUtil.getController().focusButton(btnOk);
|
||||
}
|
||||
else if (cancelEnabled) {
|
||||
MatchUtil.getController().focusButton(btnCancel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,6 @@ import forge.game.combat.CombatUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
@@ -89,10 +88,9 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
|
||||
private void updatePrompt() {
|
||||
if (canCallBackAttackers()) {
|
||||
ButtonUtil.update(getOwner(), "OK", "Call Back", true, true, true);
|
||||
}
|
||||
else {
|
||||
ButtonUtil.update(getOwner(), "OK", "Alpha Strike", true, true, true);
|
||||
getController().getGui().updateButtons(getOwner(), "OK", "Call Back", true, true, true);
|
||||
} else {
|
||||
getController().getGui().updateButtons(getOwner(), "OK", "Alpha Strike", true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +135,7 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
MatchUtil.updateCards(refreshCards);
|
||||
getController().getGui().updateCards(refreshCards);
|
||||
updateMessage();
|
||||
}
|
||||
|
||||
@@ -147,7 +145,7 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
setCurrentDefender(selected);
|
||||
}
|
||||
else {
|
||||
MatchUtil.getController().flashIncorrectAction(); // cannot attack that player
|
||||
getController().getGui().flashIncorrectAction(); // cannot attack that player
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,18 +258,18 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
combat.addAttacker(card, currentDefender, activeBand);
|
||||
activateBand(activeBand);
|
||||
|
||||
MatchUtil.fireEvent(new UiEventAttackerDeclared(
|
||||
card.getGame().fireEvent(new UiEventAttackerDeclared(
|
||||
CardView.get(card),
|
||||
GameEntityView.get(currentDefender)));
|
||||
}
|
||||
|
||||
private boolean undeclareAttacker(final Card card) {
|
||||
combat.removeFromCombat(card);
|
||||
MatchUtil.setUsedToPay(CardView.get(card), false);
|
||||
getController().getGui().setUsedToPay(CardView.get(card), false);
|
||||
// When removing an attacker clear the attacking band
|
||||
activateBand(null);
|
||||
|
||||
MatchUtil.fireEvent(new UiEventAttackerDeclared(
|
||||
card.getGame().fireEvent(new UiEventAttackerDeclared(
|
||||
CardView.get(card), null));
|
||||
return true;
|
||||
}
|
||||
@@ -280,10 +278,10 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
currentDefender = def;
|
||||
for (final GameEntity ge : defenders) {
|
||||
if (ge instanceof Card) {
|
||||
MatchUtil.setUsedToPay(CardView.get((Card) ge), ge == def);
|
||||
getController().getGui().setUsedToPay(CardView.get((Card) ge), ge == def);
|
||||
}
|
||||
else if (ge instanceof Player) {
|
||||
MatchUtil.setHighlighted(PlayerView.get((Player) ge), ge == def);
|
||||
getController().getGui().setHighlighted(PlayerView.get((Player) ge), ge == def);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,14 +291,14 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
private final void activateBand(final AttackingBand band) {
|
||||
if (activeBand != null) {
|
||||
for (final Card card : activeBand.getAttackers()) {
|
||||
MatchUtil.setUsedToPay(CardView.get(card), false);
|
||||
getController().getGui().setUsedToPay(CardView.get(card), false);
|
||||
}
|
||||
}
|
||||
activeBand = band;
|
||||
|
||||
if (activeBand != null) {
|
||||
for (final Card card : activeBand.getAttackers()) {
|
||||
MatchUtil.setUsedToPay(CardView.get(card), true);
|
||||
getController().getGui().setUsedToPay(CardView.get(card), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,6 +322,6 @@ public class InputAttack extends InputSyncronizedBase {
|
||||
showMessage(message);
|
||||
|
||||
updatePrompt();
|
||||
MatchUtil.getController().showCombat(); // redraw sword icons
|
||||
getController().getGui().showCombat(); // redraw sword icons
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,13 @@
|
||||
package forge.match.input;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
|
||||
@@ -41,8 +37,8 @@ import forge.util.ITriggerEvent;
|
||||
* @version $Id: InputBase.java 24769 2014-02-09 13:56:04Z Hellfish $
|
||||
*/
|
||||
public abstract class InputBase implements java.io.Serializable, Input {
|
||||
/** Constant <code>serialVersionUID=-6539552513871194081L</code>. */
|
||||
private static final long serialVersionUID = -6539552513871194081L;
|
||||
/** Constant <code>serialVersionUID=-2531867688249685076L</code>. */
|
||||
private static final long serialVersionUID = -2531867688249685076L;
|
||||
|
||||
private final PlayerControllerHuman controller;
|
||||
public InputBase(final PlayerControllerHuman controller0) {
|
||||
@@ -52,7 +48,8 @@ public abstract class InputBase implements java.io.Serializable, Input {
|
||||
return controller;
|
||||
}
|
||||
public PlayerView getOwner() {
|
||||
return controller.getPlayer().getView();
|
||||
final Player owner = getController().getPlayer();
|
||||
return owner == null ? null : owner.getView();
|
||||
}
|
||||
|
||||
private boolean finished = false;
|
||||
@@ -61,7 +58,7 @@ public abstract class InputBase implements java.io.Serializable, Input {
|
||||
finished = true;
|
||||
|
||||
if (allowAwaitNextInput()) {
|
||||
awaitNextInput(controller);
|
||||
controller.awaitNextInput();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,66 +66,11 @@ public abstract class InputBase implements java.io.Serializable, Input {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final Timer awaitNextInputTimer = new Timer();
|
||||
private static TimerTask awaitNextInputTask;
|
||||
|
||||
public static void awaitNextInput(final PlayerControllerHuman controller) {
|
||||
//delay updating prompt to await next input briefly so buttons don't flicker disabled then enabled
|
||||
awaitNextInputTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
FThreads.invokeInEdtLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (awaitNextInputTimer) {
|
||||
if (awaitNextInputTask != null) {
|
||||
updatePromptForAwait(controller);
|
||||
awaitNextInputTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
awaitNextInputTimer.schedule(awaitNextInputTask, 250);
|
||||
}
|
||||
|
||||
public static void waitForOtherPlayer() {
|
||||
final PlayerControllerHuman controller = MatchUtil.getOtherHumanController();
|
||||
if (controller == null) { return; }
|
||||
|
||||
cancelAwaitNextInput();
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updatePromptForAwait(controller);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void updatePromptForAwait(final PlayerControllerHuman controller) {
|
||||
PlayerView playerView = controller.getLocalPlayerView();
|
||||
MatchUtil.getController().showPromptMessage(playerView, "Waiting for opponent...");
|
||||
ButtonUtil.update(playerView, false, false, false);
|
||||
}
|
||||
|
||||
public static void cancelAwaitNextInput() {
|
||||
synchronized (awaitNextInputTimer) { //ensure task doesn't reset awaitNextInputTask during this block
|
||||
if (awaitNextInputTask != null) {
|
||||
try {
|
||||
awaitNextInputTask.cancel(); //cancel timer once next input shown if needed
|
||||
}
|
||||
catch (Exception ex) {} //suppress any exception thrown by cancel()
|
||||
awaitNextInputTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// showMessage() is always the first method called
|
||||
@Override
|
||||
public final void showMessageInitial() {
|
||||
finished = false;
|
||||
cancelAwaitNextInput();
|
||||
controller.cancelAwaitNextInput();
|
||||
showMessage();
|
||||
}
|
||||
|
||||
@@ -172,7 +114,7 @@ public abstract class InputBase implements java.io.Serializable, Input {
|
||||
|
||||
// to remove need for CMatchUI dependence
|
||||
protected final void showMessage(final String message) {
|
||||
MatchUtil.getController().showPromptMessage(getOwner(), message);
|
||||
controller.getGui().showPromptMessage(getOwner(), message);
|
||||
}
|
||||
|
||||
protected String getTurnPhasePriorityMessage(final Game game) {
|
||||
|
||||
@@ -30,11 +30,9 @@ import forge.game.combat.CombatUtil;
|
||||
import forge.game.event.GameEventCombatChanged;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.ThreadUtil;
|
||||
import forge.util.gui.SGuiDialog;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -78,7 +76,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
@Override
|
||||
protected final void showMessage() {
|
||||
// could add "Reset Blockers" button
|
||||
ButtonUtil.update(getOwner(), true, false, true);
|
||||
getController().getGui().updateButtons(getOwner(), true, false, true);
|
||||
|
||||
if (currentAttacker == null) {
|
||||
showMessage("Select another attacker to declare blockers for.");
|
||||
@@ -89,7 +87,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
showMessage(message);
|
||||
}
|
||||
|
||||
MatchUtil.getController().showCombat();
|
||||
getController().getGui().showCombat();
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@@ -106,7 +104,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
ThreadUtil.invokeInGameThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SGuiDialog.message(blockErrors);
|
||||
getController().getGui().message(blockErrors);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -118,7 +116,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
boolean isCorrectAction = false;
|
||||
if (triggerEvent != null && triggerEvent.getButton() == 3 && card.getController() == defender) {
|
||||
combat.removeFromCombat(card);
|
||||
MatchUtil.fireEvent(new UiEventBlockerAssigned(
|
||||
card.getGame().fireEvent(new UiEventBlockerAssigned(
|
||||
CardView.get(card), (CardView) null));
|
||||
isCorrectAction = true;
|
||||
}
|
||||
@@ -134,7 +132,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
if (combat.isBlocking(card, currentAttacker)) {
|
||||
//if creature already blocking current attacker, remove blocker from combat
|
||||
combat.removeBlockAssignment(currentAttacker, card);
|
||||
MatchUtil.fireEvent(new UiEventBlockerAssigned(
|
||||
card.getGame().fireEvent(new UiEventBlockerAssigned(
|
||||
CardView.get(card), (CardView) null));
|
||||
isCorrectAction = true;
|
||||
}
|
||||
@@ -142,7 +140,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
isCorrectAction = CombatUtil.canBlock(currentAttacker, card, combat);
|
||||
if (isCorrectAction) {
|
||||
combat.addBlocker(currentAttacker, card);
|
||||
MatchUtil.fireEvent(new UiEventBlockerAssigned(
|
||||
card.getGame().fireEvent(new UiEventBlockerAssigned(
|
||||
CardView.get(card),
|
||||
CardView.get(currentAttacker)));
|
||||
}
|
||||
@@ -178,7 +176,7 @@ public class InputBlock extends InputSyncronizedBase {
|
||||
private void setCurrentAttacker(final Card card) {
|
||||
currentAttacker = card;
|
||||
for (final Card c : combat.getAttackers()) {
|
||||
MatchUtil.setUsedToPay(CardView.get(c), card == c);
|
||||
getController().getGui().setUsedToPay(CardView.get(c), card == c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class InputConfirm extends InputSyncronizedBase {
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
protected final void showMessage() {
|
||||
ButtonUtil.update(getOwner(), yesButtonText, noButtonText, true, true, defaultYes);
|
||||
getController().getGui().updateButtons(getOwner(), yesButtonText, noButtonText, true, true, defaultYes);
|
||||
showMessage(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,10 @@ import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.Lang;
|
||||
import forge.util.ThreadUtil;
|
||||
import forge.util.gui.SGuiDialog;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -74,11 +72,11 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
if (isCommander) {
|
||||
ButtonUtil.update(getOwner(), "Keep", "Exile", true, false, true);
|
||||
getController().getGui().updateButtons(getOwner(), "Keep", "Exile", true, false, true);
|
||||
sb.append("Will you keep your hand or choose some cards to exile those and draw one less card?");
|
||||
}
|
||||
else {
|
||||
ButtonUtil.update(getOwner(), "Keep", "Mulligan", true, true, true);
|
||||
getController().getGui().updateButtons(getOwner(), "Keep", "Mulligan", true, true, true);
|
||||
sb.append("Do you want to keep your hand?");
|
||||
}
|
||||
|
||||
@@ -103,7 +101,7 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
if (isCommander) {
|
||||
// Clear the "selected" icon after clicking the done button
|
||||
for (final Card c : this.selected) {
|
||||
MatchUtil.setUsedToPay(c.getView(), false);
|
||||
getController().getGui().setUsedToPay(c.getView(), false);
|
||||
}
|
||||
}
|
||||
stop();
|
||||
@@ -121,7 +119,7 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
final CardView cView = c0.getView();
|
||||
if (isSerumPowder && SGuiDialog.confirm(cView, "Use " + cView + "'s ability?")) {
|
||||
if (isSerumPowder && getController().getGui().confirm(cView, "Use " + cView + "'s ability?")) {
|
||||
cardSelectLocked = true;
|
||||
ThreadUtil.invokeInGameThread(new Runnable() {
|
||||
public void run() {
|
||||
@@ -138,14 +136,14 @@ public class InputConfirmMulligan extends InputSyncronizedBase {
|
||||
|
||||
if (isCommander) { // allow to choose cards for partial paris
|
||||
if (selected.contains(c0)) {
|
||||
MatchUtil.setUsedToPay(c0.getView(), false);
|
||||
getController().getGui().setUsedToPay(c0.getView(), false);
|
||||
selected.remove(c0);
|
||||
}
|
||||
else {
|
||||
MatchUtil.setUsedToPay(c0.getView(), true);
|
||||
getController().getGui().setUsedToPay(c0.getView(), true);
|
||||
selected.add(c0);
|
||||
}
|
||||
ButtonUtil.update(getOwner(), "Keep", "Exile", true, !selected.isEmpty(), true);
|
||||
getController().getGui().updateButtons(getOwner(), "Keep", "Exile", true, !selected.isEmpty(), true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.ThreadUtil;
|
||||
|
||||
@@ -18,9 +18,11 @@ public class InputLockUI implements Input {
|
||||
|
||||
private final InputQueue inputQueue;
|
||||
private final Game game;
|
||||
public InputLockUI(final Game game0, final InputQueue inputQueue0) {
|
||||
private final PlayerControllerHuman controller;
|
||||
public InputLockUI(final Game game0, final InputQueue inputQueue0, final PlayerControllerHuman controller) {
|
||||
game = game0;
|
||||
inputQueue = inputQueue0;
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -32,7 +34,7 @@ public class InputLockUI implements Input {
|
||||
int ixCall = 1 + iCall.getAndIncrement();
|
||||
ThreadUtil.delay(500, new InputUpdater(ixCall));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "lockUI";
|
||||
@@ -56,7 +58,7 @@ public class InputLockUI implements Input {
|
||||
private final Runnable showMessageFromEdt = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ButtonUtil.update(InputLockUI.this.getOwner(), "", "", false, false, false);
|
||||
controller.getGui().updateButtons(InputLockUI.this.getOwner(), "", "", false, false, false);
|
||||
showMessage("Waiting for actions...");
|
||||
}
|
||||
};
|
||||
@@ -66,7 +68,7 @@ public class InputLockUI implements Input {
|
||||
}
|
||||
|
||||
protected void showMessage(String message) {
|
||||
MatchUtil.getController().showPromptMessage(getOwner(), message);
|
||||
controller.getGui().showPromptMessage(getOwner(), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,7 +31,6 @@ import forge.player.PlayerControllerHuman;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.ThreadUtil;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -44,25 +43,23 @@ import forge.util.gui.SOptionPane;
|
||||
public class InputPassPriority extends InputSyncronizedBase {
|
||||
/** Constant <code>serialVersionUID=-581477682214137181L</code>. */
|
||||
private static final long serialVersionUID = -581477682214137181L;
|
||||
private final Player player;
|
||||
|
||||
private List<SpellAbility> chosenSa;
|
||||
|
||||
public InputPassPriority(final PlayerControllerHuman controller, final Player human) {
|
||||
public InputPassPriority(final PlayerControllerHuman controller) {
|
||||
super(controller);
|
||||
player = human;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public final void showMessage() {
|
||||
showMessage(getTurnPhasePriorityMessage(player.getGame()));
|
||||
showMessage(getTurnPhasePriorityMessage(getController().getGame()));
|
||||
chosenSa = null;
|
||||
if (getController().canUndoLastAction()) { //allow undoing with cancel button if can undo last action
|
||||
ButtonUtil.update(getOwner(), "OK", "Undo", true, true, true);
|
||||
getController().getGui().updateButtons(getOwner(), "OK", "Undo", true, true, true);
|
||||
}
|
||||
else { //otherwise allow ending turn with cancel button
|
||||
ButtonUtil.update(getOwner(), "OK", "End Turn", true, true, true);
|
||||
getController().getGui().updateButtons(getOwner(), "OK", "End Turn", true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +82,7 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
passPriority(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
player.getController().autoPassUntilEndOfTurn();
|
||||
getController().autoPassUntilEndOfTurn();
|
||||
stop();
|
||||
}
|
||||
});
|
||||
@@ -94,13 +91,13 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
|
||||
@Override
|
||||
protected boolean allowAwaitNextInput() {
|
||||
return chosenSa == null && !player.getController().mayAutoPass(); //don't allow awaiting next input if player chose to end the turn or if a spell/ability is chosen
|
||||
return chosenSa == null && !getController().mayAutoPass(); //don't allow awaiting next input if player chose to end the turn or if a spell/ability is chosen
|
||||
}
|
||||
|
||||
private void passPriority(final Runnable runnable) {
|
||||
if (FModel.getPreferences().getPrefBoolean(FPref.UI_MANA_LOST_PROMPT)) {
|
||||
//if gui player has mana floating that will be lost if phase ended right now, prompt before passing priority
|
||||
final Game game = player.getGame();
|
||||
final Game game = getController().getGame();
|
||||
if (game.getStack().isEmpty()) { //phase can't end right now if stack isn't empty
|
||||
Player player = game.getPhaseHandler().getPriorityPlayer();
|
||||
if (player != null && player.getManaPool().willManaBeLostAtEndOfPhase() && player.getLobbyPlayer() == GamePlayerUtil.getGuiPlayer()) {
|
||||
@@ -111,7 +108,7 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
if (FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN)) {
|
||||
message += " You will take mana burn damage equal to the amount of floating mana lost this way.";
|
||||
}
|
||||
if (SOptionPane.showOptionDialog(message, "Mana Floating", SOptionPane.WARNING_ICON, new String[]{"OK", "Cancel"}) == 0) {
|
||||
if (getController().getGui().showConfirmDialog(message, "Mana Floating", "Ok", "Cancel")) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
@@ -128,12 +125,12 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
@Override
|
||||
protected boolean onCardSelected(final Card card, final List<Card> otherCardsToSelect, final ITriggerEvent triggerEvent) {
|
||||
//remove unplayable unless triggerEvent specified, in which case unplayable may be shown as disabled options
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(player, triggerEvent == null);
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(getController().getPlayer(), triggerEvent == null);
|
||||
if (abilities.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final SpellAbility ability = player.getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
final SpellAbility ability = getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
if (ability != null) {
|
||||
chosenSa = new ArrayList<SpellAbility>();
|
||||
chosenSa.add(ability);
|
||||
@@ -141,7 +138,7 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
//if mana ability activated, activate same ability on other cards to select if possible
|
||||
String abStr = ability.toUnsuppressedString();
|
||||
for (Card c : otherCardsToSelect) {
|
||||
for (SpellAbility ab : c.getAllPossibleAbilities(player, true)) {
|
||||
for (SpellAbility ab : c.getAllPossibleAbilities(getController().getPlayer(), true)) {
|
||||
if (ab.toUnsuppressedString().equals(abStr)) {
|
||||
chosenSa.add(ab);
|
||||
break;
|
||||
@@ -155,12 +152,12 @@ public class InputPassPriority extends InputSyncronizedBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivateAction(Card card) {
|
||||
List<SpellAbility> abilities = card.getAllPossibleAbilities(player, true);
|
||||
public String getActivateAction(final Card card) {
|
||||
final List<SpellAbility> abilities = card.getAllPossibleAbilities(getController().getPlayer(), true);
|
||||
if (abilities.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
SpellAbility sa = abilities.get(0);
|
||||
final SpellAbility sa = abilities.get(0);
|
||||
if (sa.isSpell()) {
|
||||
return "cast spell";
|
||||
}
|
||||
|
||||
@@ -24,16 +24,13 @@ import forge.game.player.PlayerView;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.HumanPlay;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.Evaluator;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
|
||||
|
||||
public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
private static final long serialVersionUID = -9133423708688480255L;
|
||||
private static final long serialVersionUID = 718128600948280315L;
|
||||
|
||||
protected int phyLifeToLose = 0;
|
||||
|
||||
@@ -58,13 +55,13 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
|
||||
//if player is floating mana, show mana pool to make it easier to use that mana
|
||||
wasFloatingMana = !player.getManaPool().isEmpty();
|
||||
zoneToRestore = wasFloatingMana ? MatchUtil.getController().showManaPool(PlayerView.get(player)) : null;
|
||||
zoneToRestore = wasFloatingMana ? getController().getGui().showManaPool(PlayerView.get(player)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (wasFloatingMana) { //hide mana pool if it was shown due to floating mana
|
||||
MatchUtil.getController().hideManaPool(PlayerView.get(player), zoneToRestore);
|
||||
getController().getGui().hideManaPool(PlayerView.get(player), zoneToRestore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,9 +270,8 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
|
||||
final SpellAbility chosen;
|
||||
if (chosenAbility == null) {
|
||||
chosen = abilities.size() > 1 && choice ? SGuiChoose.one("Choose mana ability", abilities) : abilities.get(0);
|
||||
}
|
||||
else {
|
||||
chosen = abilities.size() > 1 && choice ? getController().getGui().one("Choose mana ability", abilities) : abilities.get(0);
|
||||
} else {
|
||||
chosen = chosenAbility;
|
||||
}
|
||||
ColorSet colors = ColorSet.fromMask(0 == colorNeeded ? colorCanUse : colorNeeded);
|
||||
@@ -387,10 +383,9 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
|
||||
protected void updateButtons() {
|
||||
if (supportAutoPay()) {
|
||||
ButtonUtil.update(getOwner(), "Auto", "Cancel", false, true, false);
|
||||
}
|
||||
else {
|
||||
ButtonUtil.update(getOwner(), "", "Cancel", false, true, false);
|
||||
getController().getGui().updateButtons(getOwner(), "Auto", "Cancel", false, true, false);
|
||||
} else {
|
||||
getController().getGui().updateButtons(getOwner(), "", "Cancel", false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +407,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
|
||||
canPayManaCost = proc.getResult();
|
||||
}
|
||||
if (canPayManaCost) { //enabled Auto button if mana cost can be paid
|
||||
ButtonUtil.update(getOwner(), "Auto", "Cancel", true, true, true);
|
||||
getController().getGui().updateButtons(getOwner(), "Auto", "Cancel", true, true, true);
|
||||
}
|
||||
}
|
||||
showMessage(getMessage());
|
||||
|
||||
@@ -4,10 +4,8 @@ import forge.control.FControlGamePlayback;
|
||||
import forge.game.Game;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.match.MatchUtil;
|
||||
|
||||
public class InputPlaybackControl extends InputSyncronizedBase implements InputSynchronized {
|
||||
public class InputPlaybackControl extends InputSyncronizedBase {
|
||||
private static final long serialVersionUID = 7979208993306642072L;
|
||||
|
||||
final FControlGamePlayback control;
|
||||
@@ -17,17 +15,12 @@ public class InputPlaybackControl extends InputSyncronizedBase implements InputS
|
||||
|
||||
private final Game game;
|
||||
public InputPlaybackControl(final Game game0, final FControlGamePlayback fControlGamePlayback) {
|
||||
super(null);
|
||||
super(fControlGamePlayback.getController());
|
||||
game = game0;
|
||||
control = fControlGamePlayback;
|
||||
setPause(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerView getOwner() {
|
||||
return MatchUtil.getHumanController().getLocalPlayerView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void showMessage() {
|
||||
setPause(false);
|
||||
@@ -39,8 +32,7 @@ public class InputPlaybackControl extends InputSyncronizedBase implements InputS
|
||||
if (isPaused) {
|
||||
showMessage(getTurnPhasePriorityMessage(game));
|
||||
currentTurn = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
final PhaseHandler ph = game.getPhaseHandler();
|
||||
if (currentTurn == ph.getTurn()) { return; }
|
||||
|
||||
@@ -49,13 +41,12 @@ public class InputPlaybackControl extends InputSyncronizedBase implements InputS
|
||||
}
|
||||
}
|
||||
|
||||
private void setPause(boolean pause) {
|
||||
private void setPause(final boolean pause) {
|
||||
isPaused = pause;
|
||||
if (isPaused) {
|
||||
ButtonUtil.update(getOwner(), "Resume", "Step", true, true, true);
|
||||
}
|
||||
else {
|
||||
ButtonUtil.update(getOwner(), "Pause", isFast ? "1x Speed" : "10x Faster", true, true, true);
|
||||
getController().getGui().updateButtons(null, "Resume", "Step", true, true, true);
|
||||
} else {
|
||||
getController().getGui().updateButtons(null, "Pause", isFast ? "1x Speed" : "10x Faster", true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
|
||||
public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
private static final long serialVersionUID = -1779224307654698954L;
|
||||
@@ -61,7 +60,7 @@ public final class InputProliferate extends InputSelectManyBase<GameEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
CounterType toAdd = choices.size() == 1 ? choices.get(0) : SGuiChoose.one("Select counter type", choices);
|
||||
CounterType toAdd = choices.size() == 1 ? choices.get(0) : getController().getGui().one("Select counter type", choices);
|
||||
chosenCounters.put(card, toAdd);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,10 @@ public class InputProxy implements Observer {
|
||||
game.getPhaseHandler().debugPrintState(), Singletons.getControl().getInputQueue().printInputStack());
|
||||
*/
|
||||
input.set(nextInput);
|
||||
Runnable showMessage = new Runnable() {
|
||||
if (!(nextInput instanceof InputLockUI)) {
|
||||
controller.getGui().setCurrentPlayer(nextInput.getOwner());
|
||||
}
|
||||
final Runnable showMessage = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Input current = getInput();
|
||||
@@ -70,7 +73,6 @@ public class InputProxy implements Observer {
|
||||
current.showMessageInitial();
|
||||
}
|
||||
};
|
||||
|
||||
FThreads.invokeInEdtLater(showMessage);
|
||||
}
|
||||
/**
|
||||
@@ -79,7 +81,7 @@ public class InputProxy implements Observer {
|
||||
* </p>
|
||||
*/
|
||||
public final void selectButtonOK() {
|
||||
Input inp = getInput();
|
||||
final Input inp = getInput();
|
||||
if (inp != null) {
|
||||
inp.selectButtonOK();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.concurrent.BlockingDeque;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
|
||||
/**
|
||||
@@ -35,11 +34,9 @@ import forge.player.PlayerControllerHuman;
|
||||
*/
|
||||
public class InputQueue extends Observable {
|
||||
private final BlockingDeque<InputSynchronized> inputStack = new LinkedBlockingDeque<InputSynchronized>();
|
||||
private final InputLockUI inputLock;
|
||||
private final Game game;
|
||||
|
||||
public InputQueue(final Game game, final InputProxy inputProxy) {
|
||||
inputLock = new InputLockUI(game, this);
|
||||
this.game = game;
|
||||
addObserver(inputProxy);
|
||||
}
|
||||
@@ -63,11 +60,11 @@ public class InputQueue extends Observable {
|
||||
}
|
||||
|
||||
public final Input getActualInput(final PlayerControllerHuman controller) {
|
||||
Input topMost = inputStack.peek(); // incoming input to Control
|
||||
if (topMost != null && !controller.getGame().isGameOver()) {
|
||||
final Input topMost = inputStack.peek(); // incoming input to Control
|
||||
if (topMost != null && !game.isGameOver()) {
|
||||
return topMost;
|
||||
}
|
||||
return inputLock;
|
||||
return new InputLockUI(game, this, controller);
|
||||
} // getInput()
|
||||
|
||||
// only for debug purposes
|
||||
@@ -76,23 +73,22 @@ public class InputQueue extends Observable {
|
||||
}
|
||||
|
||||
public void setInput(final InputSynchronized input) {
|
||||
if (MatchUtil.getHumanCount() > 1) { //update current player if needed
|
||||
MatchUtil.setCurrentPlayer(game.getPlayer(input.getOwner()));
|
||||
}
|
||||
//if (HostedMatch.getHumanCount() > 1) { //update current player if needed
|
||||
//HostedMatch.setCurrentPlayer(game.getPlayer(input.getOwner()));
|
||||
//}
|
||||
inputStack.push(input);
|
||||
InputBase.waitForOtherPlayer();
|
||||
syncPoint();
|
||||
updateObservers();
|
||||
}
|
||||
|
||||
public void syncPoint() {
|
||||
synchronized (inputLock) {
|
||||
void syncPoint() {
|
||||
synchronized (this) {
|
||||
// acquire and release lock, so that actions from Game thread happen before EDT reads their results
|
||||
}
|
||||
}
|
||||
|
||||
public void onGameOver(boolean releaseAllInputs) {
|
||||
for (InputSynchronized inp : inputStack) {
|
||||
public void onGameOver(final boolean releaseAllInputs) {
|
||||
for (final InputSynchronized inp : inputStack) {
|
||||
inp.relaseLatchWhenGameIsOver();
|
||||
if (!releaseAllInputs) {
|
||||
break;
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.google.common.collect.Iterables;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardView;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
|
||||
public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyncronizedBase {
|
||||
@@ -46,7 +45,7 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
|
||||
@Override
|
||||
public final void showMessage() {
|
||||
showMessage(getMessage());
|
||||
ButtonUtil.update(getOwner(), hasEnoughTargets(), allowCancel, true);
|
||||
getController().getGui().updateButtons(getOwner(), hasEnoughTargets(), allowCancel, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,14 +75,14 @@ public abstract class InputSelectManyBase<T extends GameEntity> extends InputSyn
|
||||
|
||||
protected void onSelectStateChanged(final GameEntity c, final boolean newState) {
|
||||
if (c instanceof Card) {
|
||||
MatchUtil.setUsedToPay(CardView.get((Card) c), newState); // UI supports card highlighting though this abstraction-breaking mechanism
|
||||
getController().getGui().setUsedToPay(CardView.get((Card) c), newState); // UI supports card highlighting though this abstraction-breaking mechanism
|
||||
}
|
||||
}
|
||||
|
||||
private void resetUsedToPay() {
|
||||
for (final GameEntity c : getSelected()) {
|
||||
if (c instanceof Card) {
|
||||
MatchUtil.setUsedToPay(CardView.get((Card) c), false);
|
||||
getController().getGui().setUsedToPay(CardView.get((Card) c), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,8 @@ import forge.game.card.CardView;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.player.PlayerControllerHuman;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
|
||||
|
||||
public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
private final List<Card> choices;
|
||||
@@ -70,19 +67,19 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
if (!tgt.isMinTargetsChosen(sa.getHostCard(), sa) || tgt.isDividedAsYouChoose()) {
|
||||
if (mandatory && tgt.hasCandidates(sa, true)) {
|
||||
// Player has to click on a target
|
||||
ButtonUtil.update(getOwner(), false, false, false);
|
||||
getController().getGui().updateButtons(getOwner(), false, false, false);
|
||||
}
|
||||
else {
|
||||
ButtonUtil.update(getOwner(), false, true, false);
|
||||
getController().getGui().updateButtons(getOwner(), false, true, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mandatory && tgt.hasCandidates(sa, true)) {
|
||||
// Player has to click on a target or ok
|
||||
ButtonUtil.update(getOwner(), true, false, true);
|
||||
getController().getGui().updateButtons(getOwner(), true, false, true);
|
||||
}
|
||||
else {
|
||||
ButtonUtil.update(getOwner(), true, true, true);
|
||||
getController().getGui().updateButtons(getOwner(), true, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +167,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(card.toString());
|
||||
Integer chosen = SGuiChoose.oneOrNone(sb.toString(), choices);
|
||||
final Integer chosen = getController().getGui().oneOrNone(sb.toString(), choices);
|
||||
if (chosen == null) {
|
||||
return true; //still return true since there was a valid choice
|
||||
}
|
||||
@@ -226,7 +223,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(apiBasedMessage);
|
||||
sb.append(player.getName());
|
||||
Integer chosen = SGuiChoose.oneOrNone(sb.toString(), choices);
|
||||
final Integer chosen = getController().getGui().oneOrNone(sb.toString(), choices);
|
||||
if (null == chosen) {
|
||||
return;
|
||||
}
|
||||
@@ -243,7 +240,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
private void addTarget(final GameEntity ge) {
|
||||
sa.getTargets().add(ge);
|
||||
if (ge instanceof Card) {
|
||||
MatchUtil.setUsedToPay(CardView.get((Card) ge), true);
|
||||
getController().getGui().setUsedToPay(CardView.get((Card) ge), true);
|
||||
lastTarget = (Card) ge;
|
||||
}
|
||||
final Integer val = targetDepth.get(ge);
|
||||
@@ -260,7 +257,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
private void done() {
|
||||
for (final GameEntity c : targetDepth.keySet()) {
|
||||
if (c instanceof Card) {
|
||||
MatchUtil.setUsedToPay(CardView.get((Card) c), false);
|
||||
getController().getGui().setUsedToPay(CardView.get((Card) c), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.Set;
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.ImageKeys;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.card.CardRarity;
|
||||
@@ -37,12 +38,11 @@ import forge.deck.Deck;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.GameType;
|
||||
import forge.game.GameView;
|
||||
import forge.game.Match;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IWinLoseView;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.model.FModel;
|
||||
import forge.planarconquest.ConquestPlaneData.RegionData;
|
||||
import forge.planarconquest.ConquestPreferences.CQPref;
|
||||
@@ -253,8 +253,8 @@ public class ConquestController {
|
||||
variants.add(GameType.Planechase);
|
||||
}
|
||||
|
||||
RegisteredPlayer humanStart = new RegisteredPlayer(commander.getDeck());
|
||||
RegisteredPlayer aiStart = new RegisteredPlayer(opponent.getDeck());
|
||||
final RegisteredPlayer humanStart = new RegisteredPlayer(commander.getDeck());
|
||||
final RegisteredPlayer aiStart = new RegisteredPlayer(opponent.getDeck());
|
||||
|
||||
if (isHumanDefending) { //give human a small life bonus if defending
|
||||
humanStart.setStartingLife(humanStart.getStartingLife() + prefs.getPrefInt(CQPref.DEFEND_BONUS_LIFE));
|
||||
@@ -276,28 +276,28 @@ public class ConquestController {
|
||||
aiPlayerName += " (AI)"; //ensure player names are distinct
|
||||
}
|
||||
|
||||
List<RegisteredPlayer> starter = new ArrayList<RegisteredPlayer>();
|
||||
final List<RegisteredPlayer> starter = new ArrayList<RegisteredPlayer>();
|
||||
humanPlayer = new LobbyPlayerHuman(humanPlayerName);
|
||||
humanPlayer.setAvatarCardImageKey(ImageKeys.getImageKey(commander.getCard(), false));
|
||||
starter.add(humanStart.setPlayer(humanPlayer));
|
||||
|
||||
LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1);
|
||||
final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1);
|
||||
aiPlayer.setAvatarCardImageKey(ImageKeys.getImageKey(opponent.getCard(), false));
|
||||
starter.add(aiStart.setPlayer(aiPlayer));
|
||||
|
||||
boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
|
||||
for(RegisteredPlayer rp : starter) {
|
||||
final boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
|
||||
for (final RegisteredPlayer rp : starter) {
|
||||
rp.setRandomFoil(useRandomFoil);
|
||||
}
|
||||
GameRules rules = new GameRules(GameType.PlanarConquest);
|
||||
final GameRules rules = new GameRules(GameType.PlanarConquest);
|
||||
rules.setGamesPerMatch(1); //only play one game at a time
|
||||
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
|
||||
rules.canCloneUseTargetsImage = FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE);
|
||||
final Match mc = new Match(rules, starter);
|
||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
MatchUtil.startGame(mc);
|
||||
hostedMatch.startMatch(rules, null, starter, humanStart, GuiBase.getInterface().getNewGuiGame());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import forge.LobbyPlayer;
|
||||
import forge.ai.AiProfileUtil;
|
||||
import forge.ai.LobbyPlayerAi;
|
||||
import forge.game.player.Player;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.model.FModel;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
@@ -87,17 +86,6 @@ public final class GamePlayerUtil {
|
||||
newPlayerName = getVerifiedPlayerName(getPlayerNameUsingStandardPrompt(oldPlayerName), oldPlayerName);
|
||||
}
|
||||
|
||||
//update name for player in active game if needed
|
||||
if (MatchUtil.getGame() != null) {
|
||||
for (Player player : MatchUtil.getGame().getPlayers()) {
|
||||
if (player.getLobbyPlayer() == MatchUtil.getGuiPlayer()) {
|
||||
player.setName(newPlayerName);
|
||||
player.getLobbyPlayer().setName(newPlayerName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FModel.getPreferences().setPref(FPref.PLAYER_NAME, newPlayerName);
|
||||
FModel.getPreferences().save();
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package forge.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -16,7 +24,34 @@ import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardPredicates.Presets;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.cost.*;
|
||||
import forge.game.cost.CostAddMana;
|
||||
import forge.game.cost.CostChooseCreatureType;
|
||||
import forge.game.cost.CostDamage;
|
||||
import forge.game.cost.CostDecisionMakerBase;
|
||||
import forge.game.cost.CostDiscard;
|
||||
import forge.game.cost.CostDraw;
|
||||
import forge.game.cost.CostExile;
|
||||
import forge.game.cost.CostExileFromStack;
|
||||
import forge.game.cost.CostExiledMoveToGrave;
|
||||
import forge.game.cost.CostFlipCoin;
|
||||
import forge.game.cost.CostGainControl;
|
||||
import forge.game.cost.CostGainLife;
|
||||
import forge.game.cost.CostMill;
|
||||
import forge.game.cost.CostPartMana;
|
||||
import forge.game.cost.CostPayLife;
|
||||
import forge.game.cost.CostPutCardToLib;
|
||||
import forge.game.cost.CostPutCounter;
|
||||
import forge.game.cost.CostRemoveAnyCounter;
|
||||
import forge.game.cost.CostRemoveCounter;
|
||||
import forge.game.cost.CostReturn;
|
||||
import forge.game.cost.CostReveal;
|
||||
import forge.game.cost.CostSacrifice;
|
||||
import forge.game.cost.CostTap;
|
||||
import forge.game.cost.CostTapType;
|
||||
import forge.game.cost.CostUnattach;
|
||||
import forge.game.cost.CostUntap;
|
||||
import forge.game.cost.CostUntapType;
|
||||
import forge.game.cost.PaymentDecision;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -28,11 +63,6 @@ import forge.util.Aggregates;
|
||||
import forge.util.FCollectionView;
|
||||
import forge.util.ITriggerEvent;
|
||||
import forge.util.Lang;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
import forge.util.gui.SGuiDialog;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
private final PlayerControllerHuman controller;
|
||||
@@ -298,18 +328,18 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return PaymentDecision.number(0);
|
||||
}
|
||||
final Game game = controller.getGame();
|
||||
final Player p = game.getPlayer(SGuiChoose.oneOrNone(String.format("Exile from whose %s?", cost.getFrom()), PlayerView.getCollection(payableZone)));
|
||||
final Player p = game.getPlayer(controller.getGui().oneOrNone(String.format("Exile from whose %s?", cost.getFrom()), PlayerView.getCollection(payableZone)));
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CardCollection typeList = CardLists.filter(list, CardPredicates.isOwner(p));
|
||||
int count = typeList.size();
|
||||
final CardCollection typeList = CardLists.filter(list, CardPredicates.isOwner(p));
|
||||
final int count = typeList.size();
|
||||
if (count < nNeeded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CardCollection toExile = game.getCardList(SGuiChoose.many("Exile from " + cost.getFrom(), "To be exiled", nNeeded, CardView.getCollection(typeList), null));
|
||||
final CardCollection toExile = game.getCardList(controller.getGui().many("Exile from " + cost.getFrom(), "To be exiled", nNeeded, CardView.getCollection(typeList), null));
|
||||
return PaymentDecision.card(toExile);
|
||||
}
|
||||
|
||||
@@ -357,7 +387,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
List<SpellAbility> exiled = new ArrayList<SpellAbility>();
|
||||
for (int i = 0; i < c; i++) {
|
||||
//Have to use the stack descriptions here because some copied spells have no description otherwise
|
||||
final String o = SGuiChoose.oneOrNone("Exile from Stack", descList);
|
||||
final String o = controller.getGui().oneOrNone("Exile from Stack", descList);
|
||||
|
||||
if (o != null) {
|
||||
final SpellAbility toExile = saList.get(descList.indexOf(o));
|
||||
@@ -393,7 +423,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
|
||||
CardCollection exiled = new CardCollection();
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = getCard(SGuiChoose.oneOrNone("Exile from " + cost.getFrom(), CardView.getCollection(typeList)));
|
||||
final Card c = getCard(controller.getGui().oneOrNone("Exile from " + cost.getFrom(), CardView.getCollection(typeList)));
|
||||
if (c == null) { return null; }
|
||||
|
||||
typeList.remove(c);
|
||||
@@ -422,7 +452,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
if (list.size() < c) {
|
||||
return null;
|
||||
}
|
||||
final CardCollection choice = controller.getGame().getCardList(SGuiChoose.many("Choose an exiled card to put into graveyard", "To graveyard", c, CardView.getCollection(list), CardView.get(source)));
|
||||
final CardCollection choice = controller.getGame().getCardList(controller.getGui().many("Choose an exiled card to put into graveyard", "To graveyard", c, CardView.getCollection(list), CardView.get(source)));
|
||||
return PaymentDecision.card(choice);
|
||||
}
|
||||
|
||||
@@ -494,7 +524,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(source.getName()).append(" - Choose an opponent to gain ").append(c).append(" life:");
|
||||
|
||||
final Player chosenToGain = controller.getGame().getPlayer(SGuiChoose.oneOrNone(sb.toString(), PlayerView.getCollection(oppsThatCanGainLife)));
|
||||
final Player chosenToGain = controller.getGame().getPlayer(controller.getGui().oneOrNone(sb.toString(), PlayerView.getCollection(oppsThatCanGainLife)));
|
||||
if (chosenToGain == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -604,7 +634,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
|
||||
CardCollection chosen = new CardCollection();
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = getCard(SGuiChoose.oneOrNone("Put from " + fromZone + " to library", CardView.getCollection(typeList)));
|
||||
final Card c = getCard(controller.getGui().oneOrNone("Put from " + fromZone + " to library", CardView.getCollection(typeList)));
|
||||
if (c == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -619,7 +649,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return PaymentDecision.number(0);
|
||||
}
|
||||
|
||||
final Player p = controller.getGame().getPlayer(SGuiChoose.oneOrNone(String.format("Put cards from whose %s?", fromZone), PlayerView.getCollection(payableZone)));
|
||||
final Player p = controller.getGame().getPlayer(controller.getGui().oneOrNone(String.format("Put cards from whose %s?", fromZone), PlayerView.getCollection(payableZone)));
|
||||
if (p == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -631,7 +661,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
|
||||
CardCollection chosen = new CardCollection();
|
||||
for (int i = 0; i < nNeeded; i++) {
|
||||
final Card c = getCard(SGuiChoose.oneOrNone("Put cards from " + fromZone + " to Library", CardView.getCollection(typeList)));
|
||||
final Card c = getCard(controller.getGui().oneOrNone("Put cards from " + fromZone + " to Library", CardView.getCollection(typeList)));
|
||||
if (c == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -805,7 +835,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
}
|
||||
|
||||
String prompt = "Select type counters to remove";
|
||||
cost.setCounterType(SGuiChoose.one(prompt, typeChoices));
|
||||
cost.setCounterType(controller.getGui().one(prompt, typeChoices));
|
||||
|
||||
return PaymentDecision.card(selected, cost.getCounter());
|
||||
}
|
||||
@@ -903,7 +933,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
int maxCounters = source.getCounters(cost.counter);
|
||||
if (amount.equals("All")) {
|
||||
final CardView view = CardView.get(ability.getHostCard());
|
||||
if (!SGuiDialog.confirm(view, "Remove all counters?")) {
|
||||
if (!controller.getGui().confirm(view, "Remove all counters?")) {
|
||||
return null;
|
||||
}
|
||||
cntRemoved = maxCounters;
|
||||
@@ -959,7 +989,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
}
|
||||
}
|
||||
|
||||
final Card card = getCard(SGuiChoose.oneOrNone("Remove counter(s) from a card in " + cost.zone, suspended));
|
||||
final Card card = getCard(controller.getGui().oneOrNone("Remove counter(s) from a card in " + cost.zone, suspended));
|
||||
return null == card ? null : PaymentDecision.card(card, c);
|
||||
}
|
||||
|
||||
|
||||
@@ -450,7 +450,7 @@ public class HumanPlay {
|
||||
}
|
||||
if (typeChoices.size() > 1) {
|
||||
String cprompt = "Select type counters to remove";
|
||||
counterType = SGuiChoose.one(cprompt, typeChoices);
|
||||
counterType = controller.getGui().one(cprompt, typeChoices);
|
||||
}
|
||||
else {
|
||||
counterType = typeChoices.get(0);
|
||||
|
||||
@@ -5,7 +5,6 @@ import forge.game.Game;
|
||||
import forge.game.player.IGameEntitiesFactory;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.util.GuiDisplayUtil;
|
||||
|
||||
public class LobbyPlayerHuman extends LobbyPlayer implements IGameEntitiesFactory {
|
||||
@@ -19,14 +18,14 @@ public class LobbyPlayerHuman extends LobbyPlayer implements IGameEntitiesFactor
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player createIngamePlayer(Game game, final int id) {
|
||||
Player player = new Player(GuiDisplayUtil.personalizeHuman(getName()), game, id);
|
||||
PlayerControllerHuman controller = new PlayerControllerHuman(game, player, this);
|
||||
public Player createIngamePlayer(final Game game, final int id) {
|
||||
final Player player = new Player(GuiDisplayUtil.personalizeHuman(getName()), game, id);
|
||||
final PlayerControllerHuman controller = new PlayerControllerHuman(game, player, this);
|
||||
player.setFirstController(controller);
|
||||
return player;
|
||||
}
|
||||
|
||||
public void hear(LobbyPlayer player, String message) {
|
||||
MatchUtil.getController().hear(player, message);
|
||||
//ostedMatch.getController().hear(player, message);
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import forge.control.FControlGamePlayback;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.events.UiEventNextGameDecision;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityView;
|
||||
@@ -63,7 +64,6 @@ import forge.game.cost.Cost;
|
||||
import forge.game.cost.CostPart;
|
||||
import forge.game.cost.CostPartMana;
|
||||
import forge.game.mana.Mana;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.DelayedReveal;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
@@ -80,13 +80,14 @@ import forge.game.trigger.WrappedAbility;
|
||||
import forge.game.zone.MagicStack;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.interfaces.IDevModeCheats;
|
||||
import forge.interfaces.IGameController;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.PaperCard;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.input.ButtonUtil;
|
||||
import forge.match.NextGameDecision;
|
||||
import forge.match.input.Input;
|
||||
import forge.match.input.InputAttack;
|
||||
import forge.match.input.InputBase;
|
||||
import forge.match.input.InputBlock;
|
||||
import forge.match.input.InputConfirm;
|
||||
import forge.match.input.InputConfirmMulligan;
|
||||
@@ -107,8 +108,6 @@ import forge.util.ITriggerEvent;
|
||||
import forge.util.Lang;
|
||||
import forge.util.MessageUtil;
|
||||
import forge.util.TextUtil;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
import forge.util.gui.SGuiDialog;
|
||||
import forge.util.gui.SOptionPane;
|
||||
|
||||
/**
|
||||
@@ -116,7 +115,9 @@ import forge.util.gui.SOptionPane;
|
||||
*
|
||||
* Handles phase skips for now.
|
||||
*/
|
||||
public class PlayerControllerHuman extends PlayerController {
|
||||
public class PlayerControllerHuman
|
||||
extends PlayerController
|
||||
implements IGameController {
|
||||
/**
|
||||
* Cards this player may look at right now, for example when searching a
|
||||
* library.
|
||||
@@ -124,20 +125,29 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
private boolean mayLookAtAllCards = false;
|
||||
private boolean disableAutoYields = false;
|
||||
|
||||
private IGuiGame gui;
|
||||
|
||||
protected final InputQueue inputQueue;
|
||||
protected final InputProxy inputProxy;
|
||||
|
||||
public PlayerControllerHuman(Game game0, Player p, LobbyPlayer lp) {
|
||||
public PlayerControllerHuman(final Game game0, final Player p, final LobbyPlayer lp) {
|
||||
super(game0, p, lp);
|
||||
inputProxy = new InputProxy(this);
|
||||
inputQueue = new InputQueue(game, inputProxy);
|
||||
}
|
||||
public PlayerControllerHuman(Player p, LobbyPlayer lp, PlayerControllerHuman owner) {
|
||||
public PlayerControllerHuman(final Player p, final LobbyPlayer lp, final PlayerControllerHuman owner) {
|
||||
super(owner.getGame(), p, lp);
|
||||
gui = owner.gui;
|
||||
inputProxy = owner.inputProxy;
|
||||
inputQueue = owner.getInputQueue();
|
||||
}
|
||||
|
||||
public final IGuiGame getGui() {
|
||||
return gui;
|
||||
}
|
||||
public final void setGui(final IGuiGame gui) {
|
||||
this.gui = gui;
|
||||
}
|
||||
|
||||
public final InputQueue getInputQueue() {
|
||||
return inputQueue;
|
||||
}
|
||||
@@ -147,7 +157,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
|
||||
public PlayerView getLocalPlayerView() {
|
||||
return player.getView();
|
||||
return player == null ? null : player.getView();
|
||||
}
|
||||
|
||||
public boolean getDisableAutoYields() {
|
||||
@@ -157,12 +167,13 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
disableAutoYields = disableAutoYields0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayLookAtAllCards() {
|
||||
return mayLookAtAllCards;
|
||||
}
|
||||
|
||||
private final HashSet<Card> tempShownCards = new HashSet<Card>();
|
||||
public <T> void tempShow(Iterable<T> objects) {
|
||||
public <T> void tempShow(final Iterable<T> objects) {
|
||||
for (final T t : objects) {
|
||||
if (t instanceof Card) {
|
||||
// assume you may see any card passed through here
|
||||
@@ -170,22 +181,22 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
}
|
||||
}
|
||||
private void tempShowCard(Card c) {
|
||||
private void tempShowCard(final Card c) {
|
||||
if (c == null) { return; }
|
||||
tempShownCards.add(c);
|
||||
c.setMayLookAt(player, true, true);
|
||||
}
|
||||
private void tempShowCards(Iterable<Card> cards) {
|
||||
private void tempShowCards(final Iterable<Card> cards) {
|
||||
if (mayLookAtAllCards) { return; } //no needed if this is set
|
||||
|
||||
for (Card c : cards) {
|
||||
for (final Card c : cards) {
|
||||
tempShowCard(c);
|
||||
}
|
||||
}
|
||||
private void endTempShowCards() {
|
||||
if (tempShownCards.isEmpty()) { return; }
|
||||
|
||||
for (Card c : tempShownCards) {
|
||||
for (final Card c : tempShownCards) {
|
||||
c.setMayLookAt(player, false, true);
|
||||
}
|
||||
tempShownCards.clear();
|
||||
@@ -202,15 +213,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
this.mayLookAtAllCards = mayLookAtAllCards;
|
||||
}
|
||||
|
||||
public boolean isUiSetToSkipPhase(final Player turn, final PhaseType phase) {
|
||||
return !MatchUtil.getController().stopAtPhase(PlayerView.get(turn), phase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses GUI to learn which spell the player (human in our case) would like to play
|
||||
*/
|
||||
public SpellAbility getAbilityToPlay(final List<SpellAbility> abilities, final ITriggerEvent triggerEvent) {
|
||||
return MatchUtil.getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
return getGui().getAbilityToPlay(abilities, triggerEvent);
|
||||
//return HostedMatch.getController().getAbilityToPlay(abilities, triggerEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -258,11 +266,11 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
else {
|
||||
errMsg = String.format("Too many cards in your sideboard (maximum %d), please make modifications to your deck again.", sbMax);
|
||||
}
|
||||
SOptionPane.showErrorDialog(errMsg, "Invalid Deck");
|
||||
getGui().showErrorDialog(errMsg, "Invalid Deck");
|
||||
}
|
||||
// Sideboard rules have changed for M14, just need to consider min maindeck and max sideboard sizes
|
||||
// No longer need 1:1 sideboarding in non-limited formats
|
||||
newMain = GuiBase.getInterface().sideboard(sideboard, main);
|
||||
newMain = getGui().sideboard(sideboard, main);
|
||||
} while (conform && (newMain.size() < deckMinSize || combinedDeckSize - newMain.size() > sbMax));
|
||||
|
||||
return newMain;
|
||||
@@ -283,7 +291,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if ((attacker.hasKeyword("Trample") && defender != null) || (blockers.size() > 1)) {
|
||||
final CardView vAttacker = CardView.get(attacker);
|
||||
final GameEntityView vDefender = GameEntityView.get(defender);
|
||||
final Map<CardView, Integer> result = MatchUtil.getDamageToAssign(vAttacker, vBlockers, damageDealt, vDefender, overrideOrder);
|
||||
final Map<CardView, Integer> result = getGui().assignDamage(vAttacker, vBlockers, damageDealt, vDefender, overrideOrder);
|
||||
for (final Entry<CardView, Integer> e : result.entrySet()) {
|
||||
map.put(game.getCard(e.getKey()), e.getValue());
|
||||
}
|
||||
@@ -298,13 +306,13 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
private final boolean assignDamageAsIfNotBlocked(final Card attacker) {
|
||||
return attacker.hasKeyword("CARDNAME assigns its combat damage as though it weren't blocked.")
|
||||
|| (attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.")
|
||||
&& SGuiDialog.confirm(CardView.get(attacker), "Do you want to assign its combat damage as though it weren't blocked?"));
|
||||
&& getGui().confirm(CardView.get(attacker), "Do you want to assign its combat damage as though it weren't blocked?"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer announceRequirements(SpellAbility ability, String announce, boolean canChooseZero) {
|
||||
int min = canChooseZero ? 0 : 1;
|
||||
return SGuiChoose.getInteger("Choose " + announce + " for " + ability.getHostCard().getName(),
|
||||
return getGui().getInteger("Choose " + announce + " for " + ability.getHostCard().getName(),
|
||||
min, Integer.MAX_VALUE, min + 9);
|
||||
}
|
||||
|
||||
@@ -347,7 +355,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
return singleChosen == null ? CardCollection.EMPTY : new CardCollection(singleChosen);
|
||||
}
|
||||
|
||||
MatchUtil.getController().setPanelSelection(CardView.get(sa.getHostCard()));
|
||||
getGui().setPanelSelection(CardView.get(sa.getHostCard()));
|
||||
|
||||
// try to use InputSelectCardsFromList when possible
|
||||
boolean cardsAreInMyHandOrBattlefield = true;
|
||||
@@ -369,7 +377,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
|
||||
tempShowCards(sourceList);
|
||||
final CardCollection choices = getGame().getCardList(SGuiChoose.many(title, "Chosen Cards", min, max, CardView.getCollection(sourceList), CardView.get(sa.getHostCard())));
|
||||
final CardCollection choices = getGame().getCardList(getGui().many(title, "Chosen Cards", min, max, CardView.getCollection(sourceList), CardView.get(sa.getHostCard())));
|
||||
endTempShowCards();
|
||||
|
||||
return choices;
|
||||
@@ -417,7 +425,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
return Iterables.getFirst(input.getSelected(), null);
|
||||
}
|
||||
|
||||
final GameEntityView result = GuiBase.getInterface().chooseSingleEntityForEffect(title, optionList, delayedReveal, isOptional, this);
|
||||
final GameEntityView result = getGui().chooseSingleEntityForEffect(title, optionList, delayedReveal, isOptional, this);
|
||||
endTempShowCards(); //assume tempShow called by GuiBase.getInterface().chooseSingleEntityForEffect
|
||||
if (result instanceof CardView) {
|
||||
return (T) game.getCard((CardView)result);
|
||||
@@ -437,12 +445,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
for (int i = 0; i <= max - min; i++) {
|
||||
choices[i] = Integer.valueOf(i + min);
|
||||
}
|
||||
return SGuiChoose.one(title, choices).intValue();
|
||||
return getGui().one(title, choices).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int chooseNumber(SpellAbility sa, String title, List<Integer> choices, Player relatedPlayer) {
|
||||
return SGuiChoose.one(title, choices).intValue();
|
||||
return getGui().one(title, choices).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -452,7 +460,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
|
||||
// Human is supposed to read the message and understand from it what to choose
|
||||
return SGuiChoose.one(title, spells);
|
||||
return getGui().one(title, spells);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -460,26 +468,26 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
*/
|
||||
@Override
|
||||
public boolean confirmAction(SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||
return SGuiDialog.confirm(CardView.get(sa.getHostCard()), message);
|
||||
return getGui().confirm(CardView.get(sa.getHostCard()), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirmBidAction(SpellAbility sa, PlayerActionConfirmMode bidlife,
|
||||
String string, int bid, Player winner) {
|
||||
return SGuiDialog.confirm(CardView.get(sa.getHostCard()), string + " Highest Bidder " + winner);
|
||||
return getGui().confirm(CardView.get(sa.getHostCard()), string + " Highest Bidder " + winner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
||||
return SGuiDialog.confirm(CardView.get(hostCard), message);
|
||||
return getGui().confirm(CardView.get(hostCard), message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean confirmTrigger(SpellAbility sa, Trigger regtrig, Map<String, String> triggerParams, boolean isMandatory) {
|
||||
if (this.shouldAlwaysAcceptTrigger(regtrig.getId())) {
|
||||
if (getGui().shouldAlwaysAcceptTrigger(regtrig.getId())) {
|
||||
return true;
|
||||
}
|
||||
if (this.shouldAlwaysDeclineTrigger(regtrig.getId())) {
|
||||
if (getGui().shouldAlwaysDeclineTrigger(regtrig.getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -535,22 +543,22 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
@Override
|
||||
public CardCollection orderBlockers(final Card attacker, final CardCollection blockers) {
|
||||
final CardView vAttacker = CardView.get(attacker);
|
||||
MatchUtil.getController().setPanelSelection(vAttacker);
|
||||
return game.getCardList(SGuiChoose.order("Choose Damage Order for " + vAttacker, "Damaged First", CardView.getCollection(blockers), vAttacker));
|
||||
getGui().setPanelSelection(vAttacker);
|
||||
return game.getCardList(getGui().order("Choose Damage Order for " + vAttacker, "Damaged First", CardView.getCollection(blockers), vAttacker));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardCollection orderBlocker(final Card attacker, final Card blocker, final CardCollection oldBlockers) {
|
||||
final CardView vAttacker = CardView.get(attacker);
|
||||
MatchUtil.getController().setPanelSelection(vAttacker);
|
||||
return game.getCardList(SGuiChoose.insertInList("Choose blocker after which to place " + vAttacker + " in damage order; cancel to place it first", CardView.get(blocker), CardView.getCollection(oldBlockers)));
|
||||
getGui().setPanelSelection(vAttacker);
|
||||
return game.getCardList(getGui().insertInList("Choose blocker after which to place " + vAttacker + " in damage order; cancel to place it first", CardView.get(blocker), CardView.getCollection(oldBlockers)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardCollection orderAttackers(final Card blocker, final CardCollection attackers) {
|
||||
final CardView vBlocker = CardView.get(blocker);
|
||||
MatchUtil.getController().setPanelSelection(vBlocker);
|
||||
return game.getCardList(SGuiChoose.order("Choose Damage Order for " + vBlocker, "Damaged First", CardView.getCollection(attackers), vBlocker));
|
||||
getGui().setPanelSelection(vBlocker);
|
||||
return game.getCardList(getGui().order("Choose Damage Order for " + vBlocker, "Damaged First", CardView.getCollection(attackers), vBlocker));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -564,11 +572,11 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
String fm = MessageUtil.formatMessage(message, player, owner);
|
||||
if (!cards.isEmpty()) {
|
||||
tempShowCards(cards);
|
||||
SGuiChoose.reveal(fm, CardView.getCollection(cards));
|
||||
getGui().reveal(fm, CardView.getCollection(cards));
|
||||
endTempShowCards();
|
||||
}
|
||||
else {
|
||||
SGuiDialog.message(MessageUtil.formatMessage("There are no cards in {player's} " +
|
||||
getGui().message(MessageUtil.formatMessage("There are no cards in {player's} " +
|
||||
zone.name().toLowerCase(), player, owner), fm);
|
||||
}
|
||||
}
|
||||
@@ -588,7 +596,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
}
|
||||
else {
|
||||
toBottom = game.getCardList(SGuiChoose.many("Select cards to be put on the bottom of your library", "Cards to put on the bottom", -1, CardView.getCollection(topN), null));
|
||||
toBottom = game.getCardList(getGui().many("Select cards to be put on the bottom of your library", "Cards to put on the bottom", -1, CardView.getCollection(topN), null));
|
||||
topN.removeAll((Collection<?>)toBottom);
|
||||
if (topN.isEmpty()) {
|
||||
toTop = null;
|
||||
@@ -597,7 +605,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
toTop = topN;
|
||||
}
|
||||
else {
|
||||
toTop = game.getCardList(SGuiChoose.order("Arrange cards to be put on top of your library", "Top of Library", CardView.getCollection(topN), null));
|
||||
toTop = game.getCardList(getGui().order("Arrange cards to be put on top of your library", "Top of Library", CardView.getCollection(topN), null));
|
||||
}
|
||||
}
|
||||
endTempShowCards();
|
||||
@@ -609,7 +617,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
final CardView view = CardView.get(c);
|
||||
|
||||
tempShowCard(c);
|
||||
boolean result = SGuiDialog.confirm(view, "Put " + view + " on the top or bottom of your library?", new String[]{"Top", "Bottom"});
|
||||
final boolean result = getGui().confirm(view, "Put " + view + " on the top or bottom of your library?", new String[]{"Top", "Bottom"});
|
||||
endTempShowCards();
|
||||
|
||||
return result;
|
||||
@@ -621,22 +629,22 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
tempShowCards(cards);
|
||||
switch (destinationZone) {
|
||||
case Library:
|
||||
choices = SGuiChoose.order("Choose order of cards to put into the library", "Closest to top", CardView.getCollection(cards), null);
|
||||
choices = getGui().order("Choose order of cards to put into the library", "Closest to top", CardView.getCollection(cards), null);
|
||||
break;
|
||||
case Battlefield:
|
||||
choices = SGuiChoose.order("Choose order of cards to put onto the battlefield", "Put first", CardView.getCollection(cards), null);
|
||||
choices = getGui().order("Choose order of cards to put onto the battlefield", "Put first", CardView.getCollection(cards), null);
|
||||
break;
|
||||
case Graveyard:
|
||||
choices = SGuiChoose.order("Choose order of cards to put into the graveyard", "Closest to bottom", CardView.getCollection(cards), null);
|
||||
choices = getGui().order("Choose order of cards to put into the graveyard", "Closest to bottom", CardView.getCollection(cards), null);
|
||||
break;
|
||||
case PlanarDeck:
|
||||
choices = SGuiChoose.order("Choose order of cards to put into the planar deck", "Closest to top", CardView.getCollection(cards), null);
|
||||
choices = getGui().order("Choose order of cards to put into the planar deck", "Closest to top", CardView.getCollection(cards), null);
|
||||
break;
|
||||
case SchemeDeck:
|
||||
choices = SGuiChoose.order("Choose order of cards to put into the scheme deck", "Closest to top", CardView.getCollection(cards), null);
|
||||
choices = getGui().order("Choose order of cards to put into the scheme deck", "Closest to top", CardView.getCollection(cards), null);
|
||||
break;
|
||||
case Stack:
|
||||
choices = SGuiChoose.order("Choose order of copies to cast", "Put first", CardView.getCollection(cards), null);
|
||||
choices = getGui().order("Choose order of copies to cast", "Put first", CardView.getCollection(cards), null);
|
||||
break;
|
||||
default:
|
||||
System.out.println("ZoneType " + destinationZone + " - Not Ordered");
|
||||
@@ -651,7 +659,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
public CardCollectionView chooseCardsToDiscardFrom(Player p, SpellAbility sa, CardCollection valid, int min, int max) {
|
||||
if (p != player) {
|
||||
tempShowCards(valid);
|
||||
final CardCollection choices = game.getCardList(SGuiChoose.many("Choose " + min + " card" + (min != 1 ? "s" : "") + " to discard",
|
||||
final CardCollection choices = game.getCardList(getGui().many("Choose " + min + " card" + (min != 1 ? "s" : "") + " to discard",
|
||||
"Discarded", min, min, CardView.getCollection(valid), null));
|
||||
endTempShowCards();
|
||||
return choices;
|
||||
@@ -666,7 +674,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
@Override
|
||||
public void playMiracle(final SpellAbility miracle, final Card card) {
|
||||
final CardView view = CardView.get(card);
|
||||
if (SGuiDialog.confirm(view, view + " - Drawn. Play for Miracle Cost?")) {
|
||||
if (getGui().confirm(view, view + " - Drawn. Play for Miracle Cost?")) {
|
||||
HumanPlay.playSpellAbility(this, player, miracle);
|
||||
}
|
||||
}
|
||||
@@ -683,9 +691,9 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
cntChoice[i] = Integer.valueOf(i);
|
||||
}
|
||||
|
||||
final Integer chosenAmount = SGuiChoose.one("Delve how many cards?", cntChoice);
|
||||
final Integer chosenAmount = getGui().one("Delve how many cards?", cntChoice);
|
||||
for (int i = 0; i < chosenAmount; i++) {
|
||||
final CardView nowChosen = SGuiChoose.oneOrNone("Exile which card?", CardView.getCollection(grave));
|
||||
final CardView nowChosen = getGui().oneOrNone("Exile which card?", CardView.getCollection(grave));
|
||||
|
||||
if (nowChosen == null) {
|
||||
// User canceled,abort delving.
|
||||
@@ -754,7 +762,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
Mana m = manaChoices.get(i);
|
||||
options.add(String.format("%d. %s mana from %s", 1+i, MagicColor.toLongString(m.getColor()), m.getSourceCard()));
|
||||
}
|
||||
String chosen = SGuiChoose.one("Pay Mana from Mana Pool", options);
|
||||
String chosen = getGui().one("Pay Mana from Mana Pool", options);
|
||||
String idx = TextUtil.split(chosen, '.')[0];
|
||||
return manaChoices.get(Integer.parseInt(idx)-1);
|
||||
}
|
||||
@@ -769,14 +777,14 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
Iterables.removeAll(types, invalidTypes);
|
||||
}
|
||||
if (isOptional) {
|
||||
return SGuiChoose.oneOrNone("Choose a " + kindOfType.toLowerCase() + " type", types);
|
||||
return getGui().oneOrNone("Choose a " + kindOfType.toLowerCase() + " type", types);
|
||||
}
|
||||
return SGuiChoose.one("Choose a " + kindOfType.toLowerCase() + " type", types);
|
||||
return getGui().one("Choose a " + kindOfType.toLowerCase() + " type", types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object vote(SpellAbility sa, String prompt, List<Object> options, ArrayListMultimap<Object, Player> votes) {
|
||||
return SGuiChoose.one(prompt, options);
|
||||
return getGui().one(prompt, options);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@@ -784,7 +792,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
*/
|
||||
@Override
|
||||
public boolean confirmReplacementEffect(ReplacementEffect replacementEffect, SpellAbility effectSA, String question) {
|
||||
return SGuiDialog.confirm(CardView.get(replacementEffect.getHostCard()), question);
|
||||
return getGui().confirm(CardView.get(replacementEffect.getHostCard()), question);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -795,7 +803,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void declareAttackers(Player attackingPlayer, Combat combat) {
|
||||
public void declareAttackers(final Player attackingPlayer, final Combat combat) {
|
||||
if (mayAutoPass()) {
|
||||
if (CombatUtil.validateAttackers(combat)) {
|
||||
return; //don't prompt to declare attackers if user chose to end the turn and not attacking is legal
|
||||
@@ -814,41 +822,13 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
// This input should not modify combat object itself, but should return user choice
|
||||
final InputBlock inpBlock = new InputBlock(this, defender, combat);
|
||||
inpBlock.showAndWait();
|
||||
updateAutoPassPrompt();
|
||||
getGui().updateAutoPassPrompt();
|
||||
}
|
||||
|
||||
public void updateAutoPassPrompt() {
|
||||
if (mayAutoPass()) {
|
||||
//allow user to cancel auto-pass
|
||||
InputBase.cancelAwaitNextInput(); //don't overwrite prompt with awaiting opponent
|
||||
PhaseType phase = getAutoPassUntilPhase();
|
||||
MatchUtil.getController().showPromptMessage(player.getView(), "Yielding until " + (phase == PhaseType.CLEANUP ? "end of turn" : phase.nameForUi.toString()) +
|
||||
".\nYou may cancel this yield to take an action.");
|
||||
ButtonUtil.update(player.getView(), false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autoPassUntilEndOfTurn() {
|
||||
super.autoPassUntilEndOfTurn();
|
||||
updateAutoPassPrompt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autoPassCancel() {
|
||||
if (getAutoPassUntilPhase() == null) { return; }
|
||||
super.autoPassCancel();
|
||||
|
||||
//prevent prompt getting stuck on yielding message while actually waiting for next input opportunity
|
||||
PlayerView playerView = getLocalPlayerView();
|
||||
MatchUtil.getController().showPromptMessage(playerView, "");
|
||||
ButtonUtil.update(playerView, false, false, false);
|
||||
InputBase.awaitNextInput(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SpellAbility> chooseSpellAbilityToPlay() {
|
||||
MagicStack stack = game.getStack();
|
||||
final MagicStack stack = game.getStack();
|
||||
|
||||
if (mayAutoPass()) {
|
||||
//avoid prompting for input if current phase is set to be auto-passed
|
||||
@@ -856,7 +836,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
int delay = 0;
|
||||
if (stack.isEmpty()) {
|
||||
//make sure to briefly pause at phases you're not set up to skip
|
||||
if (!isUiSetToSkipPhase(game.getPhaseHandler().getPlayerTurn(), game.getPhaseHandler().getPhase())) {
|
||||
if (!getGui().isUiSetToSkipPhase(game.getPhaseHandler().getPlayerTurn().getView(), game.getPhaseHandler().getPhase())) {
|
||||
delay = FControlGamePlayback.phasesDelay;
|
||||
}
|
||||
}
|
||||
@@ -876,13 +856,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
|
||||
if (stack.isEmpty()) {
|
||||
if (isUiSetToSkipPhase(game.getPhaseHandler().getPlayerTurn(), game.getPhaseHandler().getPhase())) {
|
||||
if (getGui().isUiSetToSkipPhase(game.getPhaseHandler().getPlayerTurn().getView(), game.getPhaseHandler().getPhase())) {
|
||||
return null; //avoid prompt for input if stack is empty and player is set to skip the current phase
|
||||
}
|
||||
}
|
||||
else if (!game.getDisableAutoYields()) {
|
||||
SpellAbility ability = stack.peekAbility();
|
||||
if (ability != null && ability.isAbility() && shouldAutoYield(ability.toUnsuppressedString())) {
|
||||
} else {
|
||||
final SpellAbility ability = stack.peekAbility();
|
||||
if (ability != null && ability.isAbility() && getGui().shouldAutoYield(ability.toUnsuppressedString())) {
|
||||
//avoid prompt for input if top ability of stack is set to auto-yield
|
||||
try {
|
||||
Thread.sleep(FControlGamePlayback.resolveDelay);
|
||||
@@ -894,7 +873,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
}
|
||||
|
||||
InputPassPriority defaultInput = new InputPassPriority(this, player);
|
||||
final InputPassPriority defaultInput = new InputPassPriority(this);
|
||||
defaultInput.showAndWait();
|
||||
return defaultInput.getChosenSa();
|
||||
}
|
||||
@@ -946,7 +925,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if (srcCards.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
final List<CardView> chosen = SGuiChoose.many("Choose cards to activate from opening hand and their order", "Activate first", -1, CardView.getCollection(srcCards), null);
|
||||
final List<CardView> chosen = getGui().many("Choose cards to activate from opening hand and their order", "Activate first", -1, CardView.getCollection(srcCards), null);
|
||||
for (final CardView view : chosen) {
|
||||
final Card c = game.getCard(view);
|
||||
for (SpellAbility sa : usableFromOpeningHand) {
|
||||
@@ -971,7 +950,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
case PlayOrDraw: labels = new String[]{"Play", "Draw"}; break;
|
||||
default: labels = kindOfChoice.toString().split("Or");
|
||||
}
|
||||
return SGuiDialog.confirm(CardView.get(sa.getHostCard()), question, defaultVal == null || defaultVal.booleanValue(), labels);
|
||||
return getGui().confirm(CardView.get(sa.getHostCard()), question, defaultVal == null || defaultVal.booleanValue(), labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -981,13 +960,13 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
for (int i = 0; i < results.length; i++) {
|
||||
strResults[i] = labelsSrc[results[i] ? 0 : 1];
|
||||
}
|
||||
return SGuiChoose.one(sa.getHostCard().getName() + " - Choose a result", strResults).equals(labelsSrc[0]);
|
||||
return getGui().one(sa.getHostCard().getName() + " - Choose a result", strResults).equals(labelsSrc[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Card chooseProtectionShield(GameEntity entityBeingDamaged, List<String> options, Map<String, Card> choiceMap) {
|
||||
String title = entityBeingDamaged + " - select which prevention shield to use";
|
||||
return choiceMap.get(SGuiChoose.one(title, options));
|
||||
return choiceMap.get(getGui().one(title, options));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -998,12 +977,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
|
||||
String counterChoiceTitle = "Choose a counter type on " + cardWithCounter;
|
||||
final CounterType chosen = SGuiChoose.one(counterChoiceTitle, cardWithCounter.getCounters().keySet());
|
||||
final CounterType chosen = getGui().one(counterChoiceTitle, cardWithCounter.getCounters().keySet());
|
||||
|
||||
String putOrRemoveTitle = "What to do with that '" + chosen.getName() + "' counter ";
|
||||
final String putString = "Put another " + chosen.getName() + " counter on " + cardWithCounter;
|
||||
final String removeString = "Remove a " + chosen.getName() + " counter from " + cardWithCounter;
|
||||
final String addOrRemove = SGuiChoose.one(putOrRemoveTitle, new String[]{putString,removeString});
|
||||
final String addOrRemove = getGui().one(putOrRemoveTitle, new String[]{putString,removeString});
|
||||
|
||||
return new ImmutablePair<CounterType,String>(chosen,addOrRemove);
|
||||
}
|
||||
@@ -1021,7 +1000,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}
|
||||
};
|
||||
|
||||
List<Pair<SpellAbilityStackInstance, GameObject>> chosen = SGuiChoose.getChoices(saSpellskite.getHostCard().getName(), 1, 1, allTargets, null, fnToString);
|
||||
List<Pair<SpellAbilityStackInstance, GameObject>> chosen = getGui().getChoices(saSpellskite.getHostCard().getName(), 1, 1, allTargets, null, fnToString);
|
||||
return Iterables.getFirst(chosen, null);
|
||||
}
|
||||
|
||||
@@ -1031,7 +1010,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if (sa != null && sa.isManaAbility()) {
|
||||
game.getGameLog().add(GameLogEntryType.LAND, message);
|
||||
} else {
|
||||
SGuiDialog.message(message, sa == null || sa.getHostCard() == null ? "" : CardView.get(sa.getHostCard()).toString());
|
||||
getGui().message(message, sa == null || sa.getHostCard() == null ? "" : CardView.get(sa.getHostCard()).toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1048,10 +1027,10 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
for (int i = 0; i < num; i++) {
|
||||
AbilitySub a;
|
||||
if (i < min) {
|
||||
a = SGuiChoose.one(modeTitle, choices);
|
||||
a = getGui().one(modeTitle, choices);
|
||||
}
|
||||
else {
|
||||
a = SGuiChoose.oneOrNone(modeTitle, choices);
|
||||
a = getGui().oneOrNone(modeTitle, choices);
|
||||
}
|
||||
if (a == null) {
|
||||
break;
|
||||
@@ -1065,7 +1044,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
|
||||
@Override
|
||||
public List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options) {
|
||||
return SGuiChoose.getChoices(message, min, max, options);
|
||||
return getGui().getChoices(message, min, max, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1099,9 +1078,9 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
colorNames[i++] = MagicColor.toLongString(b);
|
||||
}
|
||||
if (colorNames.length > 2) {
|
||||
return MagicColor.fromName(SGuiChoose.one(message, colorNames));
|
||||
return MagicColor.fromName(getGui().one(message, colorNames));
|
||||
}
|
||||
int idxChosen = SGuiDialog.confirm(CardView.get(c), message, colorNames) ? 0 : 1;
|
||||
int idxChosen = getGui().confirm(CardView.get(c), message, colorNames) ? 0 : 1;
|
||||
return MagicColor.fromName(colorNames[idxChosen]);
|
||||
}
|
||||
|
||||
@@ -1110,7 +1089,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
Iterable<PaperCard> cardsFromDb = FModel.getMagicDb().getCommonCards().getUniqueCards();
|
||||
List<PaperCard> cards = Lists.newArrayList(Iterables.filter(cardsFromDb, cpp));
|
||||
Collections.sort(cards);
|
||||
return SGuiChoose.one(message, cards);
|
||||
return getGui().one(message, cards);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1118,7 +1097,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if (options.size() <= 1) {
|
||||
return Iterables.getFirst(options, null);
|
||||
}
|
||||
return SGuiChoose.one(prompt, options);
|
||||
return getGui().one(prompt, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1133,12 +1112,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if (possibleReplacers.size() == 1) {
|
||||
return possibleReplacers.get(0);
|
||||
}
|
||||
return SGuiChoose.one(prompt, possibleReplacers);
|
||||
return getGui().one(prompt, possibleReplacers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseProtectionType(String string, SpellAbility sa, List<String> choices) {
|
||||
return SGuiChoose.one(string, choices);
|
||||
return getGui().one(string, choices);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1151,7 +1130,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
public void orderAndPlaySimultaneousSa(List<SpellAbility> activePlayerSAs) {
|
||||
List<SpellAbility> orderedSAs = activePlayerSAs;
|
||||
if (activePlayerSAs.size() > 1) { // give a dual list form to create instead of needing to do it one at a time
|
||||
orderedSAs = SGuiChoose.order("Select order for Simultaneous Spell Abilities", "Resolve first", activePlayerSAs, null);
|
||||
orderedSAs = getGui().order("Select order for Simultaneous Spell Abilities", "Resolve first", activePlayerSAs, null);
|
||||
}
|
||||
int size = orderedSAs.size();
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
@@ -1199,7 +1178,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
final String p1Str = String.format("Pile 1 (%s cards)", pile1.size());
|
||||
final String p2Str = String.format("Pile 2 (%s cards)", pile2.size());
|
||||
final String[] possibleValues = { p1Str , p2Str };
|
||||
return SGuiDialog.confirm(CardView.get(sa.getHostCard()), "Choose a Pile", possibleValues);
|
||||
return getGui().confirm(CardView.get(sa.getHostCard()), "Choose a Pile", possibleValues);
|
||||
}
|
||||
|
||||
tempShowCards(pile1);
|
||||
@@ -1217,7 +1196,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
// make sure Pile 1 or Pile 2 is clicked on
|
||||
boolean result;
|
||||
while (true) {
|
||||
final CardView chosen = SGuiChoose.one("Choose a pile", cards);
|
||||
final CardView chosen = getGui().one("Choose a pile", cards);
|
||||
if (chosen.equals(pileView1)) {
|
||||
result = true;
|
||||
break;
|
||||
@@ -1235,7 +1214,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
@Override
|
||||
public void revealAnte(String message, Multimap<Player, PaperCard> removedAnteCards) {
|
||||
for (Player p : removedAnteCards.keySet()) {
|
||||
SGuiChoose.reveal(message + " from " + Lang.getPossessedObject(MessageUtil.mayBeYou(player, p), "deck"), removedAnteCards.get(p));
|
||||
getGui().reveal(message + " from " + Lang.getPossessedObject(MessageUtil.mayBeYou(player, p), "deck"), removedAnteCards.get(p));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1248,12 +1227,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
for (CardShields shield : c.getShields()) {
|
||||
shields.add(shield);
|
||||
}
|
||||
return SGuiChoose.one("Choose a regeneration shield:", shields);
|
||||
return getGui().one("Choose a regeneration shield:", shields);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PaperCard> chooseCardsYouWonToAddToDeck(List<PaperCard> losses) {
|
||||
return SGuiChoose.many("Select cards to add to your deck", "Add these to my deck", 0, losses.size(), losses, null);
|
||||
return getGui().many("Select cards to add to your deck", "Add these to my deck", 0, losses.size(), losses, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1351,7 +1330,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SOptionPane.showMessageDialog("Cannot pass priority at this time.");
|
||||
getGui().message("Cannot pass priority at this time.");
|
||||
}
|
||||
});
|
||||
return false;
|
||||
@@ -1392,8 +1371,8 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
public boolean canPlayUnlimitedLands() {
|
||||
return canPlayUnlimitedLands;
|
||||
}
|
||||
private DevModeCheats cheats;
|
||||
public DevModeCheats cheat() {
|
||||
private IDevModeCheats cheats;
|
||||
public IDevModeCheats cheat() {
|
||||
if (cheats == null) {
|
||||
cheats = new DevModeCheats();
|
||||
//TODO: In Network game, inform other players that this player is cheating
|
||||
@@ -1403,25 +1382,37 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
public boolean hasCheated() {
|
||||
return cheats != null;
|
||||
}
|
||||
public class DevModeCheats {
|
||||
public class DevModeCheats implements IDevModeCheats {
|
||||
private DevModeCheats() {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#setCanPlayUnlimitedLands(boolean)
|
||||
*/
|
||||
@Override
|
||||
public void setCanPlayUnlimitedLands(boolean canPlayUnlimitedLands0) {
|
||||
canPlayUnlimitedLands = canPlayUnlimitedLands0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#setViewAllCards(boolean)
|
||||
*/
|
||||
@Override
|
||||
public void setViewAllCards(final boolean canViewAll) {
|
||||
mayLookAtAllCards = canViewAll;
|
||||
for (final Player p : game.getPlayers()) {
|
||||
MatchUtil.updateCards(CardView.getCollection(p.getAllCards()));
|
||||
getGui().updateCards(CardView.getCollection(p.getAllCards()));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#generateMana()
|
||||
*/
|
||||
@Override
|
||||
public void generateMana() {
|
||||
Player pPriority = game.getPhaseHandler().getPriorityPlayer();
|
||||
if (pPriority == null) {
|
||||
SGuiDialog.message("No player has priority at the moment, so mana cannot be added to their pool.");
|
||||
getGui().message("No player has priority at the moment, so mana cannot be added to their pool.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1444,12 +1435,16 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
};
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#dumpGameState()
|
||||
*/
|
||||
@Override
|
||||
public void dumpGameState() {
|
||||
final GameState state = createGameStateObject();
|
||||
try {
|
||||
state.initFromGame(game);
|
||||
File f = GuiBase.getInterface().getSaveFile(new File(ForgeConstants.USER_GAMES_DIR, "state.txt"));
|
||||
if (f != null && (!f.exists() || SOptionPane.showConfirmDialog("Overwrite existing file?"))) {
|
||||
if (f != null && (!f.exists() || getGui().showConfirmDialog("Overwrite existing file?"))) {
|
||||
final BufferedWriter bw = new BufferedWriter(new FileWriter(f));
|
||||
bw.write(state.toString());
|
||||
bw.close();
|
||||
@@ -1459,11 +1454,15 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
if (e.getMessage() != null) {
|
||||
err += ": " + e.getMessage();
|
||||
}
|
||||
SOptionPane.showErrorDialog(err);
|
||||
getGui().showErrorDialog(err);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#setupGameState()
|
||||
*/
|
||||
@Override
|
||||
public void setupGameState() {
|
||||
File gamesDir = new File(ForgeConstants.USER_GAMES_DIR);
|
||||
if (!gamesDir.exists()) { // if the directory does not exist, try to create it
|
||||
@@ -1491,16 +1490,20 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
|
||||
Player pPriority = game.getPhaseHandler().getPriorityPlayer();
|
||||
if (pPriority == null) {
|
||||
SGuiDialog.message("No player has priority at the moment, so game state cannot be setup.");
|
||||
getGui().message("No player has priority at the moment, so game state cannot be setup.");
|
||||
return;
|
||||
}
|
||||
state.applyToGame(game);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#tutorForCard()
|
||||
*/
|
||||
@Override
|
||||
public void tutorForCard() {
|
||||
Player pPriority = game.getPhaseHandler().getPriorityPlayer();
|
||||
if (pPriority == null) {
|
||||
SGuiDialog.message("No player has priority at the moment, so their deck can't be tutored from.");
|
||||
getGui().message("No player has priority at the moment, so their deck can't be tutored from.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1519,20 +1522,28 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#addCountersToPermanent()
|
||||
*/
|
||||
@Override
|
||||
public void addCountersToPermanent() {
|
||||
final CardCollectionView cards = game.getCardsIn(ZoneType.Battlefield);
|
||||
final Card card = game.getCard(SGuiChoose.oneOrNone("Add counters to which card?", CardView.getCollection(cards)));
|
||||
final Card card = game.getCard(getGui().oneOrNone("Add counters to which card?", CardView.getCollection(cards)));
|
||||
if (card == null) { return; }
|
||||
|
||||
final CounterType counter = SGuiChoose.oneOrNone("Which type of counter?", CounterType.values());
|
||||
final CounterType counter = getGui().oneOrNone("Which type of counter?", CounterType.values());
|
||||
if (counter == null) { return; }
|
||||
|
||||
final Integer count = SGuiChoose.getInteger("How many counters?", 1, Integer.MAX_VALUE, 10);
|
||||
final Integer count = getGui().getInteger("How many counters?", 1, Integer.MAX_VALUE, 10);
|
||||
if (count == null) { return; }
|
||||
|
||||
card.addCounter(counter, count, false);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#tapPermanents()
|
||||
*/
|
||||
@Override
|
||||
public void tapPermanents() {
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
@@ -1551,6 +1562,10 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#untapPermanents()
|
||||
*/
|
||||
@Override
|
||||
public void untapPermanents() {
|
||||
game.getAction().invoke(new Runnable() {
|
||||
@Override
|
||||
@@ -1569,20 +1584,28 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#setPlayerLife()
|
||||
*/
|
||||
@Override
|
||||
public void setPlayerLife() {
|
||||
final Player player = game.getPlayer(SGuiChoose.oneOrNone("Set life for which player?", PlayerView.getCollection(game.getPlayers())));
|
||||
final Player player = game.getPlayer(getGui().oneOrNone("Set life for which player?", PlayerView.getCollection(game.getPlayers())));
|
||||
if (player == null) { return; }
|
||||
|
||||
final Integer life = SGuiChoose.getInteger("Set life to what?", 0);
|
||||
final Integer life = getGui().getInteger("Set life to what?", 0);
|
||||
if (life == null) { return; }
|
||||
|
||||
player.setLife(life, null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#winGame()
|
||||
*/
|
||||
@Override
|
||||
public void winGame() {
|
||||
Input input = inputQueue.getInput();
|
||||
if (!(input instanceof InputPassPriority)) {
|
||||
SOptionPane.showMessageDialog("You must have priority to use this feature.", "Win Game", SOptionPane.INFORMATION_ICON);
|
||||
getGui().message("You must have priority to use this feature.", "Win Game");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1599,8 +1622,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
input.selectButtonOK();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#addCardToHand()
|
||||
*/
|
||||
@Override
|
||||
public void addCardToHand() {
|
||||
final Player p = game.getPlayer(SGuiChoose.oneOrNone("Put card in hand for which player?", PlayerView.getCollection(game.getPlayers())));
|
||||
final Player p = game.getPlayer(getGui().oneOrNone("Put card in hand for which player?", PlayerView.getCollection(game.getPlayers())));
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1609,7 +1636,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
Collections.sort(cards);
|
||||
|
||||
// use standard forge's list selection dialog
|
||||
final IPaperCard c = SGuiChoose.oneOrNone("Name the card", cards);
|
||||
final IPaperCard c = getGui().oneOrNone("Name the card", cards);
|
||||
if (c == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1619,8 +1646,12 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
}});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#addCardToBattlefield()
|
||||
*/
|
||||
@Override
|
||||
public void addCardToBattlefield() {
|
||||
final Player p = game.getPlayer(SGuiChoose.oneOrNone("Put card in play for which player?", PlayerView.getCollection(game.getPlayers())));
|
||||
final Player p = game.getPlayer(getGui().oneOrNone("Put card in play for which player?", PlayerView.getCollection(game.getPlayers())));
|
||||
if (p == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1629,7 +1660,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
Collections.sort(cards);
|
||||
|
||||
// use standard forge's list selection dialog
|
||||
final IPaperCard c = SGuiChoose.oneOrNone("Name the card", cards);
|
||||
final IPaperCard c = getGui().oneOrNone("Name the card", cards);
|
||||
if (c == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1654,7 +1685,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
sa = choices.iterator().next();
|
||||
}
|
||||
else {
|
||||
sa = SGuiChoose.oneOrNone("Choose", (FCollection<SpellAbility>)choices);
|
||||
sa = getGui().oneOrNone("Choose", (FCollection<SpellAbility>)choices);
|
||||
}
|
||||
if (sa == null) {
|
||||
return; // happens if cancelled
|
||||
@@ -1670,11 +1701,15 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#riggedPlanarRoll()
|
||||
*/
|
||||
@Override
|
||||
public void riggedPlanarRoll() {
|
||||
final Player player = game.getPlayer(SGuiChoose.oneOrNone("Which player should roll?", PlayerView.getCollection(game.getPlayers())));
|
||||
final Player player = game.getPlayer(getGui().oneOrNone("Which player should roll?", PlayerView.getCollection(game.getPlayers())));
|
||||
if (player == null) { return; }
|
||||
|
||||
final PlanarDice res = SGuiChoose.oneOrNone("Choose result", PlanarDice.values());
|
||||
final PlanarDice res = getGui().oneOrNone("Choose result", PlanarDice.values());
|
||||
if (res == null) { return; }
|
||||
|
||||
System.out.println("Rigging planar dice roll: " + res.toString());
|
||||
@@ -1687,6 +1722,10 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
});
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.player.IDevModeCheats#planeswalkTo()
|
||||
*/
|
||||
@Override
|
||||
public void planeswalkTo() {
|
||||
if (!game.getRules().hasAppliedVariant(GameType.Planechase)) { return; }
|
||||
final Player p = game.getPhaseHandler().getPlayerTurn();
|
||||
@@ -1700,7 +1739,7 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
Collections.sort(allPlanars);
|
||||
|
||||
// use standard forge's list selection dialog
|
||||
final IPaperCard c = SGuiChoose.oneOrNone("Name the card", allPlanars);
|
||||
final IPaperCard c = getGui().oneOrNone("Name the card", allPlanars);
|
||||
if (c == null) { return; }
|
||||
final Card forgeCard = Card.fromPaperCard(c, p);
|
||||
|
||||
@@ -1714,4 +1753,36 @@ public class PlayerControllerHuman extends PlayerController {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void concede() {
|
||||
this.player.concede();
|
||||
getGame().getAction().checkGameOverCondition();
|
||||
}
|
||||
public boolean mayAutoPass() {
|
||||
return getGui().mayAutoPass(getLocalPlayerView());
|
||||
}
|
||||
public void autoPassUntilEndOfTurn() {
|
||||
getGui().autoPassUntilEndOfTurn(getLocalPlayerView());
|
||||
}
|
||||
@Override
|
||||
public void autoPassCancel() {
|
||||
getGui().autoPassCancel(getLocalPlayerView());
|
||||
}
|
||||
public void awaitNextInput() {
|
||||
getGui().awaitNextInput();
|
||||
}
|
||||
public void cancelAwaitNextInput() {
|
||||
getGui().cancelAwaitNextInput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nextGameDecision(final NextGameDecision decision) {
|
||||
game.fireEvent(new UiEventNextGameDecision(this, decision));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivateDescription(final CardView card) {
|
||||
return getInputProxy().getActivateAction(card);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,8 @@ import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.input.InputSelectTargets;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -137,12 +135,12 @@ public class TargetSelection {
|
||||
for (Card card : validTargets) {
|
||||
playersWithValidTargets.put(PlayerView.get(card.getController()), null);
|
||||
}
|
||||
if (MatchUtil.getController().openZones(zone, playersWithValidTargets)) {
|
||||
if (controller.getGui().openZones(zone, playersWithValidTargets)) {
|
||||
InputSelectTargets inp = new InputSelectTargets(controller, validTargets, ability, mandatory);
|
||||
inp.showAndWait();
|
||||
choiceResult = !inp.hasCancelled();
|
||||
bTargetingDone = inp.hasPressedOk();
|
||||
MatchUtil.getController().restoreOldZones(playersWithValidTargets);
|
||||
controller.getGui().restoreOldZones(playersWithValidTargets);
|
||||
}
|
||||
else {
|
||||
// for every other case an all-purpose GuiChoose
|
||||
@@ -206,10 +204,10 @@ public class TargetSelection {
|
||||
|
||||
Object chosen = null;
|
||||
if (!choices.isEmpty() && mandatory) {
|
||||
chosen = SGuiChoose.one(getTgt().getVTSelection(), choicesFiltered);
|
||||
chosen = controller.getGui().one(getTgt().getVTSelection(), choicesFiltered);
|
||||
}
|
||||
else {
|
||||
chosen = SGuiChoose.oneOrNone(getTgt().getVTSelection(), choicesFiltered);
|
||||
chosen = controller.getGui().oneOrNone(getTgt().getVTSelection(), choicesFiltered);
|
||||
}
|
||||
if (chosen == null) {
|
||||
return false;
|
||||
@@ -258,7 +256,7 @@ public class TargetSelection {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
final Object madeChoice = SGuiChoose.oneOrNone(message, selectOptions);
|
||||
final Object madeChoice = controller.getGui().oneOrNone(message, selectOptions);
|
||||
if (madeChoice == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ public class ForgePreferences extends PreferencesStore<ForgePreferences.FPref> {
|
||||
ENFORCE_DECK_LEGALITY ("true"),
|
||||
|
||||
DEV_MODE_ENABLED ("false"),
|
||||
DEV_WORKSHOP_SYNTAX ("false"),
|
||||
DEV_LOG_ENTRY_TYPE (GameLogEntryType.DAMAGE.toString()),
|
||||
|
||||
DECK_DEFAULT_CARD_LIMIT ("4"),
|
||||
|
||||
@@ -3,69 +3,56 @@ package forge.quest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckGroup;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.GameType;
|
||||
import forge.game.Match;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
import forge.util.storage.IStorage;
|
||||
|
||||
public class QuestDraftUtils {
|
||||
private static List<DraftMatchup> matchups = new ArrayList<DraftMatchup>();
|
||||
private static final List<DraftMatchup> matchups = new ArrayList<DraftMatchup>();
|
||||
|
||||
public static boolean matchInProgress = false;
|
||||
public static boolean aiMatchInProgress = false;
|
||||
private static boolean waitForUserInput = false;
|
||||
|
||||
public static void continueMatch(final Game lastGame) {
|
||||
if (lastGame.getMatch().isMatchOver()) {
|
||||
matchInProgress = false;
|
||||
}
|
||||
if (matchInProgress) {
|
||||
MatchUtil.continueMatch();
|
||||
}
|
||||
else {
|
||||
MatchUtil.endCurrentGame();
|
||||
public static void completeDraft(final DeckGroup finishedDraft) {
|
||||
|
||||
final List<Deck> aiDecks = new ArrayList<Deck>(finishedDraft.getAiDecks());
|
||||
finishedDraft.getAiDecks().clear();
|
||||
|
||||
for (int i = 0; i < aiDecks.size(); i++) {
|
||||
final Deck oldDeck = aiDecks.get(i);
|
||||
final Deck namedDeck = new Deck("AI Deck " + i);
|
||||
namedDeck.putSection(DeckSection.Main, oldDeck.get(DeckSection.Main));
|
||||
namedDeck.putSection(DeckSection.Sideboard, oldDeck.get(DeckSection.Sideboard));
|
||||
finishedDraft.getAiDecks().add(namedDeck);
|
||||
}
|
||||
|
||||
final IStorage<DeckGroup> draft = FModel.getQuest().getDraftDecks();
|
||||
draft.add(finishedDraft);
|
||||
|
||||
FModel.getQuest().save();
|
||||
|
||||
}
|
||||
|
||||
public static void completeDraft(DeckGroup finishedDraft) {
|
||||
|
||||
List<Deck> aiDecks = new ArrayList<Deck>(finishedDraft.getAiDecks());
|
||||
finishedDraft.getAiDecks().clear();
|
||||
public static String getDeckLegality() {
|
||||
final String message = GameType.QuestDraft.getDeckFormat().getDeckConformanceProblem(FModel.getQuest().getAssets().getDraftDeckStorage().get(QuestEventDraft.DECK_NAME).getHumanDeck());
|
||||
if (message != null && FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
|
||||
return message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < aiDecks.size(); i++) {
|
||||
Deck oldDeck = aiDecks.get(i);
|
||||
Deck namedDeck = new Deck("AI Deck " + i);
|
||||
namedDeck.putSection(DeckSection.Main, oldDeck.get(DeckSection.Main));
|
||||
namedDeck.putSection(DeckSection.Sideboard, oldDeck.get(DeckSection.Sideboard));
|
||||
finishedDraft.getAiDecks().add(namedDeck);
|
||||
}
|
||||
|
||||
IStorage<DeckGroup> draft = FModel.getQuest().getDraftDecks();
|
||||
draft.add(finishedDraft);
|
||||
|
||||
FModel.getQuest().save();
|
||||
|
||||
}
|
||||
|
||||
public static String getDeckLegality() {
|
||||
String message = GameType.QuestDraft.getDeckFormat().getDeckConformanceProblem(FModel.getQuest().getAssets().getDraftDeckStorage().get(QuestEventDraft.DECK_NAME).getHumanDeck());
|
||||
if (message != null && FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
|
||||
return message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void startNextMatch() {
|
||||
|
||||
public static void startNextMatch(final IGuiGame gui) {
|
||||
if (matchups.size() > 0) {
|
||||
return;
|
||||
}
|
||||
@@ -127,7 +114,7 @@ public class QuestDraftUtils {
|
||||
|
||||
}
|
||||
|
||||
update();
|
||||
update(gui);
|
||||
|
||||
}
|
||||
|
||||
@@ -148,9 +135,7 @@ public class QuestDraftUtils {
|
||||
}
|
||||
|
||||
if (humanIndex > -1) {
|
||||
|
||||
matchup.hasHumanPlayer = true;
|
||||
matchup.matchStarter.add(new RegisteredPlayer(decks.getHumanDeck()).setPlayer(GamePlayerUtil.getGuiPlayer()));
|
||||
matchup.setHumanPlayer(new RegisteredPlayer(decks.getHumanDeck()).setPlayer(GamePlayerUtil.getGuiPlayer()));
|
||||
|
||||
int aiName = Integer.parseInt(draft.getStandings()[aiIndex]) - 1;
|
||||
|
||||
@@ -173,7 +158,7 @@ public class QuestDraftUtils {
|
||||
matchups.add(matchup);
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
public static void update(final IGuiGame gui) {
|
||||
if (matchups.isEmpty()) {
|
||||
if (!matchInProgress) {
|
||||
aiMatchInProgress = false;
|
||||
@@ -189,39 +174,45 @@ public class QuestDraftUtils {
|
||||
return;
|
||||
}
|
||||
|
||||
MatchUtil.getController().enableOverlay();
|
||||
gui.enableOverlay();
|
||||
|
||||
DraftMatchup nextMatch = matchups.remove(0);
|
||||
|
||||
final DraftMatchup nextMatch = matchups.remove(0);
|
||||
matchInProgress = true;
|
||||
|
||||
if (!nextMatch.hasHumanPlayer) {
|
||||
MatchUtil.getController().disableOverlay();
|
||||
|
||||
if (nextMatch.hasHumanPlayer()) {
|
||||
waitForUserInput = true;
|
||||
aiMatchInProgress = false;
|
||||
} else {
|
||||
gui.disableOverlay();
|
||||
waitForUserInput = false;
|
||||
aiMatchInProgress = true;
|
||||
}
|
||||
else {
|
||||
waitForUserInput = true;
|
||||
aiMatchInProgress = false;
|
||||
}
|
||||
|
||||
GameRules rules = new GameRules(GameType.QuestDraft);
|
||||
|
||||
final GameRules rules = new GameRules(GameType.QuestDraft);
|
||||
rules.setPlayForAnte(false);
|
||||
rules.setMatchAnteRarity(false);
|
||||
rules.setGamesPerMatch(3);
|
||||
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
|
||||
rules.canCloneUseTargetsImage = FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE);
|
||||
|
||||
MatchUtil.getController().startNewMatch(new Match(rules, nextMatch.matchStarter));
|
||||
final HostedMatch newMatch = GuiBase.getInterface().hostMatch();
|
||||
newMatch.startMatch(rules, null, nextMatch.matchStarter, nextMatch.humanPlayer, gui);
|
||||
}
|
||||
|
||||
public static void continueMatches() {
|
||||
public static void continueMatches(final IGuiGame gui) {
|
||||
waitForUserInput = false;
|
||||
update();
|
||||
update(gui);
|
||||
}
|
||||
|
||||
private static class DraftMatchup {
|
||||
private List<RegisteredPlayer> matchStarter = new ArrayList<RegisteredPlayer>();
|
||||
private boolean hasHumanPlayer = false;
|
||||
private static final class DraftMatchup {
|
||||
private final List<RegisteredPlayer> matchStarter = new ArrayList<RegisteredPlayer>();
|
||||
private RegisteredPlayer humanPlayer = null;
|
||||
private void setHumanPlayer(final RegisteredPlayer humanPlayer) {
|
||||
this.matchStarter.add(humanPlayer);
|
||||
this.humanPlayer = humanPlayer;
|
||||
}
|
||||
private boolean hasHumanPlayer() {
|
||||
return humanPlayer != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
package forge.quest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
|
||||
import forge.card.CardRules;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
*
|
||||
*/
|
||||
public abstract class QuestRewardCard implements InventoryItem, IQuestRewardCard {
|
||||
public abstract class QuestRewardCard implements IQuestRewardCard {
|
||||
|
||||
protected String buildDescription(final String [] input) {
|
||||
final String defaultDescription = "a card";
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
package forge.quest;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.util.ItemPool;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.util.ItemPool;
|
||||
|
||||
/**
|
||||
* Resolves a card chooser InventoryItem into a CardPrinted.
|
||||
* The initial version includes "duplicate", other type may be added later.
|
||||
*
|
||||
*/
|
||||
public class QuestRewardCardChooser extends QuestRewardCard implements InventoryItem {
|
||||
public class QuestRewardCardChooser extends QuestRewardCard {
|
||||
/**
|
||||
* Possible types for this object.
|
||||
*/
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.List;
|
||||
* Allows the player to choose a card from a predicate-filtered list of cards.
|
||||
*
|
||||
*/
|
||||
public class QuestRewardCardFiltered extends QuestRewardCard implements IQuestRewardCard {
|
||||
public class QuestRewardCardFiltered extends QuestRewardCard {
|
||||
private final String description;
|
||||
private final Predicate<PaperCard> predicates;
|
||||
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
*/
|
||||
package forge.quest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.GuiBase;
|
||||
import forge.LobbyPlayer;
|
||||
@@ -27,13 +34,13 @@ import forge.card.CardRules;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.GameRules;
|
||||
import forge.game.GameType;
|
||||
import forge.game.Match;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.RegisteredPlayer;
|
||||
import forge.interfaces.IButton;
|
||||
import forge.interfaces.IGuiGame;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.PaperToken;
|
||||
import forge.match.MatchUtil;
|
||||
import forge.match.HostedMatch;
|
||||
import forge.model.FModel;
|
||||
import forge.player.GamePlayerUtil;
|
||||
import forge.properties.ForgePreferences.FPref;
|
||||
@@ -45,10 +52,6 @@ import forge.quest.data.QuestAssets;
|
||||
import forge.quest.data.QuestPreferences.QPref;
|
||||
import forge.util.gui.SGuiChoose;
|
||||
import forge.util.gui.SOptionPane;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -540,8 +543,8 @@ public class QuestUtil {
|
||||
forceAnte = qc.isForceAnte();
|
||||
}
|
||||
|
||||
RegisteredPlayer humanStart = new RegisteredPlayer(getDeckForNewGame());
|
||||
RegisteredPlayer aiStart = new RegisteredPlayer(event.getEventDeck());
|
||||
final RegisteredPlayer humanStart = new RegisteredPlayer(getDeckForNewGame());
|
||||
final RegisteredPlayer aiStart = new RegisteredPlayer(event.getEventDeck());
|
||||
|
||||
if (lifeHuman != null) {
|
||||
humanStart.setStartingLife(lifeHuman);
|
||||
@@ -555,34 +558,36 @@ public class QuestUtil {
|
||||
aiStart.setCardsOnBattlefield(QuestUtil.getComputerStartingCards(event));
|
||||
}
|
||||
|
||||
List<RegisteredPlayer> starter = new ArrayList<>();
|
||||
final List<RegisteredPlayer> starter = new ArrayList<>();
|
||||
starter.add(humanStart.setPlayer(GamePlayerUtil.getQuestPlayer()));
|
||||
|
||||
LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(event.getOpponent() == null ? event.getTitle() : event.getOpponent());
|
||||
GuiBase.getInterface().setPlayerAvatar(aiPlayer, event);
|
||||
final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(event.getOpponent() == null ? event.getTitle() : event.getOpponent());
|
||||
starter.add(aiStart.setPlayer(aiPlayer));
|
||||
|
||||
boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
|
||||
for(RegisteredPlayer rp : starter) {
|
||||
final boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
|
||||
for (final RegisteredPlayer rp : starter) {
|
||||
rp.setRandomFoil(useRandomFoil);
|
||||
}
|
||||
boolean useAnte = FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE);
|
||||
boolean matchAnteRarity = FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY);
|
||||
if(forceAnte != null)
|
||||
final boolean matchAnteRarity = FModel.getPreferences().getPrefBoolean(FPref.UI_ANTE_MATCH_RARITY);
|
||||
if (forceAnte != null) {
|
||||
useAnte = forceAnte;
|
||||
GameRules rules = new GameRules(GameType.Quest);
|
||||
}
|
||||
final GameRules rules = new GameRules(GameType.Quest);
|
||||
rules.setPlayForAnte(useAnte);
|
||||
rules.setMatchAnteRarity(matchAnteRarity);
|
||||
rules.setGamesPerMatch(qData.getCharmState() ? 5 : 3);
|
||||
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
|
||||
rules.canCloneUseTargetsImage = FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE);
|
||||
final Match mc = new Match(rules, starter);
|
||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
|
||||
FThreads.invokeInEdtNowOrLater(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
MatchUtil.startGame(mc);
|
||||
hostedMatch.startMatch(rules, null, starter, ImmutableMap.of(humanStart, gui));
|
||||
}
|
||||
});
|
||||
gui.setPlayerAvatar(aiPlayer, event);
|
||||
}
|
||||
|
||||
private static Deck getDeckForNewGame() {
|
||||
|
||||
@@ -361,8 +361,7 @@ public class QuestDataIO {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T readAsset(final XStream xs, final Document doc, final String tagName, final Class<T> clasz)
|
||||
throws IllegalAccessException, NoSuchFieldException {
|
||||
private static <T> T readAsset(final XStream xs, final Document doc, final String tagName, final Class<T> clasz) {
|
||||
final NodeList nn = doc.getElementsByTagName(tagName);
|
||||
final Node n = nn.item(0);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import forge.LobbyPlayer;
|
||||
import forge.events.IUiEventVisitor;
|
||||
import forge.events.UiEventAttackerDeclared;
|
||||
import forge.events.UiEventBlockerAssigned;
|
||||
import forge.events.UiEventNextGameDecision;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.event.GameEvent;
|
||||
import forge.game.event.GameEventBlockersDeclared;
|
||||
@@ -214,6 +215,10 @@ public class EventVisualizer extends IGameEventVisitor.Base<SoundEffectType> imp
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public SoundEffectType visit(UiEventNextGameDecision event) {
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public SoundEffectType visit(GameEventCardPhased event) {
|
||||
return SoundEffectType.Phasing;
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.game.card.CardView;
|
||||
|
||||
public class SGuiChoose {
|
||||
public static final String[] defaultConfirmOptions = { "Yes", "No" };
|
||||
|
||||
/**
|
||||
* Convenience for getChoices(message, 0, 1, choices).
|
||||
*
|
||||
@@ -191,18 +192,18 @@ public class SGuiChoose {
|
||||
return GuiBase.getInterface().getChoices(message, min, max, choices, selected, display);
|
||||
}
|
||||
|
||||
public static <T> List<T> many(final String title, final String topCaption, int cnt, final List<T> sourceChoices, final CardView referenceCard) {
|
||||
return many(title, topCaption, cnt, cnt, sourceChoices, referenceCard);
|
||||
public static <T> List<T> many(final String title, final String topCaption, int cnt, final List<T> sourceChoices) {
|
||||
return many(title, topCaption, cnt, cnt, sourceChoices);
|
||||
}
|
||||
|
||||
public static <T> List<T> many(final String title, final String topCaption, int min, int max, final List<T> sourceChoices, final CardView referenceCard) {
|
||||
public static <T> List<T> many(final String title, final String topCaption, int min, int max, final List<T> sourceChoices) {
|
||||
int m2 = min >= 0 ? sourceChoices.size() - min : -1;
|
||||
int m1 = max >= 0 ? sourceChoices.size() - max : -1;
|
||||
return order(title, topCaption, m1, m2, sourceChoices, null, referenceCard, false);
|
||||
return order(title, topCaption, m1, m2, sourceChoices, null);
|
||||
}
|
||||
|
||||
public static <T> List<T> order(final String title, final String top, final List<T> sourceChoices, final CardView referenceCard) {
|
||||
return order(title, top, 0, 0, sourceChoices, null, referenceCard, false);
|
||||
public static <T> List<T> order(final String title, final String top, final List<T> sourceChoices) {
|
||||
return order(title, top, 0, 0, sourceChoices, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,17 +217,17 @@ public class SGuiChoose {
|
||||
* @return A shallow copy of the list of objects, with newItem inserted.
|
||||
*/
|
||||
public static <T> List<T> insertInList(final String title, final T newItem, final List<T> oldItems) {
|
||||
final T placeAfter = oneOrNone(title, oldItems);
|
||||
final int indexAfter = (placeAfter == null ? 0 : oldItems.indexOf(placeAfter) + 1);
|
||||
final List<T> result = Lists.newArrayListWithCapacity(oldItems.size() + 1);
|
||||
result.addAll(oldItems);
|
||||
result.add(indexAfter, newItem);
|
||||
return result;
|
||||
final T placeAfter = oneOrNone(title, oldItems);
|
||||
final int indexAfter = (placeAfter == null ? 0 : oldItems.indexOf(placeAfter) + 1);
|
||||
final List<T> result = Lists.newArrayListWithCapacity(oldItems.size() + 1);
|
||||
result.addAll(oldItems);
|
||||
result.add(indexAfter, newItem);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <T> List<T> order(final String title, final String top, final int remainingObjectsMin, final int remainingObjectsMax,
|
||||
final List<T> sourceChoices, final List<T> destChoices, final CardView referenceCard, final boolean sideboardingMode) {
|
||||
return GuiBase.getInterface().order(title, top, remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices, referenceCard, sideboardingMode);
|
||||
final List<T> sourceChoices, final List<T> destChoices) {
|
||||
return GuiBase.getInterface().order(title, top, remainingObjectsMin, remainingObjectsMax, sourceChoices, destChoices);
|
||||
}
|
||||
|
||||
// If comparer is NULL, T has to be comparable. Otherwise you'll get an exception from inside the Arrays.sort() routine
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package forge.util.gui;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.game.card.CardView;
|
||||
|
||||
/**
|
||||
* Holds player interactions using standard windows
|
||||
*
|
||||
*/
|
||||
public class SGuiDialog {
|
||||
private static final String[] defaultConfirmOptions = { "Yes", "No" };
|
||||
|
||||
public static boolean confirm(final CardView c, final String question) {
|
||||
return SGuiDialog.confirm(c, question, true, null);
|
||||
}
|
||||
public static boolean confirm(final CardView c, final String question, final boolean defaultChoice) {
|
||||
return SGuiDialog.confirm(c, question, defaultChoice, null);
|
||||
}
|
||||
public static boolean confirm(final CardView c, final String question, String[] options) {
|
||||
return SGuiDialog.confirm(c, question, true, options);
|
||||
}
|
||||
|
||||
public static boolean confirm(final CardView c, final String question, final boolean defaultIsYes, final String[] options) {
|
||||
final String title = c == null ? "Question" : c + " - Ability";
|
||||
String questionToUse = StringUtils.isBlank(question) ? "Activate card's ability?" : question;
|
||||
String[] opts = options == null ? defaultConfirmOptions : options;
|
||||
int answer = SOptionPane.showCardOptionDialog(c, questionToUse, title, SOptionPane.QUESTION_ICON, opts, defaultIsYes ? 0 : 1);
|
||||
return answer == 0;
|
||||
}
|
||||
|
||||
public static void message(final String message) {
|
||||
message(message, "Forge");
|
||||
}
|
||||
|
||||
public static void message(final String message, final String title) {
|
||||
SOptionPane.showMessageDialog(message, title, null);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package forge.util.gui;
|
||||
|
||||
import forge.GuiBase;
|
||||
import forge.assets.FSkinProp;
|
||||
import forge.game.card.CardView;
|
||||
|
||||
public class SOptionPane {
|
||||
public static final FSkinProp QUESTION_ICON = FSkinProp.ICO_QUESTION;
|
||||
@@ -60,10 +59,6 @@ public class SOptionPane {
|
||||
return GuiBase.getInterface().showOptionDialog(message, title, icon, options, defaultOption);
|
||||
}
|
||||
|
||||
public static int showCardOptionDialog(CardView card, String message, String title, FSkinProp icon, String[] options, int defaultOption) {
|
||||
return GuiBase.getInterface().showCardOptionDialog(card, message, title, icon, options, defaultOption);
|
||||
}
|
||||
|
||||
public static String showInputDialog(String message, String title) {
|
||||
return showInputDialog(message, title, null, "", null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user