...
 
Commits (48)
......@@ -95,7 +95,7 @@ public class ComputerUtil {
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
if (sa.isCopied()) {
if (!sa.isCopied()) {
sa.resetPaidHash();
}
......
......@@ -321,11 +321,17 @@ public class ComputerUtilMana {
SpellAbility saPayment = chooseManaAbility(cost, sa, ai, toPay, saList, true);
if (saPayment == null) {
if (!toPay.isPhyrexian() || !ai.canPayLife(2)) {
boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B");
if ((!toPay.isPhyrexian() && !lifeInsteadOfBlack) || !ai.canPayLife(2)) {
break; // cannot pay
}
cost.payPhyrexian();
if (toPay.isPhyrexian()) {
cost.payPhyrexian();
} else if (lifeInsteadOfBlack) {
cost.decreaseShard(ManaCostShard.BLACK, 1);
}
continue;
}
......@@ -381,6 +387,8 @@ public class ComputerUtilMana {
while (!cost.isPaid()) {
toPay = getNextShardToPay(cost);
boolean lifeInsteadOfBlack = toPay.isBlack() && ai.hasKeyword("PayLifeInsteadOf:B");
Collection<SpellAbility> saList = null;
if (hasConverge &&
(toPay == ManaCostShard.GENERIC || toPay == ManaCostShard.X)) {
......@@ -431,7 +439,8 @@ public class ComputerUtilMana {
}
if (saPayment == null) {
if (!toPay.isPhyrexian() || !ai.canPayLife(2) || (ai.getLife() <= 2 && !ai.cantLoseForZeroOrLessLife())) {
if ((!toPay.isPhyrexian() && !lifeInsteadOfBlack) || !ai.canPayLife(2)
|| (ai.getLife() <= 2 && !ai.cantLoseForZeroOrLessLife())) {
break; // cannot pay
}
......@@ -446,7 +455,12 @@ public class ComputerUtilMana {
}
}
cost.payPhyrexian();
if (toPay.isPhyrexian()) {
cost.payPhyrexian();
} else if (lifeInsteadOfBlack) {
cost.decreaseShard(ManaCostShard.BLACK, 1);
}
if (!test) {
ai.payLife(2, sa.getHostCard());
}
......
......@@ -192,6 +192,14 @@ public class CloneAi extends SpellAbilityAi {
if (!newOptions.isEmpty()) {
options = newOptions;
}
if (sa.hasParam("AiChoiceLogic")) {
final String logic = sa.getParam("AiChoiceLogic");
if ("BestOppCtrl".equals(logic)) {
options = CardLists.filterControlledBy(options, ctrl.getOpponents());
}
}
Card choice = isOpp ? ComputerUtilCard.getWorstAI(options) : ComputerUtilCard.getBestAI(options);
if (isVesuva && "Vesuva".equals(choice.getName())) {
......
......@@ -163,6 +163,10 @@ public final class ImageKeys {
for (String ext : FILE_EXTENSIONS) {
File file = new File(dir, filename + ext);
if (file.exists()) {
if (file.isDirectory()) {
file.delete();
continue;
}
return file;
}
}
......
......@@ -36,6 +36,8 @@ public class StaticData {
private Predicate<PaperCard> standardPredicate;
private Predicate<PaperCard> brawlPredicate;
private Predicate<PaperCard> modernPredicate;
private Predicate<PaperCard> commanderPredicate;
private Predicate<PaperCard> oathbreakerPredicate;
private boolean filteredHandsEnabled = false;
......@@ -201,17 +203,23 @@ public class StaticData {
public void setStandardPredicate(Predicate<PaperCard> standardPredicate) { this.standardPredicate = standardPredicate; }
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = standardPredicate; }
public void setCommanderPredicate(Predicate<PaperCard> commanderPredicate) { this.commanderPredicate = commanderPredicate; }
public void setOathbreakerPredicate(Predicate<PaperCard> oathbreakerPredicate) { this.oathbreakerPredicate = oathbreakerPredicate; }
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
public Predicate<PaperCard> getModernPredicate() {
return modernPredicate;
}
public Predicate<PaperCard> getBrawlPredicate() {
return brawlPredicate;
}
public Predicate<PaperCard> getCommanderPredicate() { return commanderPredicate; }
public Predicate<PaperCard> getOathbreakerPredicate() { return oathbreakerPredicate; }
public Predicate<PaperCard> getBrawlPredicate() { return brawlPredicate; }
public void setFilteredHandsEnabled(boolean filteredHandsEnabled){
this.filteredHandsEnabled = filteredHandsEnabled;
......
......@@ -219,7 +219,7 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
if (upcomingSet != null) {
addCard(new PaperCard(cr, upcomingSet.getCode(), CardRarity.Unknown, 1));
} else {
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/cardeditions/ folder. ");
System.err.println("The card " + cr.getName() + " was not assigned to any set. Adding it to UNKNOWN set... to fix see res/editions/ folder. ");
addCard(new PaperCard(cr, CardEdition.UNKNOWN.getCode(), CardRarity.Special, 1));
}
}
......
......@@ -210,6 +210,16 @@ public final class CardRules implements ICardCharacteristics {
return canBeCommander() && (hasKeyword("Partner") || !this.partnerWith.isEmpty());
}
public boolean canBeOathbreaker() {
CardType type = mainPart.getType();
return type.isPlaneswalker();
}
public boolean canBeSignatureSpell() {
CardType type = mainPart.getType();
return type.isInstant() || type.isSorcery();
}
public boolean canBeBrawlCommander() {
CardType type = mainPart.getType();
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker();
......@@ -219,7 +229,7 @@ public final class CardRules implements ICardCharacteristics {
return meldWith;
}
public String getParterWith() {
public String getPartnerWith() {
return partnerWith;
}
......
......@@ -570,6 +570,19 @@ public final class CardRulesPredicates {
}
};
public static final Predicate<CardRules> CAN_BE_OATHBREAKER = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.canBeOathbreaker();
}
};
public static final Predicate<CardRules> CAN_BE_SIGNATURE_SPELL = new Predicate<CardRules>() {
@Override
public boolean apply(final CardRules subject) {
return subject.canBeSignatureSpell();
}
};
public static final Predicate<CardRules> IS_PLANESWALKER = CardRulesPredicates.coreType(true, CardType.CoreType.Planeswalker);
public static final Predicate<CardRules> IS_INSTANT = CardRulesPredicates.coreType(true, CardType.CoreType.Instant);
public static final Predicate<CardRules> IS_SORCERY = CardRulesPredicates.coreType(true, CardType.CoreType.Sorcery);
......
......@@ -122,9 +122,45 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
for (final Entry<PaperCard, Integer> c : cp) {
result.add(c.getKey());
}
if (result.size() > 1) { //sort by type so signature spell comes after oathbreaker
Collections.sort(result, new Comparator<PaperCard>() {
@Override
public int compare(final PaperCard c1, final PaperCard c2) {
return Boolean.compare(c1.getRules().canBeSignatureSpell(), c2.getRules().canBeSignatureSpell());
}
});
}
return result;
}
//at least for now, Oathbreaker will only support one oathbreaker and one signature spell
public PaperCard getOathbreaker() {
final CardPool cp = get(DeckSection.Commander);
if (cp == null) {
return null;
}
for (final Entry<PaperCard, Integer> c : cp) {
PaperCard card = c.getKey();
if (card.getRules().canBeOathbreaker()) {
return card;
}
}
return null;
}
public PaperCard getSignatureSpell() {
final CardPool cp = get(DeckSection.Commander);
if (cp == null) {
return null;
}
for (final Entry<PaperCard, Integer> c : cp) {
PaperCard card = c.getKey();
if (card.getRules().canBeSignatureSpell()) {
return card;
}
}
return null;
}
// may return nulls
public CardPool get(DeckSection deckSection) {
loadDeferredSections();
......
......@@ -296,7 +296,7 @@ public class GameFormat implements Comparable<GameFormat> {
coreFormats.add("Commander.txt");
coreFormats.add("Extended.txt");
coreFormats.add("Brawl.txt");
coreFormats.add("Oathbreaker.txt");
}
public Reader(File forgeFormats, File customFormats, boolean includeHistoric) {
......
......@@ -88,6 +88,7 @@ public class GameRules {
public boolean hasCommander() {
return appliedVariants.contains(GameType.Commander)
|| appliedVariants.contains(GameType.Oathbreaker)
|| appliedVariants.contains(GameType.TinyLeaders)
|| appliedVariants.contains(GameType.Brawl);
}
......
......@@ -24,6 +24,7 @@ public enum GameType {
DeckManager (DeckFormat.Constructed, false, true, true, "lblDeckManager", ""),
Vanguard (DeckFormat.Vanguard, true, true, true, "lblVanguard", "lblVanguardDesc"),
Commander (DeckFormat.Commander, false, false, false, "lblCommander", "lblCommanderDesc"),
Oathbreaker (DeckFormat.Oathbreaker, false, false, false, "lblOathbreaker", "lblOathbreakerDesc"),
TinyLeaders (DeckFormat.TinyLeaders, false, false, false, "lblTinyLeaders", "lblTinyLeadersDesc"),
Brawl (DeckFormat.Brawl, false, false, false, "lblBrawl", "lblBrawlDesc"),
Planeswalker (DeckFormat.PlanarConquest, false, false, true, "lblPlaneswalker", "lblPlaneswalkerDesc"),
......@@ -126,6 +127,7 @@ public enum GameType {
/*switch (this) {
case Archenemy:
case Commander:
case Oathbreaker:
case TinyLeaders:
case Planechase:
case Vanguard:
......
......@@ -34,8 +34,6 @@ import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
......@@ -1674,7 +1672,7 @@ public class AbilityUtils {
for(String c : MagicColor.Constant.COLORS_AND_COLORLESS) {
// Use the strings from MagicColor, since that's how the Script will be coming in as
String key = WordUtils.capitalize(c) + "Conversion";
String key = StringUtils.capitalize(c) + "Conversion";
if (params.containsKey(key)) {
String convertTo = params.get(key);
byte convertByte = 0;
......
......@@ -292,6 +292,7 @@ public class AnimateEffect extends AnimateEffectBase {
addedStaticAbilities, timestamp);
c.removeChangedName(timestamp);
c.updateStateForView();
game.fireEvent(new GameEventCardStatsChanged(c));
......
......@@ -79,7 +79,7 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect {
}
if (sa.hasParam("RemoveLandTypes")) {
removeCreatureTypes = true;
removeLandTypes = true;
}
if (sa.hasParam("RemoveCreatureTypes")) {
removeCreatureTypes = true;
......
......@@ -166,6 +166,9 @@ public class CloneEffect extends SpellAbilityEffect {
sa.getHostCard().addFacedownCommand(unclone);
}
}
if (sa.hasParam("RememberCloneOrigin")) {
tgtCard.addRemembered(cardToCopy);
}
game.fireEvent(new GameEventCardStatsChanged(tgtCard));
} // cloneResolve
......
......@@ -874,6 +874,15 @@ public class CardProperty {
}
}
return false;
case "TriggeredCard":
final Object triggeringObject = source.getTriggeringObject(restriction.substring("Triggered".length()));
if (!(triggeringObject instanceof Card)) {
return false;
}
if (card.sharesCardTypeWith((Card) triggeringObject)) {
return true;
}
return false;
case "EachTopLibrary":
final CardCollection cards = new CardCollection();
for (Player p : game.getPlayers()) {
......@@ -1067,34 +1076,6 @@ public class CardProperty {
if (p == null || !controller.equals(game.getNextPlayerAfter(p, direction))) {
return false;
}
} else if (property.startsWith("sharesTypeWith")) {
if (property.equals("sharesTypeWith")) {
if (!card.sharesTypeWith(source)) {
return false;
}
} else {
final String restriction = property.split("sharesTypeWith ")[1];
final Card checkCard;
if (restriction.startsWith("Triggered")) {
final Object triggeringObject = source.getTriggeringObject(restriction.substring("Triggered".length()));
if (!(triggeringObject instanceof Card)) {
return false;
}
checkCard = (Card) triggeringObject;
} else if (restriction.startsWith("Remembered")) {
final Object rememberedObject = source.getFirstRemembered();
if (!(rememberedObject instanceof Card)) {
return false;
}
checkCard = (Card) rememberedObject;
} else {
return false;
}
if (!card.sharesTypeWith(checkCard)) {
return false;
}
}
} else if (property.startsWith("hasKeyword")) {
// "withFlash" would find Flashback cards, add this to fix Mystical Teachings
if (!card.hasKeyword(property.substring(10))) {
......
......@@ -7,6 +7,7 @@ import forge.card.*;
import forge.card.mana.ManaCost;
import forge.game.Direction;
import forge.game.GameEntityView;
import forge.game.GameType;
import forge.game.combat.Combat;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
......@@ -195,7 +196,29 @@ public class CardView extends GameEntityView {
return get(TrackableProperty.IsCommander);
}
void updateCommander(Card c) {
set(TrackableProperty.IsCommander, c.isCommander());
boolean isCommander = c.isCommander();
set(TrackableProperty.IsCommander, isCommander);
if (c.getGame().getRules().hasAppliedVariant(GameType.Oathbreaker)) {
//store alternate type for oathbreaker or signature spell for display in card text
if (isCommander) {
if (c.getPaperCard().getRules().canBeSignatureSpell()) {
set(TrackableProperty.CommanderAltType, "Signature Spell");
}
else {
set(TrackableProperty.CommanderAltType, "Oathbreaker");
}
}
else {
set(TrackableProperty.CommanderAltType, null);
}
}
}
public String getCommanderType() {
String type = get(TrackableProperty.CommanderAltType);
if (type == null) {
type = "Commander";
}
return type;
}
public Map<CounterType, Integer> getCounters() {
......@@ -542,7 +565,7 @@ public class CardView extends GameEntityView {
sb.append(rulesText).append("\r\n\r\n");
}
if (isCommander()) {
sb.append(getOwner()).append("'s Commander\r\n");
sb.append(getOwner()).append("'s " + getCommanderType() + "\r\n");
sb.append(getOwner().getCommanderInfo(this)).append("\r\n");
}
......
......@@ -598,9 +598,11 @@ public class Player extends GameEntity implements Comparable<Player> {
}
}
//Tiny Leaders and Brawl ignore commander damage rule.
if (source.isCommander() && isCombat && this.getGame().getRules().getGameType() != GameType.TinyLeaders
&& this.getGame().getRules().getGameType() != GameType.Brawl) {
//Oathbreaker, Tiny Leaders, and Brawl ignore commander damage rule
if (source.isCommander() && isCombat
&& !this.getGame().getRules().hasAppliedVariant(GameType.Oathbreaker)
&& !this.getGame().getRules().hasAppliedVariant(GameType.TinyLeaders)
&& !this.getGame().getRules().hasAppliedVariant(GameType.Brawl)) {
commanderDamage.put(source, getCommanderDamage(source) + amount);
view.updateCommanderDamage(this);
}
......@@ -2641,9 +2643,9 @@ public class Player extends GameEntity implements Comparable<Player> {
public List<Card> getCommanders() {
return commanders;
}
public void setCommanders(List<Card> commander0) {
if (commander0 == commanders) { return; }
commanders = commander0;
public void setCommanders(List<Card> commanders0) {
if (commanders0 == commanders) { return; }
commanders = commanders0;
view.updateCommander(this);
}
......@@ -2767,15 +2769,30 @@ public class Player extends GameEntity implements Comparable<Player> {
final String name = Lang.getPossesive(commander.getName()) + " Commander Effect";
DetachedCardEffect eff = new DetachedCardEffect(commander, name);
eff.setSVar("CommanderMoveReplacement", "DB$ ChangeZone | Origin$ Battlefield,Graveyard,Exile,Library,Hand | Destination$ Command | Defined$ ReplacedCard");
if (game.getRules().hasAppliedVariant(GameType.Oathbreaker) && commander.getRules().canBeSignatureSpell()) {
//signature spells can only reside on the stack or in the command zone
eff.setSVar("SignatureSpellMoveReplacement", "DB$ ChangeZone | Origin$ Stack | Destination$ Command | Defined$ ReplacedCard");
String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | ReplaceWith$ CommanderMoveReplacement ";
if (game.getRules().hasAppliedVariant(GameType.TinyLeaders)) {
moved += " | Destination$ Graveyard,Exile | Description$ If a commander would be put into its owner's graveyard or exile from anywhere, that player may put it into the command zone instead.";
} else {
moved += " | Destination$ Graveyard,Exile,Hand,Library | Description$ If a commander would be exiled or put into hand, graveyard, or library from anywhere, that player may put it into the command zone instead.";
String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | ReplaceWith$ SignatureSpellMoveReplacement | Destination$ Graveyard,Exile,Hand,Library | " +
"Description$ If a signature spell would be put into another zone from the stack, put it into the command zone instead.";
eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true));
//signature spells can only be cast if your oathbreaker is in on the battlefield under your control
String castRestriction = "Mode$ CantBeCast | ValidCard$ Card.EffectSource+YouOwn | EffectZone$ Command | IsPresent$ Card.IsCommander+YouOwn+YouCtrl | PresentZone$ Battlefield | PresentCompare$ EQ0 | " +
"Description$ Signature spell can only be cast if your oathbreaker is on the battlefield under your control.";
eff.addStaticAbility(castRestriction);
}
else {
eff.setSVar("CommanderMoveReplacement", "DB$ ChangeZone | Origin$ Battlefield,Graveyard,Exile,Library,Hand | Destination$ Command | Defined$ ReplacedCard");
String moved = "Event$ Moved | ValidCard$ Card.EffectSource+YouOwn | Secondary$ True | Optional$ True | OptionalDecider$ You | ReplaceWith$ CommanderMoveReplacement ";
if (game.getRules().hasAppliedVariant(GameType.TinyLeaders)) {
moved += " | Destination$ Graveyard,Exile | Description$ If a commander would be put into its owner's graveyard or exile from anywhere, that player may put it into the command zone instead.";
} else {
moved += " | Destination$ Graveyard,Exile,Hand,Library | Description$ If a commander would be exiled or put into hand, graveyard, or library from anywhere, that player may put it into the command zone instead.";
}
eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true));
}
eff.addReplacementEffect(ReplacementHandler.parseReplacement(moved, eff, true));
String mayBePlayedAbility = "Mode$ Continuous | EffectZone$ Command | MayPlay$ True | Affected$ Card.YouOwn+EffectSource | AffectedZone$ Command";
if (game.getRules().hasAppliedVariant(GameType.Planeswalker)) { //support paying for Planeswalker with any color mana
......
......@@ -120,7 +120,10 @@ public class RegisteredPlayer {
start.setStartingLife(start.getStartingLife() + 20); // 903.7: ...each player sets his or her life total to 40
// Modified for layering of variants to life +20
}
if (appliedVariants.contains(GameType.TinyLeaders)) {
if (appliedVariants.contains(GameType.Oathbreaker)) {
start.commanders = deck.getCommanders();
}
if (appliedVariants.contains(GameType.TinyLeaders)) {
start.commanders = deck.getCommanders();
start.setStartingLife(start.getStartingLife() + 5);
}
......
......@@ -83,6 +83,7 @@ public enum TriggerType {
SetInMotion(TriggerSetInMotion.class),
Shuffled(TriggerShuffled.class),
SpellAbilityCast(TriggerSpellAbilityCast.class),
SpellAbilityCopy(TriggerSpellAbilityCopy.class),
SpellCast(TriggerSpellAbilityCast.class),
SpellCopy(TriggerSpellAbilityCopy.class),
Surveil(TriggerSurveil.class),
......
......@@ -334,6 +334,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
if (sp.isSpell()) {
game.getTriggerHandler().runTrigger(TriggerType.SpellCopy, runParams, false);
}
game.getTriggerHandler().runTrigger(TriggerType.SpellAbilityCopy, runParams, false);
}
// Run BecomesTarget triggers
......
......@@ -20,6 +20,7 @@ package forge.game.zone;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.game.Game;
import forge.game.GameType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
......@@ -80,7 +81,7 @@ public class Zone implements java.io.Serializable, Iterable<Card> {
add(c, index, null);
}
public void add(final Card c, final Integer index, final Card latestState) {
public void add(final Card c, Integer index, final Card latestState) {
if (index != null && cardList.isEmpty() && index.intValue() > 0) {
// something went wrong, most likely the method fired when the game was in an unexpected state
// (e.g. conceding during the mana payment prompt)
......@@ -88,6 +89,15 @@ public class Zone implements java.io.Serializable, Iterable<Card> {
return;
}
//ensure commander returns to being first card in command zone
if (index == null && zoneType == ZoneType.Command && c.isCommander()) {
index = 0;
if (game.getRules().hasAppliedVariant(GameType.Oathbreaker) && c.getRules().canBeSignatureSpell()
&& !cardList.isEmpty() && cardList.get(0).isCommander()) {
index = 1; //signature spell should return to being second card in command zone if oathbreaker is there too
}
}
// Immutable cards are usually emblems and effects
if (!c.isImmutable()) {
final Zone oldZone = game.getZoneOf(c);
......
......@@ -37,6 +37,7 @@ public enum TrackableProperty {
Tapped(TrackableTypes.BooleanType),
Token(TrackableTypes.BooleanType),
IsCommander(TrackableTypes.BooleanType),
CommanderAltType(TrackableTypes.StringType),
Damage(TrackableTypes.IntegerType),
AssignedDamage(TrackableTypes.IntegerType),
ShieldCount(TrackableTypes.IntegerType),
......
......@@ -7,6 +7,7 @@
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
......@@ -14,13 +15,15 @@
<application
android:allowBackup="true"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:icon="@drawable/ic_launcher"
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:largeHeap="true">
<activity
android:name=".Main"
android:label="@string/app_name">
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
......
......@@ -102,7 +102,7 @@
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-android</artifactId>
<version>1.5.5</version>
<version>1.9.10</version>
</dependency>
</dependencies>
......
......@@ -8,4 +8,5 @@
# project structure.
# Project target.
project.type=0
target=android-20
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#f0f0f0</color>
</resources>
\ No newline at end of file
......@@ -17,6 +17,8 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.PowerManager;
import android.provider.Settings;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import android.view.WindowManager;
import android.webkit.MimeTypeMap;
import com.badlogic.gdx.Gdx;
......@@ -35,6 +37,8 @@ import java.io.OutputStream;
import java.util.concurrent.Callable;
public class Main extends AndroidApplication {
public int time = -2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......@@ -235,13 +239,17 @@ public class Main extends AndroidApplication {
@Override
public void preventSystemSleep(final boolean preventSleep) {
if (time == -2)
time = Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0);
FThreads.invokeInEdtNowOrLater(new Runnable() { //must set window flags from EDT thread
@Override
public void run() {
if (preventSleep) {
Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, Integer.MAX_VALUE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
else {
Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, time);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
......
......@@ -14,6 +14,13 @@ final class ImageLoader extends CacheLoader<String, BufferedImage> {
public BufferedImage load(String key) {
File file = ImageKeys.getImageFile(key);
if (file != null) {
if (!file.exists()) {
return null;
}
if (file.isDirectory()) {
file.delete();
return null;
}
try {
return ImageIO.read(file);
}
......
......@@ -136,14 +136,22 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
private void updateCustom() {
DeckFormat deckFormat = lstDecks.getGameType().getDeckFormat();
if(deckFormat.equals(DeckFormat.Commander)){
switch (deckFormat) {
case Commander:
updateDecks(DeckProxy.getAllCommanderDecks(), ItemManagerConfig.COMMANDER_DECKS);
}else if(deckFormat.equals(DeckFormat.TinyLeaders)){
updateDecks(DeckProxy.getAllTinyLeadersDecks(), ItemManagerConfig.COMMANDER_DECKS);
}else if(deckFormat.equals(DeckFormat.Brawl)){
break;
case Oathbreaker:
updateDecks(DeckProxy.getAllOathbreakerDecks(), ItemManagerConfig.COMMANDER_DECKS);
break;
case Brawl:
updateDecks(DeckProxy.getAllBrawlDecks(), ItemManagerConfig.COMMANDER_DECKS);
}else {
break;
case TinyLeaders:
updateDecks(DeckProxy.getAllTinyLeadersDecks(), ItemManagerConfig.COMMANDER_DECKS);
break;
default:
updateDecks(DeckProxy.getAllConstructedDecks(), ItemManagerConfig.CONSTRUCTED_DECKS);
break;
}
}
......@@ -184,14 +192,13 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
}
private void updateRandomCommander() {
if((!lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Commander))&&
!(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.TinyLeaders))&&
!(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Brawl))){
DeckFormat deckFormat = lstDecks.getGameType().getDeckFormat();
if (!deckFormat.hasCommander()) {
return;
}
lstDecks.setAllowMultipleSelections(false);
lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(lstDecks.getGameType().getDeckFormat(), isAi, false));
lstDecks.setAllowMultipleSelections(false);
lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(deckFormat, isAi, false));
lstDecks.setup(ItemManagerConfig.STRING_ONLY);
btnRandom.setText("Random");
......@@ -207,13 +214,13 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
}
private void updateRandomCardGenCommander() {
if((!lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Commander))&&
!(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.TinyLeaders))&&
!(lstDecks.getGameType().getDeckFormat().equals(DeckFormat.Brawl))){
DeckFormat deckFormat = lstDecks.getGameType().getDeckFormat();
if (!deckFormat.hasCommander()) {
return;
}
lstDecks.setAllowMultipleSelections(false);
lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(lstDecks.getGameType().getDeckFormat(), isAi, true));
lstDecks.setPool(CommanderDeckGenerator.getCommanderDecks(deckFormat, isAi, true));
lstDecks.setup(ItemManagerConfig.STRING_ONLY);
btnRandom.setText("Random");
......
......@@ -14,6 +14,7 @@ import forge.screens.deckeditor.views.VDeckgen;
import forge.screens.deckeditor.views.VProbabilities;
import forge.screens.deckeditor.views.VStatistics;
import forge.screens.deckeditor.views.VTinyLeadersDecks;
import forge.screens.deckeditor.views.VOathbreakerDecks;
import forge.screens.home.gauntlet.VSubmenuGauntletBuild;
import forge.screens.home.gauntlet.VSubmenuGauntletContests;
import forge.screens.home.gauntlet.VSubmenuGauntletLoad;
......@@ -60,6 +61,7 @@ public enum EDocID {
EDITOR_COMMANDER (VCommanderDecks.SINGLETON_INSTANCE),
EDITOR_BRAWL (VBrawlDecks.SINGLETON_INSTANCE),
EDITOR_TINY_LEADERS (VTinyLeadersDecks.SINGLETON_INSTANCE),
EDITOR_OATHBREAKER (VOathbreakerDecks.SINGLETON_INSTANCE),
WORKSHOP_CATALOG (VWorkshopCatalog.SINGLETON_INSTANCE),
WORKSHOP_CARDDESIGNER (VCardDesigner.SINGLETON_INSTANCE),
......
......@@ -88,6 +88,15 @@ public class FScreen {
"Close Editor",
ForgeConstants.EDITOR_LAYOUT_FILE,
false);
public static final FScreen DECK_EDITOR_OATHBREAKER = new FScreen(
VDeckEditorUI.SINGLETON_INSTANCE,
CDeckEditorUI.SINGLETON_INSTANCE,
"Oathbreaker Deck Editor",
FSkin.getImage(FSkinProp.IMG_PACK),
true,
"Close Editor",
ForgeConstants.EDITOR_LAYOUT_FILE,
false);
public static final FScreen DECK_EDITOR_PLANECHASE = new FScreen(
VDeckEditorUI.SINGLETON_INSTANCE,
CDeckEditorUI.SINGLETON_INSTANCE,
......
......@@ -338,6 +338,11 @@ public final class DeckManager extends ItemManager<DeckProxy> implements IHasGam
DeckPreferences.setCommanderDeck((deck != null) ? deck.toString() : "");
editorCtrl = new CEditorConstructed(getCDetailPicture(), this.gameType);
break;
case Oathbreaker:
screen = FScreen.DECK_EDITOR_CONSTRUCTED; // re-use "Deck Editor", rather than creating a new top level tab
DeckPreferences.setCommanderDeck((deck != null) ? deck.toString() : "");
editorCtrl = new CEditorConstructed(getCDetailPicture(), this.gameType);
break;
case Brawl:
screen = FScreen.DECK_EDITOR_CONSTRUCTED; // re-use "Deck Editor", rather than creating a new top level tab
DeckPreferences.setBrawlDeck((deck != null) ? deck.toString() : "");
......@@ -397,6 +402,7 @@ public final class DeckManager extends ItemManager<DeckProxy> implements IHasGam
switch(this.gameType) {
case Brawl:
case Commander:
case Oathbreaker:
case TinyLeaders:
case Constructed:
case Draft:
......
......@@ -42,6 +42,7 @@ import forge.screens.deckeditor.views.VBrawlDecks;
import forge.screens.deckeditor.views.VCardCatalog;
import forge.screens.deckeditor.views.VCommanderDecks;
import forge.screens.deckeditor.views.VCurrentDeck;
import forge.screens.deckeditor.views.VOathbreakerDecks;
import forge.screens.deckeditor.views.VTinyLeadersDecks;
import forge.screens.match.controllers.CDetailPicture;
import forge.util.ItemPool;
......@@ -63,6 +64,7 @@ public enum CDeckEditorUI implements ICDoc {
private final CDetailPicture cDetailPicture;
private final VAllDecks vAllDecks;
private final VCommanderDecks vCommanderDecks;
private final VOathbreakerDecks vOathbreakerDecks;
private final VBrawlDecks vBrawlDecks;
private final VTinyLeadersDecks vTinyLeadersDecks;
......@@ -73,6 +75,8 @@ public enum CDeckEditorUI implements ICDoc {
this.vAllDecks.setCDetailPicture(cDetailPicture);
this.vCommanderDecks = VCommanderDecks.SINGLETON_INSTANCE;
this.vCommanderDecks.setCDetailPicture(cDetailPicture);
this.vOathbreakerDecks = VOathbreakerDecks.SINGLETON_INSTANCE;
this.vOathbreakerDecks.setCDetailPicture(cDetailPicture);
this.vBrawlDecks = VBrawlDecks.SINGLETON_INSTANCE;
this.vBrawlDecks.setCDetailPicture(cDetailPicture);
this.vTinyLeadersDecks = VTinyLeadersDecks.SINGLETON_INSTANCE;
......
......@@ -22,6 +22,7 @@ import com.google.common.collect.Iterables;
import forge.UiCommand;
import forge.assets.FSkinProp;
import forge.deck.*;
import forge.game.GameType;
import forge.gui.GuiChoose;
import forge.gui.GuiUtils;
import forge.gui.framework.*;
......@@ -76,6 +77,7 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
private ItemManager<TItem> deckManager;
protected DeckSection sectionMode = DeckSection.Main;
private final CDetailPicture cDetailPicture;
protected final GameType gameType;
// card transfer buttons
final Localizer localizer = Localizer.getInstance();
......@@ -114,9 +116,10 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
.icon(FSkin.getImage(FSkinProp.IMG_LAND, 18, 18))
.iconScaleAuto(false).hoverable().build();
protected ACEditorBase(final FScreen screen0, final CDetailPicture cDetailPicture) {
protected ACEditorBase(final FScreen screen0, final CDetailPicture cDetailPicture0, final GameType gameType0) {
this.screen = screen0;
this.cDetailPicture = cDetailPicture;
this.cDetailPicture = cDetailPicture0;
this.gameType = gameType0;
}
public FScreen getScreen() {
......
......@@ -6,7 +6,7 @@ import forge.itemmanager.ItemManagerConfig;
import forge.screens.deckeditor.views.VBrawlDecks;
/**
* Controls the "Commander Decks" panel in the deck editor UI.
* Controls the "Brawl Decks" panel in the deck editor UI.
*
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
*
......
package forge.screens.deckeditor.controllers;
import forge.deck.*;
import forge.game.GameType;
import forge.gui.framework.FScreen;
import forge.item.PaperCard;
import forge.screens.match.controllers.CDetailPicture;
......@@ -8,9 +9,8 @@ import forge.screens.match.controllers.CDetailPicture;
import java.util.*;
public abstract class CDeckEditor<TModel extends DeckBase> extends ACEditorBase<PaperCard, TModel> {
protected CDeckEditor(FScreen screen0, CDetailPicture cDetailPicture) {
super(screen0, cDetailPicture);
protected CDeckEditor(FScreen screen0, CDetailPicture cDetailPicture0, GameType gameType0) {
super(screen0, cDetailPicture0, gameType0);
}
/**
......
......@@ -21,15 +21,19 @@ import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import forge.UiCommand;
import forge.card.CardDb;
import forge.card.CardRules;
import forge.card.CardRulesPredicates;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.GameFormat;
import forge.game.GameType;
import forge.gui.framework.DragCell;
import forge.gui.framework.FScreen;
import forge.item.PaperCard;
import forge.itemmanager.CardManager;
import forge.itemmanager.ItemManagerConfig;
import forge.model.CardCollections;
import forge.model.FModel;
import forge.screens.deckeditor.SEditorIO;
import forge.screens.deckeditor.views.VAllDecks;
......@@ -70,26 +74,27 @@ public final class CEditorCommander extends CDeckEditor<Deck> {
* all cards are available.
*/
@SuppressWarnings("serial")
public CEditorCommander(final CDetailPicture cDetailPicture, boolean tinyLeaders, boolean brawl) {
super(tinyLeaders ? FScreen.DECK_EDITOR_TINY_LEADERS : brawl ? FScreen.DECK_EDITOR_BRAWL : FScreen.DECK_EDITOR_COMMANDER, cDetailPicture);
public CEditorCommander(final CDetailPicture cDetailPicture, GameType gameType0) {
super(gameType0 == GameType.TinyLeaders ? FScreen.DECK_EDITOR_TINY_LEADERS : gameType0 == GameType.Brawl ? FScreen.DECK_EDITOR_BRAWL :
gameType0 == GameType.Oathbreaker ? FScreen.DECK_EDITOR_OATHBREAKER : FScreen.DECK_EDITOR_COMMANDER, cDetailPicture, gameType0);
allSections.add(DeckSection.Main);
allSections.add(DeckSection.Sideboard);
allSections.add(DeckSection.Commander);
if(brawl){
CardDb commonCards = FModel.getMagicDb().getCommonCards();
if (gameType == GameType.Brawl){
GameFormat format = FModel.getFormats().get("Brawl");
Predicate<CardRules> commanderFilter = CardRulesPredicates.Presets.CAN_BE_BRAWL_COMMANDER;
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.and(
FModel.getFormats().get("Brawl").getFilterPrinted(),Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES))),PaperCard.class);
}else{
Predicate<CardRules> commanderFilter = CardRulesPredicates.Presets.CAN_BE_COMMANDER ;
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)),PaperCard.class);
commanderPool = ItemPool.createFrom(commonCards.getAllCards(Predicates.and(
format.getFilterPrinted(), Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES))), PaperCard.class);
normalPool = ItemPool.createFrom(format.getAllCards(), PaperCard.class);
}
if(brawl){
normalPool = ItemPool.createFrom(FModel.getFormats().get("Brawl").getAllCards(), PaperCard.class);
}else {
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);
else {
Predicate<CardRules> commanderFilter = gameType == GameType.Oathbreaker
?