Merge branch 'master' of https://github.com/Card-Forge/forge into adventure

 Conflicts:
	forge-gui-mobile/src/forge/adventure/scene/DeckSelectScene.java
	forge-gui-mobile/src/forge/adventure/scene/HudScene.java
	forge-gui-mobile/src/forge/adventure/scene/PlayerStatisticScene.java
	forge-gui-mobile/src/forge/adventure/scene/RewardScene.java
	forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java
	forge-gui-mobile/src/forge/adventure/scene/SettingsScene.java
	forge-gui-mobile/src/forge/adventure/scene/StartScene.java
	forge-gui-mobile/src/forge/adventure/scene/UIScene.java
	forge-gui-mobile/src/forge/adventure/stage/GameHUD.java
	forge-gui-mobile/src/forge/adventure/stage/GameStage.java
	forge-gui-mobile/src/forge/adventure/stage/MapStage.java
	forge-gui-mobile/src/forge/adventure/stage/WorldStage.java
This commit is contained in:
Grimm
2022-09-16 18:35:47 +02:00
705 changed files with 36189 additions and 1449 deletions

View File

@@ -11,6 +11,10 @@
<packaging>jar</packaging>
<name>Forge Adventure</name>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
@@ -299,6 +303,11 @@
<version>1.6.54-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-desktop</artifactId>
<version>2.2.3-SNAPSHOT</version>
</dependency>
</dependencies>
<properties>
@@ -306,4 +315,4 @@
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
</project>

View File

@@ -27,6 +27,7 @@ import forge.ai.ability.ExploreAi;
import forge.ai.ability.LearnAi;
import forge.ai.simulation.SpellAbilityPicker;
import forge.card.CardStateName;
import forge.card.CardType;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.deck.Deck;
@@ -1615,6 +1616,13 @@ public class AiController {
}
for (String sv : card.getSVars().keySet()) {
String varValue = card.getSVar(sv);
if (varValue.equals("Count$Domain")) {
for (String type : landToPlay.getType().getLandTypes()) {
if (CardType.isABasicLandType(type) && CardLists.getType(otb, type).isEmpty()) {
return true;
}
}
}
if (varValue.startsWith("Count$Valid") || sv.equals("BuffedBy")) {
if (varValue.contains("Land") || varValue.contains("Plains") || varValue.contains("Forest")
|| varValue.contains("Mountain") || varValue.contains("Island") || varValue.contains("Swamp")

View File

@@ -2,10 +2,12 @@ package forge.ai;
import static forge.ai.ComputerUtilCard.getBestCreatureAI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import forge.card.MagicColor;
import forge.game.cost.*;
import org.apache.commons.lang3.ObjectUtils;
@@ -55,6 +57,14 @@ public class AiCostDecision extends CostDecisionMakerBase {
return PaymentDecision.number(c);
}
@Override
public PaymentDecision visit(CostChooseColor cost) {
int c = cost.getAbilityAmount(ability);
List<String> choices = player.getController().chooseColors("Color", ability, c, c,
new ArrayList<>(MagicColor.Constant.ONLY_COLORS));
return PaymentDecision.colors(choices);
}
@Override
public PaymentDecision visit(CostChooseCreatureType cost) {
String choice = player.getController().chooseSomeType("Creature", ability, CardType.getAllCreatureTypes(),

View File

@@ -1201,7 +1201,7 @@ public abstract class GameState {
String[] allCounterStrings = counterString.split(",");
for (final String counterPair : allCounterStrings) {
String[] pair = counterPair.split("=", 2);
entity.addCounterInternal(CounterType.getType(pair[0]), Integer.parseInt(pair[1]), null, false, null);
entity.addCounterInternal(CounterType.getType(pair[0]), Integer.parseInt(pair[1]), null, false, null, null);
}
}

View File

@@ -218,7 +218,7 @@ public class SpecialCardAi {
Card animated = AnimateAi.becomeAnimated(sa.getHostCard(), sa.getSubAbility());
if (sa.getHostCard().canReceiveCounters(CounterEnumType.P1P1)) {
animated.addCounterInternal(CounterEnumType.P1P1, 2, ai, false, null);
animated.addCounterInternal(CounterEnumType.P1P1, 2, ai, false, null, null);
}
boolean isOppEOT = ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == ai;
boolean isValuableAttacker = ph.is(PhaseType.MAIN1, ai) && ComputerUtilCard.doesSpecifiedCreatureAttackAI(ai, animated);

View File

@@ -2,6 +2,7 @@ package forge.ai.ability;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
@@ -54,13 +55,14 @@ public abstract class DamageAiBase extends SpellAbilityAi {
final Game game = comp.getGame();
Player enemy = comp.getWeakestOpponent();
boolean dmgByCardsInHand = false;
Card hostcard = sa.getHostCard();
if ("X".equals(sa.getParam("NumDmg")) && sa.getHostCard() != null && sa.hasSVar(sa.getParam("NumDmg")) &&
if ("X".equals(sa.getParam("NumDmg")) && hostcard != null && sa.hasSVar(sa.getParam("NumDmg")) &&
sa.getSVar(sa.getParam("NumDmg")).equals("TargetedPlayer$CardsInHand")) {
dmgByCardsInHand = true;
}
// Not sure if type choice implemented for the AI yet but it should at least recognize this spell hits harder on larger enemy hand size
if ("Blood Oath".equals(sa.getHostCard().getName())) {
if ("Blood Oath".equals(hostcard.getName())) {
dmgByCardsInHand = true;
}
@@ -71,9 +73,13 @@ public abstract class DamageAiBase extends SpellAbilityAi {
return false;
}
// If the opponent will gain life (ex. Fiery Justice), not beneficial unless life gain is harmful or ignored
if ("OpponentGainLife".equals(sa.getParam("AILogic")) && ComputerUtil.lifegainPositive(enemy, hostcard)) {
return false;
}
// Benefits hitting players?
// If has triggered ability on dealing damage to an opponent, go for it!
Card hostcard = sa.getHostCard();
for (Trigger trig : hostcard.getTriggers()) {
if (trig.getMode() == TriggerType.DamageDone) {
if ("Opponent".equals(trig.getParam("ValidTarget"))
@@ -95,9 +101,9 @@ public abstract class DamageAiBase extends SpellAbilityAi {
}
if (!noPrevention) {
restDamage = ComputerUtilCombat.predictDamageTo(enemy, restDamage, sa.getHostCard(), false);
restDamage = ComputerUtilCombat.predictDamageTo(enemy, restDamage, hostcard, false);
} else {
restDamage = enemy.staticReplaceDamage(restDamage, sa.getHostCard(), false);
restDamage = enemy.staticReplaceDamage(restDamage, hostcard, false);
}
if (restDamage == 0) {

View File

@@ -781,6 +781,13 @@ public class DamageDealAi extends DamageAiBase {
sa.resetTargets();
return false;
}
// if opponent will gain life (ex. Fiery Justice), don't target only enemy player unless life gain is harmful or ignored
if ("OpponentGainLife".equals(logic) && tcs.size() == 1 && tcs.contains(enemy) && ComputerUtil.lifegainPositive(enemy, source)) {
sa.resetTargets();
return false;
}
return true;
}

View File

@@ -105,13 +105,11 @@ public class ManaEffectAi extends SpellAbilityAi {
}
PhaseHandler ph = ai.getGame().getPhaseHandler();
boolean moreManaNextTurn = false;
if (ph.is(PhaseType.END_OF_TURN) && (ph.getNextTurn() == ai || ComputerUtilCard.willUntap(ai, sa.getHostCard())) && canRampPool(ai, sa.getHostCard())) {
moreManaNextTurn = true;
}
boolean moreManaNextTurn = ph.is(PhaseType.END_OF_TURN) && (ph.getNextTurn() == ai || ComputerUtilCard.willUntap(ai, sa.getHostCard()))
&& canRampPool(ai, sa.getHostCard());
return sa.getPayCosts().hasNoManaCost() && sa.getPayCosts().isReusuableResource()
&& sa.getSubAbility() == null && (ComputerUtil.playImmediately(ai, sa) || moreManaNextTurn);
&& sa.getSubAbility() == null && (moreManaNextTurn || ComputerUtil.playImmediately(ai, sa));
}
/**

View File

@@ -140,6 +140,7 @@ public final class CardEdition implements Comparable<CardEdition> {
BUNDLE("bundle"),
BOX_TOPPER("box topper"),
DUNGEONS("dungeons"),
JUMPSTART("jumpstart"),
REBALANCED("rebalanced");
private final String name;

View File

@@ -43,6 +43,11 @@ public final class CardRules implements ICardCharacteristics {
private CardSplitType splitType;
private ICardFace mainPart;
private ICardFace otherPart;
private ICardFace wSpecialize;
private ICardFace uSpecialize;
private ICardFace bSpecialize;
private ICardFace rSpecialize;
private ICardFace gSpecialize;
private CardAiHints aiHints;
private ColorSet colorIdentity;
private ColorSet deckbuildingColors;
@@ -54,6 +59,12 @@ public final class CardRules implements ICardCharacteristics {
splitType = altMode;
mainPart = faces[0];
otherPart = faces[1];
wSpecialize = faces[2];
uSpecialize = faces[3];
bSpecialize = faces[4];
rSpecialize = faces[5];
gSpecialize = faces[6];
aiHints = cah;
meldWith = "";
partnerWith = "";
@@ -74,6 +85,11 @@ public final class CardRules implements ICardCharacteristics {
splitType = newRules.splitType;
mainPart = newRules.mainPart;
otherPart = newRules.otherPart;
wSpecialize = newRules.wSpecialize;
uSpecialize = newRules.uSpecialize;
bSpecialize = newRules.bSpecialize;
rSpecialize = newRules.rSpecialize;
gSpecialize = newRules.gSpecialize;
aiHints = newRules.aiHints;
colorIdentity = newRules.colorIdentity;
meldWith = newRules.meldWith;
@@ -132,6 +148,22 @@ public final class CardRules implements ICardCharacteristics {
return otherPart;
}
public ICardFace getWSpecialize() {
return wSpecialize;
}
public ICardFace getUSpecialize() {
return uSpecialize;
}
public ICardFace getBSpecialize() {
return bSpecialize;
}
public ICardFace getRSpecialize() {
return rSpecialize;
}
public ICardFace getGSpecialize() {
return gSpecialize;
}
public String getName() {
switch (splitType.getAggregationMethod()) {
case COMBINE:
@@ -335,7 +367,7 @@ public final class CardRules implements ICardCharacteristics {
// Reads cardname.txt
public static class Reader {
// fields to build
private CardFace[] faces = new CardFace[] { null, null };
private CardFace[] faces = new CardFace[] { null, null, null, null, null, null, null };
private int curFace = 0;
private CardSplitType altMode = CardSplitType.None;
private String meldWith = "";
@@ -382,6 +414,11 @@ public final class CardRules implements ICardCharacteristics {
CardAiHints cah = new CardAiHints(removedFromAIDecks, removedFromRandomDecks, removedFromNonCommanderDecks, hints, needs, has);
faces[0].assignMissingFields();
if (null != faces[1]) faces[1].assignMissingFields();
if (null != faces[2]) faces[2].assignMissingFields();
if (null != faces[3]) faces[3].assignMissingFields();
if (null != faces[4]) faces[4].assignMissingFields();
if (null != faces[5]) faces[5].assignMissingFields();
if (null != faces[6]) faces[6].assignMissingFields();
final CardRules result = new CardRules(faces, altMode, cah);
result.setNormalizedName(this.normalizedName);
@@ -518,6 +555,18 @@ public final class CardRules implements ICardCharacteristics {
case 'S':
if ("S".equals(key)) {
this.faces[this.curFace].addStaticAbility(value);
} else if (key.startsWith("SPECIALIZE")) {
if (value.equals("WHITE")) {
this.curFace = 2;
} else if (value.equals("BLUE")) {
this.curFace = 3;
} else if (value.equals("BLACK")) {
this.curFace = 4;
} else if (value.equals("RED")) {
this.curFace = 5;
} else if (value.equals("GREEN")) {
this.curFace = 6;
}
} else if ("SVar".equals(key)) {
if (null == value) throw new IllegalArgumentException("SVar has no variable name");
@@ -600,7 +649,7 @@ public final class CardRules implements ICardCharacteristics {
public static CardRules getUnsupportedCardNamed(String name) {
CardAiHints cah = new CardAiHints(true, true, true, null, null, null);
CardFace[] faces = { new CardFace(name), null};
CardFace[] faces = { new CardFace(name), null, null, null, null, null, null};
faces[0].setColor(ColorSet.fromMask(0));
faces[0].setType(CardType.parse("", false));
faces[0].setOracleText("This card is not supported by Forge. Whenever you start a game with this card, it will be bugged.");

View File

@@ -10,7 +10,8 @@ public enum CardSplitType
Split(FaceSelectionMethod.COMBINE, CardStateName.RightSplit),
Flip(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Flipped),
Adventure(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Adventure),
Modal(FaceSelectionMethod.USE_ACTIVE_FACE, CardStateName.Modal);
Modal(FaceSelectionMethod.USE_ACTIVE_FACE, CardStateName.Modal),
Specialize(FaceSelectionMethod.USE_ACTIVE_FACE, null);
CardSplitType(FaceSelectionMethod calcMode, CardStateName stateName) {
method = calcMode;

View File

@@ -10,7 +10,12 @@ public enum CardStateName {
LeftSplit,
RightSplit,
Adventure,
Modal
Modal,
SpecializeW,
SpecializeU,
SpecializeB,
SpecializeR,
SpecializeG
;

View File

@@ -16,20 +16,21 @@ import forge.util.lang.LangGerman;
import forge.util.lang.LangItalian;
import forge.util.lang.LangJapanese;
import forge.util.lang.LangSpanish;
import forge.util.lang.LangFrench;
/**
* Static library containing language-related utility methods.
*/
public abstract class Lang {
private static Lang instance;
private static Lang instance;
private static Lang englishInstance;
protected String languageCode;
protected String countryCode;
public static void createInstance(String localeID) {
String[] splitLocale = localeID.split("-");
String[] splitLocale = localeID.split("-");
String language = splitLocale[0];
String country = splitLocale[1];
if (language.equals("de")) {
@@ -42,6 +43,8 @@ public abstract class Lang {
instance = new LangChinese();
} else if (language.equals("ja")) {
instance = new LangJapanese();
} else if (language.equals("fr")) {
instance = new LangFrench();
} else { // default is English
instance = new LangEnglish();
}
@@ -54,14 +57,14 @@ public abstract class Lang {
englishInstance.countryCode = "US";
}
public static Lang getInstance() {
return instance;
}
public static Lang getInstance() {
return instance;
}
public static Lang getEnglishInstance() {
return englishInstance;
}
protected Lang() {
}
@@ -70,7 +73,7 @@ public abstract class Lang {
* of a numbers, eg. "st" for 1 ("first") and "th" for 4 ("fourth").
*
* @param position
* the number to get the ordinal suffix for.
* the number to get the ordinal suffix for.
* @return a string containing two characters.
*/
public abstract String getOrdinal(final int position);
@@ -81,26 +84,32 @@ public abstract class Lang {
return has1 ? (has2 ? s1 + " and " + s2 : s1) : (has2 ? s2 : "");
}
public static <T> String joinHomogenous(final Iterable<T> objects) { return joinHomogenous(Lists.newArrayList(objects)); }
public static <T> String joinHomogenous(final Collection<T> objects) { return joinHomogenous(objects, null, "and"); }
public static <T> String joinHomogenous(final Iterable<T> objects) {
return joinHomogenous(Lists.newArrayList(objects));
}
public static <T> String joinHomogenous(final Collection<T> objects) {
return joinHomogenous(objects, null, "and");
}
public static <T> String joinHomogenous(final Collection<T> objects, final Function<T, String> accessor) {
return joinHomogenous(objects, accessor, "and");
}
public static <T> String joinHomogenous(final Collection<T> objects, final Function<T, String> accessor, final String lastUnion) {
public static <T> String joinHomogenous(final Collection<T> objects, final Function<T, String> accessor,
final String lastUnion) {
int remaining = objects.size();
final StringBuilder sb = new StringBuilder();
for (final T obj : objects) {
remaining--;
if (accessor != null) {
sb.append(accessor.apply(obj));
}
else {
} else {
sb.append(obj);
}
if (remaining > 1) {
sb.append(", ");
}
else if (remaining == 1) {
} else if (remaining == 1) {
sb.append(" ").append(lastUnion).append(" ");
}
}
@@ -108,7 +117,8 @@ public abstract class Lang {
}
public static <T> String joinVerb(final List<T> subjects, final String verb) {
return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb : verbs3rdPersonSingular(verb);
return subjects.size() > 1 || !subjectIsSingle3rdPerson(Iterables.getFirst(subjects, "it").toString()) ? verb
: verbs3rdPersonSingular(verb);
}
public static String joinVerb(final String subject, final String verb) {
@@ -126,7 +136,8 @@ public abstract class Lang {
}
public static String getPlural(final String noun) {
return noun + (noun.endsWith("s") && !noun.endsWith("ds") || noun.endsWith("x") || noun.endsWith("ch") ? "es" : noun.endsWith("ds") ? "" : "s");
return noun + (noun.endsWith("s") && !noun.endsWith("ds") || noun.endsWith("x") || noun.endsWith("ch") ? "es"
: noun.endsWith("ds") ? "" : "s");
}
public static String nounWithAmount(final int cnt, final String noun) {
@@ -170,6 +181,7 @@ public abstract class Lang {
}
public abstract String getPossesive(final String name);
public abstract String getPossessedObject(final String owner, final String object);
public static boolean startsWithVowel(final String word) {
@@ -177,14 +189,17 @@ public abstract class Lang {
}
private static final Pattern VOWEL_PATTERN = Pattern.compile("[aeiou]", Pattern.CASE_INSENSITIVE);
public static boolean isVowel(final char letter) {
return VOWEL_PATTERN.matcher(String.valueOf(letter)).find();
}
public final static String[] numbers0 = new String[] {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eightteen", "nineteen" };
public final static String[] numbers20 = new String[] {"twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eightteen",
"nineteen" };
public final static String[] numbers20 = new String[] { "twenty", "thirty", "fourty", "fifty", "sixty", "seventy",
"eighty", "ninety" };
public static String getNumeral(int n) {
final String prefix = n < 0 ? "minus " : "";

View File

@@ -0,0 +1,40 @@
package forge.util.lang;
import forge.util.Lang;
public class LangFrench extends Lang {
@Override
public String getOrdinal(final int position) {
if (position == 1) {
return position + "ᵉʳ";
} else {
return position + "";
}
}
@Override
public String getPossesive(final String name) {
if ("Vous".equalsIgnoreCase(name)) {
return name;
}
return "de " + name;
}
@Override
public String getPossessedObject(final String owner, final String object) {
if ("Vous".equalsIgnoreCase(owner)) {
return getPossesive(owner) + " " + object;
}
return object + " " + getPossesive(owner);
}
@Override
public String getNickName(final String name) {
if (name.contains(",")) {
return name.split(",")[0];
} else {
return name.split(" ")[0];
}
}
}

View File

@@ -80,6 +80,22 @@ public class ForgeScript {
return source.hasChosenColor()
&& colors.hasAnyColor(ColorSet.fromNames(source.getChosenColors()).getColor());
} else if (property.equals("AssociatedWithChosenColor")) {
final String color = source.getChosenColor();
switch (color) {
case "white":
return cardState.getTypeWithChanges().getLandTypes().contains("Plains");
case "blue":
return cardState.getTypeWithChanges().getLandTypes().contains("Island");
case "black":
return cardState.getTypeWithChanges().getLandTypes().contains("Swamp");
case "red":
return cardState.getTypeWithChanges().getLandTypes().contains("Mountain");
case "green":
return cardState.getTypeWithChanges().getLandTypes().contains("Forest");
default:
return false;
}
} else if (property.startsWith("non")) {
// ... Other Card types
return !cardState.getTypeWithChanges().hasStringType(property.substring(3));
@@ -100,6 +116,15 @@ public class ForgeScript {
return cardState.getTypeWithChanges().hasStringType(source.getChosenType2());
} else if (property.equals("IsNotChosenType2")) {
return !cardState.getTypeWithChanges().hasStringType(source.getChosenType2());
} else if (property.equals("NotedType")) {
boolean found = false;
for (String s : source.getNotedTypes()) {
if (cardState.getTypeWithChanges().hasStringType(s)) {
found = true;
break;
}
}
return found;
} else if (property.startsWith("HasSubtype")) {
final String subType = property.substring(11);
return cardState.getTypeWithChanges().hasSubtype(subType);
@@ -160,6 +185,10 @@ public class ForgeScript {
return !sa.isManaAbility();
} else if (property.equals("withoutXCost")) {
return !sa.costHasManaX();
} else if (property.startsWith("XCost")) {
String comparator = property.substring(5, 7);
int y = AbilityUtils.calculateAmount(sa.getHostCard(), property.substring(7), sa);
return Expressions.compare(sa.getXManaCostPaid(), comparator, y);
} else if (property.equals("hasTapCost")) {
Cost cost = sa.getPayCosts();
return cost != null && cost.hasTapCost();
@@ -207,6 +236,8 @@ public class ForgeScript {
return sa.hasParam("Nightbound");
} else if (property.equals("paidPhyrexianMana")) {
return sa.getSpendPhyrexianMana();
} else if (property.equals("LastChapter")) {
return sa.isLastChapter();
} else if (property.startsWith("ManaSpent")) {
String[] k = property.split(" ", 2);
String comparator = k[1].substring(0, 2);

View File

@@ -887,8 +887,7 @@ public class Game {
ingamePlayers.remove(p);
lostPlayers.add(p);
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, p);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
getTriggerHandler().runTrigger(TriggerType.LosesGame, runParams, false);
}
@@ -1202,8 +1201,7 @@ public class Game {
// If an effect allows or instructs a player to reveal the card as its being drawn,
// its revealed after the spell becomes cast or the ability becomes activated.
final Map<AbilityKey, Object> runParams = Maps.newHashMap();
runParams.put(AbilityKey.Card, c);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
runParams.put(AbilityKey.Number, facedownWhileCasting.get(c));
runParams.put(AbilityKey.Player, this);
runParams.put(AbilityKey.CanReveal, true);

View File

@@ -608,6 +608,10 @@ public class GameAction {
if (c.hasIntensity()) {
copied.setIntensity(c.getIntensity(false));
}
// specialize is perpetual
if (c.isSpecialized()) {
copied.setState(c.getCurrentStateName(), false);
}
// update state for view
copied.updateStateForView();
@@ -688,7 +692,7 @@ public class GameAction {
}
if (fromBattlefield) {
if (!c.isRealToken()) {
if (!c.isRealToken() && !c.isSpecialized()) {
copied.setState(CardStateName.Original, true);
}
// Soulbond unpairing
@@ -848,11 +852,7 @@ public class GameAction {
if (zoneTo.is(ZoneType.Stack)) {
// zoneFrom maybe null if the spell is cast from "Ouside the game", ex. ability of Garth One-Eye
if (zoneFrom == null) {
c.setCastFrom(null);
} else {
c.setCastFrom(zoneFrom);
}
c.setCastFrom(zoneFrom);
if (cause != null && cause.isSpell() && c.equals(cause.getHostCard())) {
c.setCastSA(cause);
} else {
@@ -1845,7 +1845,6 @@ public class GameAction {
}
public final boolean destroy(final Card c, final SpellAbility sa, final boolean regenerate, CardZoneTable table, Map<AbilityKey, Object> params) {
Player activator = null;
if (!c.canBeDestroyed()) {
return false;
}
@@ -1862,6 +1861,7 @@ public class GameAction {
return false;
}
Player activator = null;
if (sa != null) {
activator = sa.getActivatingPlayer();
}
@@ -2238,8 +2238,7 @@ public class GameAction {
game.setMonarch(p);
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, p);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
game.getTriggerHandler().runTrigger(TriggerType.BecomeMonarch, runParams, false);
}
@@ -2264,8 +2263,7 @@ public class GameAction {
// You can take the initiative even if you already have it
// Run triggers
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, p);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
game.getTriggerHandler().runTrigger(TriggerType.TakesInitiative, runParams, false);
}
@@ -2354,8 +2352,7 @@ public class GameAction {
if (cause != null) {
// set up triggers (but not actually do them until later)
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, p);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(p);
runParams.put(AbilityKey.ScryNum, numLookedAt);
game.getTriggerHandler().runTrigger(TriggerType.Scry, runParams, false);
}
@@ -2415,7 +2412,7 @@ public class GameAction {
}
// for Zangief do this before runWaitingTriggers DamageDone
damageMap.triggerExcessDamage(isCombat, lethalDamage, game);
damageMap.triggerExcessDamage(isCombat, lethalDamage, game, lkiCache);
// lose life simultaneously
if (isCombat) {

View File

@@ -580,11 +580,9 @@ public final class GameActionUtil {
if (tr != null) {
String n = o.split(":")[1];
if (host.wasCast() && n.equals("X")) {
CardCollectionView creatures = CardLists.filter(CardLists.filterControlledBy(game.getCardsIn
(ZoneType.Battlefield), activator), CardPredicates.Presets.CREATURES);
CardCollectionView creatures = activator.getCreaturesInPlay();
int max = Aggregates.max(creatures, CardPredicates.Accessors.fnGetNetPower);
int min = Aggregates.min(creatures, CardPredicates.Accessors.fnGetNetPower);
n = Integer.toString(pc.chooseNumber(sa, "Choose X for Casualty", min, max));
n = Integer.toString(pc.chooseNumber(sa, "Choose X for Casualty", 0, max));
}
final String casualtyCost = "Sac<1/Creature.powerGE" + n + "/creature with power " + n +
" or greater>";
@@ -592,6 +590,8 @@ public final class GameActionUtil {
String str = "Pay for Casualty? " + cost.toSimpleString();
boolean v = pc.addKeywordCost(sa, cost, ki, str);
tr.setSVar("CasualtyPaid", v ? "1" : "0");
tr.getOverridingAbility().setSVar("CasualtyPaid", v ? "1" : "0");
tr.setSVar("Casualty", v ? n : "0");
tr.getOverridingAbility().setSVar("Casualty", v ? n : "0");
@@ -607,7 +607,7 @@ public final class GameActionUtil {
Trigger tr = Iterables.getFirst(ki.getTriggers(), null);
if (tr != null) {
final String conspireCost = "tapXType<2/Creature.SharesColorWith/" +
"untapped creature you control that shares a color with " + host.getName() + ">";
"creature that shares a color with " + host.getName() + ">";
final Cost cost = new Cost(conspireCost, false);
String str = "Pay for Conspire? " + cost.toSimpleString();

View File

@@ -26,6 +26,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
@@ -330,9 +331,9 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
subtractCounter(CounterType.get(counterName), n);
}
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table);
public void addCounterInternal(final CounterEnumType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table) {
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table);
abstract public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params);
public void addCounterInternal(final CounterEnumType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
addCounterInternal(CounterType.get(counterType), n, source, fireEvents, table, params);
}
public void receiveDamage(Pair<Integer, Boolean> dmg) {

View File

@@ -155,11 +155,18 @@ public class GameEntityCounterTable extends ForwardingTable<Optional<Player>, Ga
continue;
}
// Add ETB flag
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.ETB, etb);
if (params != null) {
runParams.putAll(params);
}
// Apply counter after replacement effect
for (Map.Entry<Optional<Player>, Map<CounterType, Integer>> e : values.entrySet()) {
boolean remember = cause != null && cause.hasParam("RememberPut");
for (Map.Entry<CounterType, Integer> ec : e.getValue().entrySet()) {
gm.getKey().addCounterInternal(ec.getKey(), ec.getValue(), e.getKey().orNull(), true, result);
gm.getKey().addCounterInternal(ec.getKey(), ec.getValue(), e.getKey().orNull(), true, result, runParams);
if (remember && ec.getValue() >= 1) {
cause.getHostCard().addRemembered(gm.getKey());
}

View File

@@ -19,6 +19,9 @@ public class GameRules {
// same for me
private boolean useGrayText;
// whether to warn about cards AI can't play well
private boolean warnAboutAICards = true;
public GameRules(final GameType type) {
this.gameType = type;
}
@@ -109,4 +112,11 @@ public class GameRules {
public void setUseGrayText(final boolean useGrayText) {
this.useGrayText = useGrayText;
}
public boolean warnAboutAICards() {
return warnAboutAICards;
}
public void setWarnAboutAICards(final boolean warnAboutAICards) {
this.warnAboutAICards = warnAboutAICards;
}
}

View File

@@ -334,7 +334,7 @@ public class Match {
}
final Localizer localizer = Localizer.getInstance();
if (!rAICards.isEmpty() && !rules.getGameType().isCardPoolLimited()) {
if (!rAICards.isEmpty() && !rules.getGameType().isCardPoolLimited() && rules.warnAboutAICards()) {
game.getAction().revealUnplayableByAI(localizer.getMessage("lblAICantPlayCards"), rAICards);
}

View File

@@ -2737,10 +2737,10 @@ public class AbilityUtils {
SpellAbility sa = (SpellAbility) ctb;
if (sa.isReplacementAbility()) {
if (zones.get(0).equals(ZoneType.Battlefield)) {
cardsInZones = sa.getLastStateBattlefield();
cardsInZones = sa.getRootAbility().getLastStateBattlefield();
usedLastState = true;
} else if (zones.get(0).equals(ZoneType.Graveyard)) {
cardsInZones = sa.getLastStateGraveyard();
cardsInZones = sa.getRootAbility().getLastStateGraveyard();
usedLastState = true;
}
}
@@ -2827,11 +2827,6 @@ public class AbilityUtils {
CardCollection filteredCards = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restrictions[1], player, c, ctb);
return doXMath(Aggregates.sum(filteredCards, CardPredicates.Accessors.fnGetNetPower), expr, c, ctb);
}
if (sq[0].startsWith("HighestCMC_")) {
final String restriction = l[0].substring(11);
CardCollection list = CardLists.getValidCards(game.getCardsInGame(), restriction, player, c, ctb);
return Aggregates.max(list, CardPredicates.Accessors.fnGetCmc);
}
if (sq[0].startsWith("DifferentPower_")) {
final String restriction = l[0].substring(15);
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, player, c, ctb);
@@ -3565,7 +3560,7 @@ public class AbilityUtils {
* @return a int.
*/
public static int handlePaid(final Iterable<Card> paidList, final String string, final Card source, CardTraitBase ctb) {
if (paidList == null) {
if (Iterables.isEmpty(paidList)) {
if (string.contains(".")) {
final String[] splitString = string.split("\\.", 2);
return doXMath(0, splitString[1], source, ctb);
@@ -3594,6 +3589,10 @@ public class AbilityUtils {
return Aggregates.sum(paidList, CardPredicates.Accessors.fnGetNetToughness);
}
if (string.startsWith("GreatestCMC")) {
return Aggregates.max(paidList, CardPredicates.Accessors.fnGetCmc);
}
if (string.startsWith("DifferentCMC")) {
final Set<Integer> diffCMC = new HashSet<>();
for (final Card card : paidList) {
@@ -3728,7 +3727,7 @@ public class AbilityUtils {
}
}
// Count$InTargetedLibrary (targeted player's cards in hand)
// Count$InTargetedLibrary (targeted player's cards in library)
if (sq[0].contains("InTargetedLibrary")) {
for (Player tgtP : getDefinedPlayers(c, "TargetedPlayer", ctb)) {
someCards.addAll(tgtP.getCardsIn(ZoneType.Library));

View File

@@ -331,9 +331,24 @@ public abstract class SpellAbilityEffect {
}
protected static void addSelfTrigger(final SpellAbility sa, String location, final Card card) {
String player = "";
String whose = " the ";
if (location.contains("_")) {
String[] locSplit = location.split("_");
player = locSplit[0];
location = locSplit[1];
if (player.equals("You")) {
whose = " your next ";
}
}
String trigStr = "Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield " +
"| TriggerDescription$ At the beginning of the end step, " + location.toLowerCase() + " CARDNAME.";
"| TriggerDescription$ At the beginning of" + whose + "end step, " + location.toLowerCase()
+ " CARDNAME.";
if (!player.equals("")) {
trigStr += " | Player$ " + player;
}
final Trigger trig = TriggerHandler.parseTrigger(trigStr, card, true);
String trigSA = "";
@@ -462,6 +477,8 @@ public abstract class SpellAbilityEffect {
eff.setEmblem(true);
// Emblem needs to be colorless
eff.setColor(MagicColor.COLORLESS);
} else if (sa.hasParam("Boon")) {
eff.setBoon(true);
}
eff.setOwner(controller);
@@ -516,6 +533,9 @@ public abstract class SpellAbilityEffect {
"| Origin$ Battlefield | Destination$ Graveyard " +
"| Description$ If that permanent would die this turn, exile it instead.";
String effect = "DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Battlefield | Destination$ " + zone;
if (sa.hasParam("ReplaceDyingRemember")) {
effect += " | RememberToEffectSource$ True";
}
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other);

View File

@@ -39,7 +39,7 @@ public class AnimateAllEffect extends AnimateEffectBase {
if (sa.hasParam("Toughness")) {
toughness = AbilityUtils.calculateAmount(host, sa.getParam("Toughness"), sa);
}
final Game game = sa.getActivatingPlayer().getGame();
final Game game = host.getGame();
// Every Animate event needs a unique time stamp
final long timestamp = game.getNextTimestamp();
@@ -142,7 +142,7 @@ public class AnimateAllEffect extends AnimateEffectBase {
list = getTargetPlayers(sa).getCardsIn(ZoneType.Battlefield);
}
list = CardLists.getValidCards(list, valid, host.getController(), host, sa);
list = CardLists.getValidCards(list, valid, sa.getActivatingPlayer(), host, sa);
for (final Card c : list) {
doAnimate(c, sa, power, toughness, types, removeTypes, finalColors, keywords, removeKeywords,
@@ -170,6 +170,6 @@ public class AnimateAllEffect extends AnimateEffectBase {
addUntilCommand(sa, unanimate);
}
}
} // animateAllResolve
}
}

View File

@@ -1,6 +1,5 @@
package forge.game.ability.effects;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -789,6 +788,11 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
}
}
if (sa.hasParam("RememberToEffectSource")) {
if (hostCard.isImmutable() && hostCard.getEffectSource() != null) {
hostCard.getEffectSource().addRemembered(movedCard);
}
}
if (remember != null) {
hostCard.addRemembered(movedCard);
// addRememberedFromCardState ?
@@ -1143,16 +1147,15 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
fetchList = CardLists.filter(fetchList, Predicates.not(CardPredicates.sharesCMCWith(c)));
}
}
if (sa.hasParam("DifferentPower")) {
for (Card c : chosenCards) {
fetchList = CardLists.filter(fetchList, Predicates.not(Predicates.compose(Predicates.equalTo(c.getNetPower()), CardPredicates.Accessors.fnGetNetPower)));
}
}
if (sa.hasParam("ShareLandType")) {
// After the first card is chosen, check if the land type is shared
for (final Card card : chosenCards) {
fetchList = CardLists.filter(fetchList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.sharesLandTypeWith(card);
}
});
for (final Card c : chosenCards) {
fetchList = CardLists.filter(fetchList, CardPredicates.sharesLandTypeWith(c));
}
}
if (totalcmc != null) {
@@ -1494,6 +1497,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
&& !sa.hasParam("Mandatory") // only handle optional decisions, for now
&& !sa.hasParam("ShareLandType")
&& !sa.hasParam("DifferentNames")
&& !sa.hasParam("DifferentPower")
&& !sa.hasParam("DifferentCMC")
&& !sa.hasParam("AtRandom")
&& (!sa.hasParam("Defined") || sa.hasParam("ChooseFromDefined"))

View File

@@ -9,9 +9,12 @@ import forge.card.CardType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
public class ChooseTypeEffect extends SpellAbilityEffect {
@@ -58,6 +61,15 @@ public class ChooseTypeEffect extends SpellAbilityEffect {
}
}
}
} else if (sa.hasParam("MostPrevalentInDefinedZone")) {
final String[] info = sa.getParam("MostPrevalentInDefinedZone").split("_");
final Player definedP = AbilityUtils.getDefinedPlayers(sa.getHostCard(), info[0], sa).get(0);
final ZoneType z = info.length > 1 ? ZoneType.smartValueOf(info[1]) : ZoneType.Battlefield;
CardCollectionView zoneCards = definedP.getCardsIn(z);
for (String s : CardFactoryUtil.getMostProminentCreatureType(zoneCards)) {
validTypes.add(s);
}
} else {
validTypes.addAll(CardType.getAllCreatureTypes());
}

View File

@@ -55,7 +55,7 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
}
CardCollectionView cards = game.getCardsIn(zone);
cards = CardLists.getValidCards(cards, valid, host.getController(), host, sa);
cards = CardLists.getValidCards(cards, valid, activator, host, sa);
if (sa.usesTargeting()) {
final Player pl = sa.getTargets().getFirstTargetedPlayer();
@@ -80,7 +80,7 @@ public class CountersPutAllEffect extends SpellAbilityEffect {
ZoneType.smartValueOf(sa.getParam("ValidZone2")) : zone;
if (sa.hasParam("ValidCards2")) {
cards = CardLists.getValidCards(game.getCardsIn(zone2), sa.getParam("ValidCards2"),
host.getController(), host, sa);
activator, host, sa);
if (sa.usesTargeting()) {
cards = CardLists.filterControlledBy(cards, sa.getTargets().getFirstTargetedPlayer());
}

View File

@@ -450,11 +450,12 @@ public class CountersPutEffect extends SpellAbilityEffect {
0);
}
if (sa.hasParam("UpTo")) {
int min = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("UpToMin", "0"), sa);
Map<String, Object> params = Maps.newHashMap();
params.put("Target", obj);
params.put("CounterType", counterType);
counterAmount = pc.chooseNumber(sa,
Localizer.getInstance().getMessage("lblHowManyCounters"), 0, counterAmount, params);
Localizer.getInstance().getMessage("lblHowManyCounters"), min, counterAmount, params);
}
if (sa.isDividedAsYouChoose() && !sa.usesTargeting()) {
Map<String, Object> params = Maps.newHashMap();
@@ -479,6 +480,10 @@ public class CountersPutEffect extends SpellAbilityEffect {
}
}
if (sa.hasParam("ReadAhead")) {
gameCard.setReadAhead(counterAmount);
}
if (sa.hasParam("Tribute")) {
// make a copy to check if it would be on the battlefield
Card noTributeLKI = CardUtil.getLKICopy(gameCard);
@@ -608,8 +613,7 @@ public class CountersPutEffect extends SpellAbilityEffect {
&& !sa.hasParam("CounterTypes") && !sa.hasParam("ChooseDifferent")
&& !sa.hasParam("PutOnEachOther") && !sa.hasParam("PutOnDefined")) {
try {
counterType = chooseTypeFromList(sa, sa.getParam("CounterType"), null,
placer.getController());
counterType = chooseTypeFromList(sa, sa.getParam("CounterType"), null, placer.getController());
} catch (Exception e) {
System.out.println("Counter type doesn't match, nor does an SVar exist with the type name.");
return;

View File

@@ -52,7 +52,7 @@ public class CountersRemoveAllEffect extends SpellAbilityEffect {
final Game game = sa.getActivatingPlayer().getGame();
CardCollectionView cards = game.getCardsIn(zone);
cards = CardLists.getValidCards(cards, valid, sa.getHostCard().getController(), sa.getHostCard(), sa);
cards = CardLists.getValidCards(cards, valid, sa.getActivatingPlayer(), sa.getHostCard(), sa);
if (sa.usesTargeting()) {
final Player pl = sa.getTargets().getFirstTargetedPlayer();

View File

@@ -83,7 +83,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (sa.hasParam("Optional")) {
String ctrs = cntToRemove > 1 ? Localizer.getInstance().getMessage("lblCounters") : num.equals("All") ? Localizer.getInstance().getMessage("lblAllCounters") : Localizer.getInstance().getMessage("lblACounters");
if (!sa.getActivatingPlayer().getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblRemove") + " " + ctrs + "?", null)) {
if (!pc.confirmAction(sa, null, Localizer.getInstance().getMessage("lblRemove") + " " + ctrs + "?", null)) {
return;
}
}
@@ -133,7 +133,7 @@ public class CountersRemoveEffect extends SpellAbilityEffect {
if (num.equals("Any")) {
Map<String, Object> params = Maps.newHashMap();
params.put("CounterType", counterType);
srcCards = player.getController().chooseCardsForEffect(srcCards, sa, title, 0, srcCards.size(), true, params);
srcCards = pc.chooseCardsForEffect(srcCards, sa, title, 0, srcCards.size(), true, params);
}
} else if (sa.hasParam("Choices") && counterType != null) {
ZoneType choiceZone = sa.hasParam("ChoiceZone") ? ZoneType.smartValueOf(sa.getParam("ChoiceZone"))

View File

@@ -65,7 +65,7 @@ public class DamageEachEffect extends DamageBaseEffect {
FCollectionView<Card> sources = game.getCardsIn(ZoneType.Battlefield);
if (sa.hasParam("ValidCards")) {
sources = CardLists.getValidCards(sources, sa.getParam("ValidCards"), card.getController(), card, sa);
sources = CardLists.getValidCards(sources, sa.getParam("ValidCards"), sa.getActivatingPlayer(), card, sa);
}
final List<GameObject> tgts = getTargets(sa, "DefinedPlayers");
@@ -121,7 +121,7 @@ public class DamageEachEffect extends DamageBaseEffect {
final int dmg = AbilityUtils.calculateAmount(source, "X", sa);
final Card sourceLKI = source.getGame().getChangeZoneLKIInfo(source);
for (final Object o : sa.getHostCard().getRemembered()) {
for (final Object o : card.getRemembered()) {
if (o instanceof Card) {
Card rememberedcard = (Card) o;
damageMap.put(sourceLKI, rememberedcard, dmg);

View File

@@ -122,7 +122,7 @@ public class EffectEffect extends SpellAbilityEffect {
String name = sa.getParam("Name");
if (name == null) {
name = hostCard.getName() + "'s Effect";
name = hostCard.getName() + (sa.hasParam("Boon") ? "'s Boon" : "'s Effect");
}
// Unique Effects shouldn't be duplicated
@@ -226,6 +226,8 @@ public class EffectEffect extends SpellAbilityEffect {
if (!"Stack".equals(sa.getParam("ForgetOnMoved"))) {
addForgetOnCastTrigger(eff);
}
} else if (sa.hasParam("ForgetOnCast")) {
addForgetOnCastTrigger(eff);
} else if (sa.hasParam("ExileOnMoved")) {
addExileOnMovedTrigger(eff, sa.getParam("ExileOnMoved"));
}
@@ -277,6 +279,14 @@ public class EffectEffect extends SpellAbilityEffect {
eff.setNamedCard(hostCard.getNamedCard());
}
// chosen number
if (sa.hasParam("SetChosenNumber")) {
eff.setChosenNumber(AbilityUtils.calculateAmount(sa.getHostCard(),
sa.getParam("SetChosenNumber"), sa));
} else if (hostCard.hasChosenNumber()) {
eff.setChosenNumber(hostCard.getChosenNumber());
}
if (sa.hasParam("CopySVar")) {
eff.setSVar(sa.getParam("CopySVar"), hostCard.getSVar(sa.getParam("CopySVar")));
}

View File

@@ -37,11 +37,11 @@ public class LifeSetEffect extends SpellAbilityEffect {
for (final Player p : players.threadSafeIterable()) {
if (tgt == null || p.canBeTargetedBy(sa)) {
if (!redistribute) {
p.setLife(lifeAmount, sa.getHostCard());
p.setLife(lifeAmount, sa);
} else {
List<Integer> validChoices = getDistribution(players, true, lifetotals);
int life = sa.getActivatingPlayer().getController().chooseNumber(sa, Localizer.getInstance().getMessage("lblLifeTotal") + ": " + p, validChoices, p);
p.setLife(life, sa.getHostCard());
p.setLife(life, sa);
lifetotals.remove((Integer) life);
players.remove(p);
}

View File

@@ -1,10 +1,11 @@
package forge.game.ability.effects;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.card.ICardFace;
import forge.game.Game;
@@ -17,6 +18,7 @@ import forge.game.card.CardZoneTable;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.CardTranslation;
@@ -34,18 +36,25 @@ public class MakeCardEffect extends SpellAbilityEffect {
for (final Player player : players) {
final Game game = player.getGame();
String name = sa.getParamOrDefault("Name", "");
if (name.equals("ChosenName")) {
if (sa.getHostCard().hasChosenName()) {
name = sa.getHostCard().getChosenName();
List<String> names = Lists.newArrayList();
if (sa.hasParam("Name")) {
final String n = sa.getParam("Name");
if (n.equals("ChosenName")) {
if (source.hasChosenName()) {
names.add(source.getChosenName());
} else {
System.err.println("Malformed MakeCard entry! - " + source.toString());
}
} else {
continue;
names.add(n);
}
}
if (sa.hasParam("DefinedName")) {
final CardCollection def = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedName"), sa);
if (def.size() > 0) {
name = def.getFirst().getName();
for (final Card c : def) {
names.add(c.getName());
}
}
} else if (sa.hasParam("Spellbook")) {
List<String> spellbook = Arrays.asList(sa.getParam("Spellbook").split(","));
@@ -56,43 +65,61 @@ public class MakeCardEffect extends SpellAbilityEffect {
faces.add(StaticData.instance().getCommonCards().getFaceByName(s));
}
if (sa.hasParam("AtRandom")) {
name = Aggregates.random(faces).getName();
names.add(Aggregates.random(faces).getName());
} else {
name = player.getController().chooseCardName(sa, faces,
Localizer.getInstance().getMessage("lblChooseFromSpellbook", CardTranslation.getTranslatedName(source.getName())));
names.add(player.getController().chooseCardName(sa, faces,
Localizer.getInstance().getMessage("lblChooseFromSpellbook",
CardTranslation.getTranslatedName(source.getName()))));
}
}
final ZoneType zone = ZoneType.smartValueOf(sa.getParamOrDefault("Zone", "Library"));
int amount = sa.hasParam("Amount") ?
AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa) : 1;
final int amount = sa.hasParam("Amount") ?
AbilityUtils.calculateAmount(source, sa.getParam("Amount"), sa) : 1;
CardCollection cards = new CardCollection();
if (!name.equals("")) {
while (amount > 0) {
Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), player);
card.setTokenCard(true);
game.getAction().moveTo(ZoneType.None, card, sa, moveParams);
cards.add(card);
amount--;
for (final String name : names) {
int toMake = amount;
if (!name.equals("")) {
while (toMake > 0) {
Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name),
player);
if (sa.hasParam("TokenCard")) {
card.setTokenCard(true);
}
game.getAction().moveTo(ZoneType.None, card, sa, moveParams);
cards.add(card);
toMake--;
}
}
}
final CardZoneTable triggerList = new CardZoneTable();
for (final Card c : cards) {
Card made = game.getAction().moveTo(zone, c, sa, moveParams);
triggerList.put(ZoneType.None, made.getZone().getZoneType(), made);
if (sa.hasParam("RememberMade")) {
sa.getHostCard().addRemembered(made);
}
if (sa.hasParam("ImprintMade")) {
sa.getHostCard().addImprintedCard(made);
}
final CardZoneTable triggerList = new CardZoneTable();
CardCollection madeCards = new CardCollection();
for (final Card c : cards) {
Card made = game.getAction().moveTo(zone, c, sa, moveParams);
triggerList.put(ZoneType.None, made.getZone().getZoneType(), made);
madeCards.add(made);
if (sa.hasParam("RememberMade")) {
source.addRemembered(made);
}
triggerList.triggerChangesZoneAll(game, sa);
if (zone.equals(ZoneType.Library)) {
player.shuffle(sa);
if (sa.hasParam("ImprintMade")) {
source.addImprintedCard(made);
}
}
triggerList.triggerChangesZoneAll(game, sa);
if (sa.hasParam("Conjure")) {
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Player, player);
runParams.put(AbilityKey.Cards, madeCards);
runParams.put(AbilityKey.Cause, sa); //-- currently not needed
game.getTriggerHandler().runTrigger(TriggerType.ConjureAll, runParams, false);
}
if (zone.equals(ZoneType.Library)) {
player.shuffle(sa);
}
}
}
}

View File

@@ -91,8 +91,8 @@ public class PlayEffect extends SpellAbilityEffect {
final boolean imprint = sa.hasParam("ImprintPlayed");
final boolean forget = sa.hasParam("ForgetPlayed");
final boolean hasTotalCMCLimit = sa.hasParam("WithTotalCMC");
int amount = 1;
int totalCMCLimit = Integer.MAX_VALUE;
int amount = 1;
if (sa.hasParam("Amount") && !sa.getParam("Amount").equals("All")) {
amount = AbilityUtils.calculateAmount(source, sa.getParam("Amount"), sa);
}

View File

@@ -4,12 +4,15 @@ import forge.card.CardStateName;
import forge.game.Game;
import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.*;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Lang;
@@ -17,19 +20,28 @@ import forge.util.Localizer;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
public class SetStateEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(final SpellAbility sa) {
final Card host = sa.getHostCard();
final StringBuilder sb = new StringBuilder();
boolean specialize = sa.getParam("Mode").equals("Specialize");
if (sa.hasParam("Flip")) {
sb.append("Flip ");
} else if (specialize) { // verb will come later
} else {
sb.append("Transform ");
}
sb.append(Lang.joinHomogenous(getTargetCards(sa)));
if (specialize) {
sb.append(" perpetually specializes into ");
sb.append(host.hasChosenColor() ? host.getChosenColor() : "the chosen color");
}
sb.append(".");
return sb.toString();
}
@@ -87,7 +99,9 @@ public class SetStateEffect extends SpellAbilityEffect {
// Cards which are not on the battlefield should not be able to transform.
// TurnFace should be allowed in other zones like Exile too
if (!"TurnFace".equals(mode) && !gameCard.isInPlay() && !sa.hasParam("ETB")) {
// Specialize and Unspecialize are allowed in other zones
if (!"TurnFace".equals(mode) && !"Unspecialize".equals(mode) && !"Specialize".equals(mode)
&& !gameCard.isInPlay() && !sa.hasParam("ETB")) {
continue;
}
@@ -160,6 +174,9 @@ public class SetStateEffect extends SpellAbilityEffect {
hasTransformed = gameCard.turnFaceUp(sa);
} else if (sa.isManifestUp()) {
hasTransformed = gameCard.turnFaceUp(true, true, sa);
} else if ("Specialize".equals(mode)) {
hasTransformed = gameCard.changeCardState(mode, host.getChosenColor(), sa);
host.setChosenColors(null);
} else {
hasTransformed = gameCard.changeCardState(mode, sa.getParam("NewState"), sa);
if (gameCard.isFaceDown() && (sa.hasParam("FaceDownPower") || sa.hasParam("FaceDownToughness")
@@ -193,6 +210,17 @@ public class SetStateEffect extends SpellAbilityEffect {
}
if (!gameCard.isDoubleFaced())
transformedCards.add(gameCard);
if ("Specialize".equals(mode)) {
gameCard.setSpecialized(true);
//run Specializes trigger
final TriggerHandler th = game.getTriggerHandler();
th.clearActiveTriggers(gameCard, null);
th.registerActiveTrigger(gameCard, false);
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(gameCard);
th.runTrigger(TriggerType.Specializes, runParams, false);
} else if ("Unspecialize".equals(mode)) {
gameCard.setSpecialized(false);
}
}
}
table.replaceCounterEffect(game, sa, true);

View File

@@ -37,7 +37,7 @@ public class UntapAllEffect extends SpellAbilityEffect {
}
list = list2;
}
list = CardLists.getValidCards(list, valid, card.getController(), card, sa);
list = CardLists.getValidCards(list, valid, sa.getActivatingPlayer(), card, sa);
boolean remember = sa.hasParam("RememberUntapped");
for (Card c : list) {

View File

@@ -212,6 +212,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private boolean foretoldThisTurn;
private boolean foretoldByEffect;
private boolean specialized;
private int timesCrewedThisTurn = 0;
private int classLevel = 1;
@@ -239,6 +241,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// for Vanguard / Manapool / Emblems etc.
private boolean isImmutable = false;
private boolean isEmblem = false;
private boolean isBoon = false;
private int exertThisTurn = 0;
private PlayerCollection exertedByPlayer = new PlayerCollection();
@@ -336,6 +339,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private ReplacementEffect shieldCounterReplaceDestroy = null;
private ReplacementEffect stunCounterReplaceUntap = null;
private Integer readAhead = null;
// Enumeration for CMC request types
public enum SplitCMCMode {
CurrentSideCMC,
@@ -661,6 +666,20 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
} else if (mode.equals("Meld") && isMeldable()) {
return changeToState(CardStateName.Meld);
} else if (mode.equals("Specialize") && canSpecialize()) {
if (customState.equalsIgnoreCase("white")) {
return changeToState(CardStateName.SpecializeW);
} else if (customState.equalsIgnoreCase("blue")) {
return changeToState(CardStateName.SpecializeU);
} else if (customState.equalsIgnoreCase("black")) {
return changeToState(CardStateName.SpecializeB);
} else if (customState.equalsIgnoreCase("red")) {
return changeToState(CardStateName.SpecializeR);
} else if (customState.equalsIgnoreCase("green")) {
return changeToState(CardStateName.SpecializeG);
}
} else if (mode.equals("Unspecialize") && isSpecialized()) {
return changeToState(CardStateName.Original);
}
return false;
}
@@ -1370,6 +1389,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
public final boolean hasDoubleStrike() {
return hasKeyword(Keyword.DOUBLE_STRIKE);
}
public final boolean hasDoubleTeam() {
return hasKeyword(Keyword.DOUBLE_TEAM);
}
public final boolean hasSecondStrike() {
return hasDoubleStrike() || !hasFirstStrike();
@@ -1389,7 +1412,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
@Override
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table) {
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
int addAmount = n;
if (addAmount <= 0 || !canReceiveCounters(counterType)) {
// As per rule 107.1b
@@ -1423,6 +1446,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
runParams.put(AbilityKey.Source, source);
runParams.put(AbilityKey.CounterType, counterType);
if (params != null) {
runParams.putAll(params);
}
for (int i = 0; i < addAmount; i++) {
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
getGame().getTriggerHandler().runTrigger(
@@ -2093,12 +2119,18 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
sbLong.append("Trample over planeswalkers").append(" (").append(inst.getReminderText()).append(")").append("\r\n");
} else if (keyword.startsWith("Hexproof:")) {
final String[] k = keyword.split(":");
sbLong.append("Hexproof from ");
if (k[2].equals("chosen")) {
k[2] = k[1].substring(5).toLowerCase();
if(!k[2].equals("Secondary")) {
sbLong.append("Hexproof from ");
if (k[2].equals("chosen")) {
k[2] = k[1].substring(5).toLowerCase();
}
sbLong.append(k[2]);
if (!k[2].contains(" and ")) { // skip reminder text for more complicated Hexproofs
sbLong.append(" (").append(inst.getReminderText().replace("chosen", k[2]));
sbLong.append(")");
}
sbLong.append("\r\n");
}
sbLong.append(k[2]).append(" (").append(inst.getReminderText().replace("chosen", k[2]))
.append(")").append("\r\n");
} else if (inst.getKeyword().equals(Keyword.COMPANION)) {
sbLong.append("Companion — ");
sbLong.append(((Companion)inst).getDescription());
@@ -2117,6 +2149,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|| keyword.equals("Living Weapon") || keyword.equals("Myriad") || keyword.equals("Exploit")
|| keyword.equals("Changeling") || keyword.equals("Delve") || keyword.equals("Decayed")
|| keyword.equals("Split second") || keyword.equals("Sunburst")
|| keyword.equals("Double team")
|| keyword.equals("Suspend") // for the ones without amount
|| keyword.equals("Foretell") // for the ones without cost
|| keyword.equals("Ascend") || keyword.equals("Totem armor")
@@ -2217,11 +2250,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|| keyword.startsWith("Embalm") || keyword.startsWith("Level up") || keyword.equals("Prowess")
|| keyword.startsWith("Eternalize") || keyword.startsWith("Reinforce")
|| keyword.startsWith("Champion") || keyword.startsWith("Prowl") || keyword.startsWith("Adapt")
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Saga")
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Saga") || keyword.startsWith("Read ahead")
|| keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap")
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")
|| keyword.startsWith("Encore") || keyword.startsWith("Mutate") || keyword.startsWith("Dungeon")
|| keyword.startsWith("Class") || keyword.startsWith("Blitz")) {
|| keyword.startsWith("Class") || keyword.startsWith("Blitz")
|| keyword.startsWith("Specialize")) {
// keyword parsing takes care of adding a proper description
} else if (keyword.equals("Unblockable")) {
sbLong.append(getName()).append(" can't be blocked.\r\n");
@@ -2242,7 +2276,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
keyword = keyword.replace("Strike", "strike");
}
sb.append(i !=0 && sb.length() !=0 ? ", " : "");
sb.append(i > 0 && sb.length() !=0 ? keyword.toLowerCase() : keyword);
sb.append(i > 0 && sb.length() !=0 ? StringUtils.uncapitalize(keyword) : keyword);
}
if (sbLong.length() > 0) {
sbLong.append("\r\n");
@@ -3980,6 +4014,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
public final CardStateName getFaceupCardStateName() {
if (isFlipped() && hasState(CardStateName.Flipped)) {
return CardStateName.Flipped;
} else if (isSpecialized()) {
return getCurrentStateName();
} else if (backside && hasBackSide()) {
CardStateName stateName = getRules().getSplitType().getChangedStateName();
if (hasState(stateName)) {
@@ -4501,7 +4537,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
return result;
}
public final void addKeywordForStaticAbility(KeywordInterface kw) {
if (kw.getStaticId() > 0) {
storedKeywords.put(kw.getStaticId(), kw.getOriginal(), kw);
@@ -5185,6 +5221,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
public final boolean isEmblem() {
return isEmblem;
}
public final void setBoon(final boolean isBoon0) {
isBoon = isBoon0;
view.updateBoon(this);
}
public final boolean isBoon() {
return isBoon;
}
public final void setEmblem(final boolean isEmblem0) {
isEmblem = isEmblem0;
view.updateEmblem(this);
@@ -5730,6 +5775,16 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
foretoldThisTurn = false;
}
public boolean isSpecialized() {
return specialized;
}
public final void setSpecialized(final boolean bool) {
specialized = bool;
}
public final boolean canSpecialize() {
return getRules() != null && getRules().getSplitType() == CardSplitType.Specialize;
}
public int getTimesCrewedThisTurn() {
return timesCrewedThisTurn;
}
@@ -7103,4 +7158,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
}
return StaticAbilityIgnoreLegendRule.ignoreLegendRule(this);
}
public Integer getReadAhead() {
return readAhead;
}
public void setReadAhead(int value) {
readAhead = value;
}
public boolean attackVigilance() {
return StaticAbilityAttackVigilance.attackVigilance(this);
}
}

View File

@@ -104,7 +104,7 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
game.getTriggerHandler().runTrigger(TriggerType.DamageAll, runParams, false);
}
public void triggerExcessDamage(boolean isCombat, Map<Card, Integer> lethalDamage, final Game game) {
public void triggerExcessDamage(boolean isCombat, Map<Card, Integer> lethalDamage, final Game game, final Map<Integer, Card> lkiCache) {
for (Entry<Card, Integer> damaged : lethalDamage.entrySet()) {
int sum = 0;
for (Integer i : this.column(damaged.getKey()).values()) {
@@ -112,6 +112,10 @@ public class CardDamageMap extends ForwardingTable<Card, GameEntity, Integer> {
}
int excess = sum - (damaged.getKey().hasBeenDealtDeathtouchDamage() ? 1 : damaged.getValue());
// also update the DamageHistory, but overwrite previous excess outcomes
// because Rith, Liberated Primeval cares about who controlled it at this moment
lkiCache.get(damaged.getKey().getId()).setHasBeenDealtExcessDamageThisTurn(excess > 0);
if (excess > 0) {
damaged.getKey().setHasBeenDealtExcessDamageThisTurn(true);
// Run triggers

View File

@@ -77,7 +77,7 @@ public class CardFactory {
*/
public final static Card copyCard(final Card in, boolean assignNewId) {
Card out;
if (!(in.isToken() || in.getCopiedPermanent() != null)) {
if (!(in.isRealToken() || in.getCopiedPermanent() != null)) {
out = assignNewId ? getCard(in.getPaperCard(), in.getOwner(), in.getGame())
: getCard(in.getPaperCard(), in.getOwner(), in.getId(), in.getGame());
} else { // token
@@ -97,6 +97,7 @@ public class CardFactory {
out.setAttachedCards(in.getAttachedCards());
out.setEntityAttachedTo(in.getEntityAttachedTo());
out.setSpecialized(in.isSpecialized());
out.addRemembered(in.getRemembered());
out.addImprintedCards(in.getImprintedCards());
out.setCommander(in.isRealCommander());
@@ -364,7 +365,33 @@ public class CardFactory {
readCardFace(card, rules.getMainPart());
if (st != CardSplitType.None) {
if (st == CardSplitType.Specialize) {
card.addAlternateState(CardStateName.SpecializeW, false);
card.setState(CardStateName.SpecializeW, false);
if (rules.getWSpecialize() != null) {
readCardFace(card, rules.getWSpecialize());
}
card.addAlternateState(CardStateName.SpecializeU, false);
card.setState(CardStateName.SpecializeU, false);
if (rules.getUSpecialize() != null) {
readCardFace(card, rules.getUSpecialize());
}
card.addAlternateState(CardStateName.SpecializeB, false);
card.setState(CardStateName.SpecializeB, false);
if (rules.getBSpecialize() != null) {
readCardFace(card, rules.getBSpecialize());
}
card.addAlternateState(CardStateName.SpecializeR, false);
card.setState(CardStateName.SpecializeR, false);
if (rules.getRSpecialize() != null) {
readCardFace(card, rules.getRSpecialize());
}
card.addAlternateState(CardStateName.SpecializeG, false);
card.setState(CardStateName.SpecializeG, false);
if (rules.getGSpecialize() != null) {
readCardFace(card, rules.getGSpecialize());
}
} else if (st != CardSplitType.None) {
card.addAlternateState(st.getChangedStateName(), false);
card.setState(st.getChangedStateName(), false);
if (rules.getOtherPart() != null) {

View File

@@ -162,14 +162,12 @@ public class CardFactoryUtil {
*/
public static SpellAbility abilityMorphUp(final CardState cardState, final String costStr, final boolean mega) {
Cost cost = new Cost(costStr, true);
String costDesc = cost.toString();
StringBuilder sbCost = new StringBuilder(mega ? "Megamorph" : "Morph");
sbCost.append(" ");
if (!cost.isOnlyManaCost()) {
sbCost.append("");
}
// get rid of the ": " at the end
sbCost.append(costDesc, 0, costDesc.length() - 2);
sbCost.append(cost.toString());
StringBuilder sb = new StringBuilder();
sb.append("ST$ SetState | Cost$ ").append(costStr).append(" | CostDesc$ ").append(sbCost);
@@ -957,8 +955,9 @@ public class CardFactoryUtil {
inst.addTrigger(parsedTrigger);
inst.addTrigger(parsedTrigReturn);
} else if (keyword.startsWith("Casualty")) {
final String trigScript = "Mode$ SpellCast | ValidCard$ Card.Self | CheckSVar$ Casualty | TriggerZones$ Stack | Secondary$ True";
String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | Amount$ 1 | MayChooseTarget$ True";
final String trigScript = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerZones$ Stack | " +
"CheckSVar$ CasualtyPaid | Secondary$ True";
String abString = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True";
String[] k = keyword.split(":");
if (k.length > 2) {
abString = abString + " | " + k[2];
@@ -967,6 +966,7 @@ public class CardFactoryUtil {
final Trigger casualtyTrigger = TriggerHandler.parseTrigger(trigScript, card, intrinsic);
casualtyTrigger.setOverridingAbility(AbilityFactory.getAbility(abString, card));
casualtyTrigger.setSVar("Casualty", "0");
casualtyTrigger.setSVar("CasualtyPaid", "0");
inst.addTrigger(casualtyTrigger);
} else if (keyword.equals("Conspire")) {
@@ -1063,6 +1063,23 @@ public class CardFactoryUtil {
dethroneTrigger.setOverridingAbility(AbilityFactory.getAbility(abString, card));
inst.addTrigger(dethroneTrigger);
} else if (keyword.equals("Double team")) {
final String trigString = "Mode$ Attacks | ValidCard$ Card.Self+nonToken | TriggerZones$ Battlefield" +
" | Secondary$ True | TriggerDescription$ Double team (" + inst.getReminderText() + ")";
final String makeString = "DB$ MakeCard | DefinedName$ Self | Zone$ Hand | RememberMade$ True | Conjure$ True";
final String forgetString = "DB$ Effect | Duration$ Permanent | RememberObjects$ Remembered | ImprintCards$ TriggeredAttacker | StaticAbilities$ RemoveDoubleTeamMade";
final String madeforgetmadeString = "Mode$ Continuous | EffectZone$ Command | Affected$ Card.IsRemembered,Card.IsImprinted | RemoveKeyword$ Double team | AffectedZone$ Battlefield,Hand,Graveyard,Exile,Stack,Library,Command | Description$ Both cards perpetually lose double team.";
final String CleanupString = "DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True";
final Trigger trigger = TriggerHandler.parseTrigger(trigString, card, intrinsic);
final SpellAbility youMake = AbilityFactory.getAbility(makeString, card);
final AbilitySub forget = (AbilitySub) AbilityFactory.getAbility(forgetString, card);
final AbilitySub Cleanup = (AbilitySub) AbilityFactory.getAbility(CleanupString, card);
forget.setSVar("RemoveDoubleTeamMade",madeforgetmadeString);
youMake.setSubAbility(forget);
forget.setSubAbility(Cleanup);
trigger.setOverridingAbility(youMake);
inst.addTrigger(trigger);
} else if (keyword.startsWith("Echo")) {
final String[] k = keyword.split(":");
final String cost = k[1];
@@ -1697,7 +1714,7 @@ public class CardFactoryUtil {
parsedTrigger.setOverridingAbility(sa);
inst.addTrigger(parsedTrigger);
} else if (keyword.startsWith("Saga")) {
} else if (keyword.startsWith("Saga") || keyword.startsWith("Read ahead")) {
final String[] k = keyword.split(":");
final List<String> abs = Arrays.asList(k[2].split(","));
if (abs.size() != Integer.valueOf(k[1])) {
@@ -1724,9 +1741,10 @@ public class CardFactoryUtil {
for (int i = idx; i <= skipId; i++) {
SpellAbility sa = AbilityFactory.getAbility(card, ab);
sa.setChapter(i);
sa.setLastChapter(idx == abs.size());
StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
trigStr.append("| CounterType$ LORE | CounterAmount$ EQ").append(i);
trigStr.append("| Chapter$ True | CounterType$ LORE | CounterAmount$ EQ").append(i);
if (i != idx) {
trigStr.append(" | Secondary$ True");
}
@@ -2311,6 +2329,23 @@ public class CardFactoryUtil {
re.getOverridingAbility().setSVar("Sunburst", "Count$Converge");
}
inst.addReplacement(re);
} else if (keyword.startsWith("Read ahead")) {
final String[] k = keyword.split(":");
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | Secondary$ True | ReplacementResult$ Updated | Description$ Choose a chapter and start with that many lore counters.";
String effStr = "DB$ PutCounter | Defined$ Self | CounterType$ LORE | ETB$ True | UpTo$ True | UpToMin$ 1 | ReadAhead$ True | CounterNum$ " + k[1];
SpellAbility saCounter = AbilityFactory.getAbility(effStr, card);
if (!intrinsic) {
saCounter.setIntrinsic(false);
}
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, host, intrinsic, card);
re.setOverridingAbility(saCounter);
inst.addReplacement(re);
} else if (keyword.equals("Rebound")) {
String repeffstr = "Event$ Moved | ValidLKI$ Card.Self+wasCastFromHand+YouOwn+YouCtrl "
+ " | Origin$ Stack | Destination$ Graveyard | Fizzle$ False "
@@ -3215,6 +3250,22 @@ public class CardFactoryUtil {
final AbilitySub cleanSub = (AbilitySub) AbilityFactory.getAbility(cleanStr, card);
effectSub.setSubAbility(cleanSub);
sa.setIntrinsic(intrinsic);
inst.addSpellAbility(sa);
} else if (keyword.startsWith("Specialize")) {
final String[] k = keyword.split(":");
final String cost = k[1];
String flavor = k.length > 2 && !k[2].isEmpty() ? k[2] + " " : "";
String condition = k.length > 3 && !k[3].isEmpty() ? ". " + k[3] : "";
String extra = k.length > 4 && !k[4].isEmpty() ? k[4] + " | " : "";
final String effect = "AB$ SetState | Cost$ " + cost + " ChooseColor<1> Discard<1/Card.ChosenColor;" +
"Card.AssociatedWithChosenColor/card of the chosen color or its associated basic land type> | " +
"Mode$ Specialize | SorcerySpeed$ True | " + extra + "PrecostDesc$ " + flavor + "Specialize | " +
"CostDesc$ " + ManaCostParser.parse(cost) + condition + " | SpellDescription$ (" +
inst.getReminderText() + ")";
final SpellAbility sa = AbilityFactory.getAbility(effect, card);
sa.setIntrinsic(intrinsic);
inst.addSpellAbility(sa);
} else if (keyword.startsWith("Spectacle")) {
@@ -3660,6 +3711,9 @@ public class CardFactoryUtil {
String effect = "Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Secondary$ True"
+ "| Amount$ Undaunted | EffectZone$ All | Description$ Undaunted (" + inst.getReminderText() + ")";
inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic));
} else if (keyword.equals("Vigilance")) {
String effect = "Mode$ AttackVigilance | ValidCard$ Card.Self | Secondary$ True | Description$ Vigilance (" + inst.getReminderText() + ")";
inst.addStaticAbility(StaticAbility.create(effect, state.getCard(), state, intrinsic));
} else if (keyword.equals("MayFlashSac")) {
String effect = "Mode$ Continuous | EffectZone$ All | Affected$ Card.Self | Secondary$ True | MayPlay$ True"
+ " | MayPlayNotSorcerySpeed$ True | MayPlayWithFlash$ True | MayPlayText$ Sacrifice at the next cleanup step"

View File

@@ -246,6 +246,13 @@ public class CardView extends GameEntityView {
set(TrackableProperty.IsEmblem, c.isEmblem());
}
public boolean isBoon() {
return get(TrackableProperty.IsBoon);
}
public void updateBoon(Card c) {
set(TrackableProperty.IsBoon, c.isBoon());
}
public boolean isTokenCard() { return get(TrackableProperty.TokenCard); }
void updateTokenCard(Card c) { set(TrackableProperty.TokenCard, c.isTokenCard()); }
@@ -449,7 +456,7 @@ public class CardView extends GameEntityView {
return get(TrackableProperty.Remembered);
}
void updateRemembered(Card c) {
if (c.getRemembered() == null || Iterables.size(c.getRemembered()) == 0) {
if (c.getRemembered() == null || Iterables.isEmpty(c.getRemembered())) {
set(TrackableProperty.Remembered, null);
return;
}
@@ -1364,6 +1371,7 @@ public class CardView extends GameEntityView {
public boolean hasDefender() { return get(TrackableProperty.HasDefender); }
public boolean hasDivideDamage() { return get(TrackableProperty.HasDivideDamage); }
public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); }
public boolean hasDoubleTeam() { return get(TrackableProperty.HasDoubleTeam); }
public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); }
public boolean hasFlying() { return get(TrackableProperty.HasFlying); }
public boolean hasFear() { return get(TrackableProperty.HasFear); }

View File

@@ -183,6 +183,8 @@ public enum CounterEnumType {
INFECTION("INFCT", 0, 230, 66),
INGENUITY("INGTY", 67, 186, 205),
INTERVENTION("INTRV", 205, 203, 105),
INVITATION("INVIT", 205, 0, 26),
@@ -265,6 +267,8 @@ public enum CounterEnumType {
PHYLACTERY("PHYLA", 117, 219, 153),
PHYRESIS("PHYRE", 125, 97, 128),
POINT("POINT", 153, 255, 130),
POLYP("POLYP", 236, 185, 198),

View File

@@ -341,6 +341,13 @@ public class Cost implements Serializable {
return new CostUnattach(splitStr[0], description);
}
if (parse.startsWith("ChooseColor<")) {
// ChooseColor<NumToChoose>
//TODO expand this to set off different UI for Specialize
final String[] splitStr = abCostParse(parse, 1);
return new CostChooseColor(splitStr[0]);
}
if (parse.startsWith("ChooseCreatureType<")) {
final String[] splitStr = abCostParse(parse, 1);
return new CostChooseCreatureType(splitStr[0]);

View File

@@ -398,7 +398,7 @@ public class CostAdjustment {
return Math.min(value, maxReduction);
}
} else {
final String color = staticAbility.getParamOrDefault("Cost", staticAbility.getParam("Color"));
final String color = staticAbility.getParamOrDefault("Cost", staticAbility.getParam("Color"));
int sumGeneric = 0;
// might be problematic for wierd hybrid combinations
for (final String cost : color.split(" ")) {
@@ -433,10 +433,6 @@ public class CostAdjustment {
if (!st.matchesValidParam("Activator", activator)) {
return false;
}
if (st.hasParam("NonActivatorTurn") && (activator == null
|| game.getPhaseHandler().isPlayerTurn(activator))) {
return false;
}
if (st.hasParam("Type")) {
final String type = st.getParam("Type");
@@ -556,4 +552,4 @@ public class CostAdjustment {
}
return true;
}
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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.game.cost;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
/**
* the class CostChooseColor
*/
public class CostChooseColor extends CostPart {
/**
* Serializables need a version ID.
*/
private static final long serialVersionUID = 1L;
/**
* Instantiates a new cost choose color.
*
* @param amount
* the amount
*/
public CostChooseColor(final String amount) {
this.setAmount(amount);
}
/*
* (non-Javadoc)
*
* @see
* forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility,
* forge.Card, forge.Player, forge.card.cost.Cost)
*/
@Override
public final boolean canPay(final SpellAbility ability, final Player payer, final boolean effect) {
return true;
}
@Override
public boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa, final boolean effect) {
sa.getHostCard().setChosenColors(pd.colors);
return true;
}
@Override
public int paymentOrder() { return 8; }
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#toString()
*/
@Override
public final String toString() {
final StringBuilder sb = new StringBuilder();
final Integer i = this.convertAmount();
sb.append("Choose ");
sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), "color"));
return sb.toString();
}
@Override
public boolean isUndoable() { return true; }
/*
* (non-Javadoc)
*
* @see forge.card.cost.CostPart#refund(forge.Card)
*/
@Override
public final void refund(final Card source) {
source.setChosenColors(null);
}
@Override
public <T> T accept(ICostVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -166,7 +166,9 @@ public class CostDiscard extends CostPartWithList {
sameName = true;
type = TextUtil.fastReplace(type, "+WithSameName", "");
}
if (!type.equals("Random") && !type.contains("X")) {
if (type.contains("ChosenColor") && !source.hasChosenColor()) {
//color hasn't been chosen yet, so skip getValidCards
} else if (!type.equals("Random") && !type.contains("X")) {
// Knollspine Invocation fails to activate without the above conditional
handList = CardLists.getValidCards(handList, type.split(";"), payer, source, ability);
}

View File

@@ -20,13 +20,12 @@ package forge.game.cost;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicate;
import forge.game.GameLogEntryType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
@@ -90,12 +89,7 @@ public class CostReveal extends CostPartWithList {
return true;
} else if (this.getType().equals("SameColor")) {
for (final Card card : handList) {
if (CardLists.filter(handList, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return c.sharesColorWith(card);
}
}).size() >= amount) {
if (CardLists.count(handList, CardPredicates.sharesColorWith(card)) >= amount) {
return true;
}
}

View File

@@ -3,6 +3,7 @@ package forge.game.cost;
public interface ICostVisitor<T> {
T visit(CostGainControl cost);
T visit(CostChooseColor cost);
T visit(CostChooseCreatureType cost);
T visit(CostDiscard cost);
T visit(CostDamage cost);
@@ -40,6 +41,11 @@ public interface ICostVisitor<T> {
return null;
}
@Override
public T visit(CostChooseColor cost) {
return null;
}
@Override
public T visit(CostChooseCreatureType cost) {
return null;

View File

@@ -13,6 +13,7 @@ import forge.util.TextUtil;
public class PaymentDecision {
public int c = 0;
public String type;
public List<String> colors;
public final CardCollection cards = new CardCollection();
public final List<Mana> mana;
@@ -48,6 +49,11 @@ public class PaymentDecision {
type = choice;
}
public PaymentDecision(List<String> choices) {
this(null, null, null, null, null);
colors = choices;
}
public static PaymentDecision card(Card chosen) {
return new PaymentDecision(chosen);
}
@@ -88,6 +94,10 @@ public class PaymentDecision {
return new PaymentDecision(choice);
}
public static PaymentDecision colors(List<String> choices) {
return new PaymentDecision(choices);
}
public static PaymentDecision players(List<Player> players) {
return new PaymentDecision(null, null, players, null, null);
}

View File

@@ -60,6 +60,7 @@ public enum Keyword {
DEVOID("Devoid", SimpleKeyword.class, true, "This card has no color."),
DISTURB("Disturb", KeywordWithCost.class, false, "You may cast this card from your graveyard transformed for its disturb cost."),
DOUBLE_STRIKE("Double Strike", SimpleKeyword.class, true, "This creature deals both first-strike and regular combat damage."),
DOUBLE_TEAM("Double team", SimpleKeyword.class, true, "When this creature attacks, if it's not a token, conjure a duplicate of it into your hand. Then both cards perpetually lose double team."),
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."),
EMBALM("Embalm", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: Create a token that's a copy of this card, except it's white, it has no mana cost, and it's a Zombie in addition to its other types. Embalm only as a sorcery."),
@@ -153,6 +154,7 @@ public enum Keyword {
SCAVENGE("Scavenge", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: Put a number of +1/+1 counters equal to this card's power on target creature. Scavenge only as a sorcery."),
SOULBOND("Soulbond", SimpleKeyword.class, true, "You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them."),
SOULSHIFT("Soulshift", KeywordWithAmount.class, false, "When this creature dies, you may return target Spirit card with mana value %d or less from your graveyard to your hand."),
SPECIALIZE("Specialize", KeywordWithCost.class, false, "%s, Choose a color, discard a card of that color or associated basic land type: This card perpetually specializes into that color. Activate only as a sorcery."),
SPECTACLE("Spectacle", KeywordWithCost.class, false, "You may cast this spell for its spectacle cost rather than its mana cost if an opponent lost life this turn."),
SPLICE("Splice", KeywordWithCostAndType.class, false, "As you cast an %2$s spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell."),
SPLIT_SECOND("Split second", SimpleKeyword.class, true, "As long as this spell is on the stack, players can't cast other spells or activate abilities that aren't mana abilities."),

View File

@@ -7,7 +7,8 @@ public class KeywordWithCost extends KeywordInstance<KeywordWithCost> {
@Override
protected void parse(String details) {
cost = new Cost(details.split("\\|", 2)[0].trim(), false);
String[] allDetails = details.split(":");
cost = new Cost(allDetails[0].split("\\|", 2)[0].trim(), false);
}
@Override

View File

@@ -300,9 +300,9 @@ public class ManaCostBeingPaid {
}
int otherSubtract = manaToSubtract;
List<ManaCostShard> toRemove = Lists.newArrayList();
//TODO move that for parts into extra function if able
// try to remove multicolored hybrid shards
// for that, this shard need to be mono colored
if (shard.isMonoColor()) {
@@ -387,15 +387,14 @@ public class ManaCostBeingPaid {
}
}
}
unpaidShards.keySet().removeAll(toRemove);
//System.out.println("Tried to substract a " + shard.toString() + " shard that is not present in this ManaCostBeingPaid");
return;
}
int difference = manaToSubtract - sc.totalCount;
int difference = manaToSubtract - sc.totalCount;
if (manaToSubtract >= sc.totalCount) {
sc.xCount = 0;
sc.totalCount = 0;

View File

@@ -52,7 +52,6 @@ import forge.game.event.GameEventTokenStateUpdate;
import forge.game.event.GameEventTurnBegan;
import forge.game.event.GameEventTurnEnded;
import forge.game.event.GameEventTurnPhase;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
@@ -556,8 +555,7 @@ public class PhaseHandler implements java.io.Serializable {
final CardCollection untapFromCancel = new CardCollection();
// do a full loop first so attackers can't be used to pay for Propaganda
for (final Card attacker : combat.getAttackers()) {
final boolean shouldTapForAttack = !attacker.hasKeyword(Keyword.VIGILANCE) && !attacker.hasKeyword("Attacking doesn't cause CARDNAME to tap.");
if (shouldTapForAttack) {
if (!attacker.attackVigilance()) {
// set tapped to true without firing triggers because it may affect propaganda costs
attacker.setTapped(true);
untapFromCancel.add(attacker);
@@ -589,8 +587,7 @@ public class PhaseHandler implements java.io.Serializable {
} while (!success);
for (final Card attacker : combat.getAttackers()) {
final boolean shouldTapForAttack = !attacker.hasKeyword(Keyword.VIGILANCE) && !attacker.hasKeyword("Attacking doesn't cause CARDNAME to tap.");
if (shouldTapForAttack) {
if (!attacker.attackVigilance()) {
attacker.setTapped(false);
attacker.tap(true, true);
}

View File

@@ -458,14 +458,14 @@ public class Player extends GameEntity implements Comparable<Player> {
return isOpponentOf(otherPlayer);
}
public final boolean setLife(final int newLife, final Card source) {
public final boolean setLife(final int newLife, final SpellAbility sa) {
boolean change = false;
// rule 119.5
if (life > newLife) {
change = loseLife(life - newLife, false, false) > 0;
}
else if (newLife > life) {
change = gainLife(newLife - life, source);
change = gainLife(newLife - life, sa == null ? null : sa.getHostCard(), sa);
}
else { // life == newLife
change = false;
@@ -487,9 +487,6 @@ public class Player extends GameEntity implements Comparable<Player> {
return life;
}
public final boolean gainLife(int lifeGain, final Card source) {
return gainLife(lifeGain, source, null);
}
public final boolean gainLife(int lifeGain, final Card source, final SpellAbility sa) {
if (!canGainLife()) {
return false;
@@ -498,7 +495,7 @@ public class Player extends GameEntity implements Comparable<Player> {
// Run any applicable replacement effects.
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
repParams.put(AbilityKey.LifeGained, lifeGain);
repParams.put(AbilityKey.Source, source);
repParams.put(AbilityKey.SourceSA, sa);
switch (getGame().getReplacementHandler().run(ReplacementType.GainLife, repParams)) {
case NotReplaced:
@@ -835,7 +832,8 @@ public class Player extends GameEntity implements Comparable<Player> {
return true;
}
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table) {
@Override
public void addCounterInternal(final CounterType counterType, final int n, final Player source, final boolean fireEvents, GameEntityCounterTable table, Map<AbilityKey, Object> params) {
int addAmount = n;
if (addAmount <= 0 || !canReceiveCounters(counterType)) {
// As per rule 107.1b
@@ -849,6 +847,9 @@ public class Player extends GameEntity implements Comparable<Player> {
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
runParams.put(AbilityKey.Source, source);
runParams.put(AbilityKey.CounterType, counterType);
if (params != null) {
runParams.putAll(params);
}
for (int i = 0; i < addAmount; i++) {
runParams.put(AbilityKey.CounterAmount, oldValue + i + 1);
getGame().getTriggerHandler().runTrigger(TriggerType.CounterAdded, AbilityKey.newMap(runParams), false);
@@ -1604,9 +1605,8 @@ public class Player extends GameEntity implements Comparable<Player> {
}
// MilledAll trigger
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
runParams.put(AbilityKey.Cards, milled);
runParams.put(AbilityKey.Player, this);
game.getTriggerHandler().runTrigger(TriggerType.MilledAll, runParams, false);
return milled;

View File

@@ -49,11 +49,11 @@ public class PlayerProperty {
return false;
}
} else if (property.equals("Active")) {
if (!player.equals(game.getPhaseHandler().getPlayerTurn())) {
if (!game.getPhaseHandler().isPlayerTurn(player)) {
return false;
}
} else if (property.equals("NonActive")) {
if (player.equals(game.getPhaseHandler().getPlayerTurn())) {
if (game.getPhaseHandler().isPlayerTurn(player)) {
return false;
}
} else if (property.equals("OpponentToActive")) {

View File

@@ -63,7 +63,10 @@ public class RegisteredPlayer {
}
public final void addExtraCardsOnBattlefield(Iterable<IPaperCard> extraCardsonTable) {
this.extraCardsOnBattlefield = extraCardsonTable;
if (this.extraCardsOnBattlefield == null)
this.extraCardsOnBattlefield = extraCardsonTable;
else
this.extraCardsOnBattlefield = Iterables.concat(this.extraCardsOnBattlefield, extraCardsonTable);
}
public int getStartingHand() {

View File

@@ -100,7 +100,7 @@ public class ReplaceDamage extends ReplacementEffect {
//Lava Burst and Whippoorwill check
SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
GameEntity affected = (GameEntity) runParams.get(AbilityKey.Affected);
if (((cause != null) && (cause.hasParam("NoRedirection")) || (affected.hasKeyword("Damage that would be dealt to CARDNAME can't be redirected.")))) {
if ((cause != null && cause.hasParam("NoRedirection") || affected.hasKeyword("Damage that would be dealt to CARDNAME can't be redirected."))) {
return false;
}
// check for DamageRedirection, the Thing where the damage is redirected to must be a creature or planeswalker or a player

View File

@@ -50,11 +50,11 @@ public class ReplaceGainLife extends ReplacementEffect {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) {
return false;
}
if (!matchesValidParam("ValidSource", runParams.get(AbilityKey.Source))) {
if (!matchesValidParam("ValidSource", runParams.get(AbilityKey.SourceSA))) {
return false;
}
if ("True".equals(getParam("SourceController"))) {
if (runParams.get(AbilityKey.Source) == null || !runParams.get(AbilityKey.Affected).equals(((Card)runParams.get(AbilityKey.Source)).getController())) {
if (runParams.get(AbilityKey.SourceSA) == null || !runParams.get(AbilityKey.Affected).equals(((SpellAbility)runParams.get(AbilityKey.SourceSA)).getActivatingPlayer())) {
return false;
}
}

View File

@@ -177,7 +177,7 @@ public class AbilityManaPart implements java.io.Serializable {
player.getGame().getTriggerHandler().runTrigger(TriggerType.TapsForMana, runParams, false);
if (source.isLand() && root.isManaAbility() && root.getPayCosts() != null && root.getPayCosts().hasTapCost()) {
player.setTappedLandForManaThisTurn(true);
root.getActivatingPlayer().setTappedLandForManaThisTurn(true);
}
}

View File

@@ -135,6 +135,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
private boolean cumulativeupkeep = false;
private boolean blessing = false;
private Integer chapter = null;
private boolean lastChapter = false;
/** The pay costs. */
private Cost payCosts;
@@ -1066,6 +1067,13 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
chapter = val;
}
public boolean isLastChapter() {
return lastChapter;
}
public boolean setLastChapter(boolean value) {
return lastChapter = value;
}
public StaticAbility getMayPlay() {
return mayPlay;
}
@@ -1129,6 +1137,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
clone.paidAbilities = Lists.newArrayList();
clone.setPaidHash(Maps.newHashMap(getPaidHash()));
// copy last chapter flag for Trigger
clone.lastChapter = this.lastChapter;
if (usesTargeting()) {
// the targets need to be cloned, otherwise they might be cleared
clone.targetChosen = getTargets().clone();

View File

@@ -570,7 +570,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
System.out.println(c.getName() + " Did not have activator set in SpellAbilityRestriction.canPlay()");
}
if (!StaticAbilityCastWithFlash.anyWithFlashNeedsTargeting(sa, c, activator)) {
if (!StaticAbilityCastWithFlash.anyWithFlashNeedsInfo(sa, c, activator)) {
if (!sa.canCastTiming(c, activator)) {
return false;
}

View File

@@ -0,0 +1,33 @@
package forge.game.staticability;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.zone.ZoneType;
public class StaticAbilityAttackVigilance {
static String MODE = "AttackVigilance";
public static boolean attackVigilance(final Card card) {
final Game game = card.getGame();
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) {
continue;
}
if (applyAttackVigilanceAbility(stAb, card)) {
return true;
}
}
}
return false;
}
public static boolean applyAttackVigilanceAbility(final StaticAbility stAb, final Card card) {
if (!stAb.matchesValidParam("ValidCard", card)) {
return false;
}
return true;
}
}

View File

@@ -11,7 +11,7 @@ public class StaticAbilityCastWithFlash {
static String MODE = "CastWithFlash";
public static boolean anyWithFlashNeedsTargeting(final SpellAbility sa, final Card card, final Player activator) {
public static boolean anyWithFlashNeedsInfo(final SpellAbility sa, final Card card, final Player activator) {
final Game game = activator.getGame();
final CardCollection allp = new CardCollection(game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES));
allp.add(card);
@@ -20,7 +20,7 @@ public class StaticAbilityCastWithFlash {
if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) {
continue;
}
if (applyWithFlashNeedsTargeting(stAb, sa, card, activator)) {
if (applyWithFlashNeedsInfo(stAb, sa, card, activator)) {
return true;
}
}
@@ -45,13 +45,15 @@ public class StaticAbilityCastWithFlash {
return false;
}
public static boolean commonParts(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) {
private static boolean commonParts(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator, final boolean skipValidSA) {
if (!stAb.matchesValidParam("ValidCard", card)) {
return false;
}
if (!stAb.matchesValidParam("ValidSA", sa)) {
return false;
if (!skipValidSA) {
if (!stAb.matchesValidParam("ValidSA", sa)) {
return false;
}
}
if (!stAb.matchesValidParam("Caster", activator)) {
@@ -60,29 +62,24 @@ public class StaticAbilityCastWithFlash {
return true;
}
public static boolean applyWithFlashNeedsTargeting(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) {
if (!commonParts(stAb, sa, card, activator)) {
public static boolean applyWithFlashNeedsInfo(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) {
boolean info = false;
String validSA = stAb.getParam("ValidSA");
if (validSA.contains("IsTargeting") || validSA.contains("XCost")) {
info = true;
}
if (!commonParts(stAb, sa, card, activator, info)) {
return false;
}
return stAb.hasParam("Targeting");
return info;
}
public static boolean applyWithFlashAbility(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) {
if (!commonParts(stAb, sa, card, activator)) {
if (!commonParts(stAb, sa, card, activator, false)) {
return false;
}
if (stAb.hasParam("Targeting")) {
if (!sa.usesTargeting()) {
return false;
}
if (!stAb.matchesValidParam("Targeting", sa.getTargets())) {
return false;
}
}
return true;
}
}

View File

@@ -19,7 +19,6 @@ package forge.game.trigger;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardZoneTable;
@@ -54,8 +53,8 @@ public class TriggerAbilityTriggered extends Trigger {
return false;
}
final Card source = spellAbility.getHostCard();
@SuppressWarnings("unchecked")
final Iterable<Card> causes = (Iterable<Card>) runParams.get(AbilityKey.Cause);
final Game game = source.getGame();
if (hasParam("ValidMode")) {
List<String> validModes = Arrays.asList(getParam("ValidMode").split(","));
@@ -73,6 +72,10 @@ public class TriggerAbilityTriggered extends Trigger {
}
}
if (!matchesValidParam("ValidSpellAbility", spellAbility)) {
return false;
}
if (!matchesValidParam("ValidSource", source)) {
return false;
}

View File

@@ -0,0 +1,55 @@
package forge.game.trigger;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
import java.util.Map;
public class TriggerConjureAll extends Trigger {
public TriggerConjureAll(Map<String, String> params, Card host, boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public boolean performTest(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
return false;
}
// currently not used
//if (!matchesValidParam("ValidCause", runParams.get(AbilityKey.Cause))) {
// return false;
//}
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Cards))) {
return false;
}
return true;
}
@Override
public void setTriggeringObjects(SpellAbility sa, Map<AbilityKey, Object> runParams) {
CardCollection cards = (CardCollection) runParams.get(AbilityKey.Cards);
if (hasParam("ValidCard")) {
cards = CardLists.getValidCards(cards, getParam("ValidCard"), getHostCard().getController(),
getHostCard(), this);
}
sa.setTriggeringObject(AbilityKey.Cards, cards);
//sa.setTriggeringObject(AbilityKey.Amount, cards.size()) -- currently don't need
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Player, AbilityKey.Cause);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ");
sb.append(sa.getTriggeringObject(AbilityKey.Player));
return sb.toString();
}
}

View File

@@ -89,6 +89,19 @@ public class TriggerCounterAdded extends Trigger {
}
}
// TODO check CR for Read Ahead when they are out
// for now assume it only is about etb counter
if (hasParam("Chapter") && runParams.containsKey(AbilityKey.ETB) && true == (boolean)runParams.get(AbilityKey.ETB)) {
Card card = (Card)runParams.get(AbilityKey.Card);
Integer readAhead = card.getReadAhead();
if (readAhead != null) {
final int actualAmount = (Integer) runParams.get(AbilityKey.CounterAmount);
if (actualAmount < readAhead) {
return false;
}
}
}
return true;
}

View File

@@ -0,0 +1,73 @@
/*
* 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.game.trigger;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
import java.util.Map;
/**
* <p>
* TriggerSpecializes class.
* </p>
*/
public class TriggerSpecializes extends Trigger {
/**
* <p>
* Constructor for TriggerSpecializes
* </p>
*
* @param params
* a {@link java.util.HashMap} object.
* @param host
* a {@link forge.game.card.Card} object.
* @param intrinsic
* the intrinsic
*/
public TriggerSpecializes (Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
/** {@inheritDoc}
* @param runParams*/
@Override
public final boolean performTest(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Card))) {
return false;
}
return true;
}
/** {@inheritDoc} */
@Override
public final void setTriggeringObjects(final SpellAbility sa, Map<AbilityKey, Object> runParams) {
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblSpecialized")).append(": ");
sb.append(sa.getTriggeringObject(AbilityKey.Card));
return sb.toString();
}
}

View File

@@ -40,6 +40,7 @@ public enum TriggerType {
ChangesZoneAll(TriggerChangesZoneAll.class),
Clashed(TriggerClashed.class),
ClassLevelGained(TriggerClassLevelGained.class),
ConjureAll(TriggerConjureAll.class),
CounterAdded(TriggerCounterAdded.class),
CounterAddedOnce(TriggerCounterAddedOnce.class),
CounterPlayerAddedAll(TriggerCounterPlayerAddedAll.class),
@@ -102,6 +103,7 @@ public enum TriggerType {
SearchedLibrary(TriggerSearchedLibrary.class),
SetInMotion(TriggerSetInMotion.class),
Shuffled(TriggerShuffled.class),
Specializes(TriggerSpecializes.class),
SpellAbilityCast(TriggerSpellAbilityCastOrCopy.class),
SpellAbilityCopy(TriggerSpellAbilityCastOrCopy.class),
SpellCast(TriggerSpellAbilityCastOrCopy.class),

View File

@@ -286,19 +286,30 @@ public class WrappedAbility extends Ability {
return sa.isCycling();
}
@Override
public boolean isChapter() {
return sa.isChapter();
}
@Override
public Integer getChapter() {
return sa.getChapter();
}
@Override
public void setChapter(int val) {
sa.setChapter(val);
}
@Override
public boolean isLastChapter() {
return sa.isLastChapter();
}
@Override
public boolean setLastChapter(boolean value) {
return sa.setLastChapter(value);
}
@Override
public boolean isFlashBackAbility() {
return sa.isFlashBackAbility();
@@ -566,4 +577,5 @@ public class WrappedAbility extends Ability {
public void setChosenList(List<AbilitySub> choices) {
sa.setChosenList(choices);
}
}

View File

@@ -26,6 +26,7 @@ public enum TrackableProperty {
IsImmutable(TrackableTypes.BooleanType),
IsEmblem(TrackableTypes.BooleanType),
IsBoon(TrackableTypes.BooleanType),
Flipped(TrackableTypes.BooleanType),
Facedown(TrackableTypes.BooleanType),
@@ -138,6 +139,7 @@ public enum TrackableProperty {
HasDefender(TrackableTypes.BooleanType),
HasDivideDamage(TrackableTypes.BooleanType),
HasDoubleStrike(TrackableTypes.BooleanType),
HasDoubleTeam(TrackableTypes.BooleanType),
HasFirstStrike(TrackableTypes.BooleanType),
HasFlying(TrackableTypes.BooleanType),
HasFear(TrackableTypes.BooleanType),

View File

@@ -12,6 +12,7 @@
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-feature android:name="android.hardware.gamepad" android:required="false"/>
<application
android:allowBackup="true"

View File

@@ -45,6 +45,12 @@
</resources>
<finalName>forge-android-${alpha-version}</finalName>
</build>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
@@ -167,6 +173,12 @@
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-android</artifactId>
<version>2.2.3-SNAPSHOT</version>
<type>aar</type>
</dependency>
</dependencies>
<profiles>
@@ -401,6 +413,7 @@
<fileset dir="${basedir}/../forge-gui/release-files/" includes="INSTALLATION.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="ISSUES.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="CHANGES.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="GAMEPAD_README.txt" />
<fileset dir="${basedir}/../forge-gui/" includes="MANUAL.txt" />
<fileset dir="${basedir}/../forge-gui-mobile-dev/" includes="sentry.properties" />
<fileset dir="${basedir}/../forge-gui/">

View File

@@ -64,6 +64,7 @@
-keep class io.sentry.android.core.SentryInitProvider
-keep class io.sentry.android.core.SentryPerformanceProvider
-keep class com.badlogic.gdx.controllers.android.AndroidControllers { *; }
-keep class com.github.tommyettinger.textra.** { *; }
-keep class io.sentry.android.ndk.SentryNdk

View File

@@ -550,6 +550,7 @@
<fileset dir="${basedir}/../forge-gui/" includes="MANUAL.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="CONTRIBUTORS.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="INSTALLATION.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="GAMEPAD_README.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="ISSUES.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="CHANGES.txt" />
<fileset dir="${basedir}/../forge-gui/">
@@ -677,6 +678,7 @@
<fileset dir="${basedir}/../forge-gui/release-files/" includes="CONTRIBUTORS.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="ISSUES.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="INSTALLATION.txt" />
<fileset dir="${basedir}/../forge-gui/release-files/" includes="GAMEPAD_README.txt" />
<fileset dir="${basedir}/../forge-gui/" includes="MANUAL.txt" />
<fileset dir="${basedir}/" includes="sentry.properties" />
</copy>

View File

@@ -230,7 +230,7 @@ public class GameSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
Card sorin = addCard("Sorin, Solemn Visitor", p);
sorin.addCounterInternal(CounterEnumType.LOYALTY, 5, p, false, null);
sorin.addCounterInternal(CounterEnumType.LOYALTY, 5, p, false, null, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
@@ -275,7 +275,7 @@ public class GameSimulationTest extends SimulationTest {
String bearCardName = "Runeclaw Bear";
addCard(bearCardName, p);
Card gideon = addCard("Gideon, Ally of Zendikar", p);
gideon.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null);
gideon.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
@@ -404,7 +404,7 @@ public class GameSimulationTest extends SimulationTest {
Game game = initAndCreateGame();
Player p = game.getPlayers().get(1);
Card sarkhan = addCard(sarkhanCardName, p);
sarkhan.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null);
sarkhan.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
@@ -439,7 +439,7 @@ public class GameSimulationTest extends SimulationTest {
addCard(ornithoperCardName, p);
addCard(bearCardName, p);
Card ajani = addCard(ajaniCardName, p);
ajani.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null);
ajani.addCounterInternal(CounterEnumType.LOYALTY, 4, p, false, null, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
@@ -472,7 +472,7 @@ public class GameSimulationTest extends SimulationTest {
SpellAbility boltSA = boltCard.getFirstSpellAbility();
Card ajani = addCard(ajaniCardName, p);
ajani.addCounterInternal(CounterEnumType.LOYALTY, 8, p, false, null);
ajani.addCounterInternal(CounterEnumType.LOYALTY, 8, p, false, null, null);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
@@ -523,7 +523,7 @@ public class GameSimulationTest extends SimulationTest {
addCard("Swamp", p);
addCard("Swamp", p);
Card depths = addCard("Dark Depths", p);
depths.addCounterInternal(CounterEnumType.ICE, 10, p, false, null);
depths.addCounterInternal(CounterEnumType.ICE, 10, p, false, null, null);
Card thespian = addCard("Thespian's Stage", p);
game.getPhaseHandler().devModeSet(PhaseType.MAIN2, p);
game.getAction().checkStateEffects(true);
@@ -2256,7 +2256,7 @@ public class GameSimulationTest extends SimulationTest {
Player p = game.getPlayers().get(0);
Card polukranos = addCard(polukranosCardName, p);
polukranos.addCounterInternal(CounterEnumType.P1P1, 6, p, false, null);
polukranos.addCounterInternal(CounterEnumType.P1P1, 6, p, false, null, null);
addCard(hydraCardName, p);
addCard(leylineCardName, p);
for (int i = 0; i < 2; ++i) {
@@ -2301,7 +2301,7 @@ public class GameSimulationTest extends SimulationTest {
}
Card nishoba = addCard(nishobaName, p1);
nishoba.addCounterInternal(CounterEnumType.P1P1, 7, p1, false, null);
nishoba.addCounterInternal(CounterEnumType.P1P1, 7, p1, false, null, null);
addCard(capridorName, p1);
Card pridemate = addCard(pridemateName, p1);
Card indestructibility = addCard(indestructibilityName, p1);

View File

@@ -48,7 +48,8 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
// Get Card From Editions Test fixtures
protected final String originalArtShivanDragonEdition = "LEA";
protected final String latestArtShivanDragonEdition = "M20";
protected final String latestArtShivanDragonEdition = "P30H";
protected final String latestArtShivanDragonEditionNoPromo = "M20";
protected final String originalArtLightningDragonEdition = "USG";
protected final String originalArtLightningDragonEditionNoPromo = "USG";
@@ -56,8 +57,8 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
protected final String latestArtLightningDragonEdition = "VMA";
protected final String latestArtLightningDragonEditionNoPromo = "USG";
protected final String latestArtHymnToTourachEdition = "EMA";
protected final String latestArtHymnToTourachEditionNoPromo = "EMA";
protected final String latestArtHymnToTourachEdition = "PLIST";
protected final String latestArtHymnToTourachEditionNoPromo = "PLIST";
protected final String originalArtHymnToTourachEdition = "FEM";
protected final String originalArtHymnToTourachEditionNoPromo = "FEM";
@@ -423,7 +424,7 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
sdCard = this.cardDb.getCardFromEditions(cardNameShivanDragon, frame);
assertEquals(sdCard.getName(), cardNameShivanDragon);
assertEquals(sdCard.getEdition(), latestArtShivanDragonEdition);
assertEquals(sdCard.getEdition(), latestArtShivanDragonEditionNoPromo);
ldCard = this.cardDb.getCardFromEditions(cardNameLightningDragon, frame);
assertEquals(ldCard.getName(), cardNameLightningDragon);
@@ -653,7 +654,8 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
nullCard = this.cardDb.getCardFromEditions(null, preference);
assertNull(nullCard);
shivanNotExistingDragon = this.cardDb.getCardFromEditions(cardNameShivanDragon, preference, 2);
//P30H Shivan Dragon had 2 treatments, so bumped artIndex to 3
shivanNotExistingDragon = this.cardDb.getCardFromEditions(cardNameShivanDragon, preference, 3);
assertNull(shivanNotExistingDragon);
nullCard = this.cardDb.getCardFromEditions(cardNameHymnToTourach, preference, 5);
@@ -1138,7 +1140,7 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
sdCard = this.cardDb.getCardFromEditionsReleasedAfter(cardNameShivanDragon, artPreference,
tenthEditionReleaseDate);
assertEquals(sdCard.getName(), cardNameShivanDragon);
assertEquals(sdCard.getEdition(), latestArtShivanDragonEdition);
assertEquals(sdCard.getEdition(), latestArtShivanDragonEditionNoPromo);
// foiled card request
ldFoilCard = this.cardDb.getCardFromEditionsReleasedAfter(cardNameFoilLightningDragon, artPreference,
@@ -1259,7 +1261,7 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
sdCard = this.cardDb.getCardFromEditionsReleasedAfter(cardNameShivanDragon, artPreference, 1,
tenthEditionReleaseDate);
assertEquals(sdCard.getName(), cardNameShivanDragon);
assertEquals(sdCard.getEdition(), latestArtShivanDragonEdition);
assertEquals(sdCard.getEdition(), latestArtShivanDragonEditionNoPromo);
assertEquals(sdCard.getArtIndex(), 1);
// foiled card request
@@ -1747,22 +1749,24 @@ public class CardDbCardMockTestCase extends CardMockTestCase {
assertEquals(shivanDragon.getName(), cardNameShivanDragon);
assertEquals(shivanDragon.getEdition(), latestArtShivanDragonEdition);
Date alphaRelaseDate = null;
Date alphaReleaseDate = null;
Date currentDate = Date.from(Instant.now());
Date latestShivanDragonReleaseDateToDate = null; // latest print to date for Shivan is in M20
Date latestShivanDragonReleaseDateToDate = null; // latest print to date for Shivan is in P30H
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
alphaRelaseDate = format.parse(alphaEditionReleaseDate);
latestShivanDragonReleaseDateToDate = format.parse("2019-07-12");
alphaReleaseDate = format.parse(alphaEditionReleaseDate);
latestShivanDragonReleaseDateToDate = format.parse("2022-09-09");
} catch (ParseException e) {
e.printStackTrace();
fail();
}
assertNull(this.cardDb.getCardFromEditionsReleasedBefore(cardNameShivanDragon, alphaRelaseDate));
assertNull(this.cardDb.getCardFromEditionsReleasedAfter(cardNameShivanDragon, currentDate));
assertNull(this.cardDb.getCardFromEditionsReleasedBefore(cardNameShivanDragon, alphaReleaseDate));
assertNull(this.cardDb.getCardFromEditionsReleasedAfter(cardNameShivanDragon,
latestShivanDragonReleaseDateToDate));
if (currentDate.after(latestShivanDragonReleaseDateToDate)) {
assertNull(this.cardDb.getCardFromEditionsReleasedAfter(cardNameShivanDragon, currentDate));
}
}
@Test

View File

@@ -41,7 +41,7 @@ public class CardEditionCollectionCardMockTestCase extends CardMockTestCase {
CardDb cardDb = FModel.getMagicDb().getCommonCards();
String[] cardNames = { "Shivan Dragon", "Animate Wall", "Balance", "Blessing", "Force of Will" };
String[] expectedSets = { "M20", "MED", "SLD", "M14", "DMR" };
String[] expectedSets = { "P30H", "MED", "SLD", "M14", "DMR" };
List<PaperCard> cards = new ArrayList<>();
for (int i = 0; i < 5; i++) {
String cardName = cardNames[i];

View File

@@ -214,7 +214,12 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>forge</groupId>
@@ -244,5 +249,10 @@
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-desktop</artifactId>
<version>2.2.3-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -23,7 +23,12 @@
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>gdx-nightlies</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>forge</groupId>
@@ -45,6 +50,11 @@
<artifactId>forge-gui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx-controllers</groupId>
<artifactId>gdx-controllers-core</artifactId>
<version>2.2.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>

View File

@@ -5,6 +5,10 @@ import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.controllers.Controller;
import com.badlogic.gdx.controllers.ControllerAdapter;
import com.badlogic.gdx.controllers.ControllerListener;
import com.badlogic.gdx.controllers.Controllers;
import com.badlogic.gdx.graphics.Cursor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
@@ -18,6 +22,7 @@ import com.badlogic.gdx.utils.Clipboard;
import forge.adventure.scene.*;
import forge.adventure.stage.MapStage;
import forge.adventure.util.Config;
import forge.adventure.world.WorldSave;
import forge.animation.ForgeAnimation;
import forge.assets.Assets;
import forge.assets.AssetsDownloader;
@@ -67,6 +72,9 @@ public class Forge implements ApplicationListener {
private static Graphics graphics;
private static FrameRate frameRate;
private static FScreen currentScreen;
private static ControllerListener controllerListener;
private static boolean hasGamepad = false;
public static Texture lastPreview = null;
protected static SplashScreen splashScreen;
protected static ClosingScreen closingScreen;
protected static TransitionScreen transitionScreen;
@@ -249,6 +257,13 @@ public class Forge implements ApplicationListener {
});
});
}
public static boolean hasGamepad() {
//Classic Mode Various Screen GUI are not yet supported, needs control mapping for each screens
if (isMobileAdventureMode) {
return hasGamepad && Forge.isLandscapeMode(); //portrait is not supported for Gamepad
}
return false;
}
public static InputProcessor getInputProcessor() {
return inputProcessor;
@@ -321,6 +336,7 @@ public class Forge implements ApplicationListener {
altZoneTabs = true;
//pixl cursor for adventure
setCursor(null, "0");
enableControllerListener();
loadAdventureResources(true);
}
private static void loadAdventureResources(boolean startScene) {
@@ -966,6 +982,7 @@ public class Forge implements ApplicationListener {
SoundSystem.instance.dispose();
try {
ExceptionHandler.unregisterErrorHandling();
lastPreview.dispose();
} catch (Exception e) {
}
}
@@ -975,6 +992,10 @@ public class Forge implements ApplicationListener {
return ((Forge)Gdx.app.getApplicationListener()).assets;
}
public static boolean switchScene(Scene newScene) {
if (newScene instanceof RewardScene || newScene instanceof SpellSmithScene || newScene instanceof DeckSelectScene || newScene instanceof PlayerStatisticScene) {
if (!(currentScene instanceof ForgeScene)) //prevent overwriting the last preview if last scene is instance of ForgeScene
WorldSave.getCurrentSave().header.createPreview();
}
if (currentScene != null) {
if (!currentScene.leave())
return false;
@@ -1352,6 +1373,7 @@ public class Forge implements ApplicationListener {
magnify = true;
mouseMovedX = screenX;
mouseMovedY = screenY;
hasGamepad = false; //prevent drawing some panels
//todo: mouse listener for android?
if (GuiBase.isAndroid())
return true;
@@ -1388,4 +1410,174 @@ public class Forge implements ApplicationListener {
return handled;
}
}
public static void enableControllerListener() {
if (controllerListener == null) {
controllerListener = new ControllerAdapter() {
@Override
public void connected(final Controller controller) {
Gdx.app.log("Controller", "Controller connected: " + controller.getName()
+ "/" + controller.getUniqueId());
hasGamepad = true;
if (controller.canVibrate())
controller.startVibration(200,1);
if (Forge.isMobileAdventureMode && Forge.currentScene instanceof UIScene) {
((UIScene) Forge.currentScene).selectCurrent();
}
}
@Override
public void disconnected(Controller controller) {
Gdx.app.log("Controller", "Controller disconnected: " + controller.getName()
+ "/" + controller.getUniqueId());
hasGamepad = false;
}
@Override
public boolean buttonDown(Controller controller, int buttonIndex) {
//System.out.println(controller.getName()+"["+controller.getUniqueId()+"]: "+buttonIndex);
hasGamepad = true;
translateButtons(controller, buttonIndex, true);
return super.buttonDown(controller, buttonIndex);
}
@Override
public boolean buttonUp(Controller controller, int buttonIndex) {
hasGamepad = true;
translateButtons(controller, buttonIndex, false);
return super.buttonUp(controller, buttonIndex);
}
@Override
public boolean axisMoved(Controller controller, int axisIndex, float value) {
//System.out.println(controller.getName()+"["+controller.getUniqueId()+"]: axis: "+axisIndex+" - "+value);
hasGamepad = true;
translateAxis(controller, axisIndex, value);//prevent multi press axis
return super.axisMoved(controller, axisIndex, value);
}
private void translateAxis(Controller controller, int axisIndex, float value) {
if (!hasGamepad())
return;//adventure only
FContainer container = FOverlay.getTopOverlay();
if (container == null) {
container = currentScreen;
}
if (container != null) {
if (currentScreen instanceof MatchScreen) {
if (4 == axisIndex && value == 1f) { //others are L2Button if missing this axis
container.keyDown(Keys.ENTER);
}
if (5 == axisIndex && value == 1f) { //others are R2 Button if missing this axis
container.keyDown(Keys.ESCAPE);
}
if (controller.getMapping().axisLeftY == axisIndex) {
if (value == 1f)
container.keyDown(Keys.PAGE_DOWN);
}
/*if (controller.getMapping().axisLeftX == axisIndex) {
if (value == 1f) {
}
}*/
}
}
}
private void translateButtons(Controller controller, int buttonIndex, boolean keyDown) {
if (!hasGamepad())
return; //adventure only
if (!keyDown)
return; //prevent keyup on forgescene
//overlay shoud have priority
FContainer container = FOverlay.getTopOverlay();
if (container == null) {
container = currentScreen;
}
if (container != null) {
if (currentScreen instanceof MatchScreen) {
if (controller.getMapping().buttonL2 == buttonIndex) {//others are axis-4
container.keyDown(Keys.ENTER);
}
if (controller.getMapping().buttonR2 == buttonIndex) {//others are axis-5
container.keyDown(Keys.ESCAPE);
}
if (controller.getMapping().buttonX == buttonIndex) {
container.keyDown(Keys.BUTTON_X);
}
if (controller.getMapping().buttonY == buttonIndex) {
container.keyDown(Keys.BUTTON_Y);
}
if (controller.getMapping().buttonR1 == buttonIndex) {
container.keyDown(Keys.BUTTON_R1);
}
if (controller.getMapping().buttonL1 == buttonIndex) {
container.keyDown(Keys.BUTTON_L1);
}
if (controller.getMapping().buttonDpadDown == buttonIndex) {
container.keyDown(Keys.DPAD_DOWN);
}
if (controller.getMapping().buttonDpadLeft == buttonIndex) {
container.keyDown(Keys.DPAD_LEFT);
}
if (controller.getMapping().buttonDpadRight == buttonIndex) {
container.keyDown(Keys.DPAD_RIGHT);
}
if (controller.getMapping().buttonDpadUp == buttonIndex) {
container.keyDown(Keys.DPAD_UP);
}
if (controller.getMapping().buttonA == buttonIndex) {
container.keyDown(Keys.BUTTON_A);
}
if (controller.getMapping().buttonB == buttonIndex) {
container.keyDown(Keys.BUTTON_B);
}
if (controller.getMapping().buttonBack == buttonIndex) {
container.keyDown(Keys.BUTTON_SELECT);
}
} else {//Others
/*if (controller.getMapping().buttonL2 == buttonIndex) {//others are axis-4
container.keyDown(Keys.ENTER);
}
if (controller.getMapping().buttonR2 == buttonIndex) {//others are axis-5
container.keyDown(Keys.ESCAPE);
}*/
if (controller.getMapping().buttonDpadDown == buttonIndex) {
container.keyDown(Keys.DPAD_DOWN);
}
if (controller.getMapping().buttonDpadLeft == buttonIndex) {
container.keyDown(Keys.DPAD_LEFT);
}
if (controller.getMapping().buttonDpadRight == buttonIndex) {
container.keyDown(Keys.DPAD_RIGHT);
}
if (controller.getMapping().buttonDpadUp == buttonIndex) {
container.keyDown(Keys.DPAD_UP);
}
if (controller.getMapping().buttonBack == buttonIndex) {
container.keyDown(Keys.BUTTON_SELECT);
}
if (controller.getMapping().buttonB == buttonIndex) {
container.keyDown(Keys.BUTTON_B);
}
if (controller.getMapping().buttonA == buttonIndex) {
container.keyDown(Keys.BUTTON_A);
}
if (controller.getMapping().buttonX == buttonIndex) {
container.keyDown(Keys.BUTTON_X);
}
if (controller.getMapping().buttonY == buttonIndex) {
container.keyDown(Keys.BUTTON_Y);
}
if (controller.getMapping().buttonR1 == buttonIndex) {
container.keyDown(Keys.BUTTON_R1);
}
if (controller.getMapping().buttonL1 == buttonIndex) {
container.keyDown(Keys.BUTTON_L1);
}
}
}
}
};
}
Controllers.addListener(controllerListener);
if (Controllers.getCurrent() != null)
System.out.println("Gamepad: " + Controllers.getCurrent().getName());
}
}

View File

@@ -582,7 +582,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
if(blessing != null) {
if(blessing.cardRewardBonus > 0) result += blessing.cardRewardBonus;
}
return Math.max(result, 3);
return Math.min(result, 3);
}
public DifficultyData getDifficulty() {

View File

@@ -1,5 +1,6 @@
package forge.adventure.scene;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Align;
import com.google.common.base.Function;
@@ -41,6 +42,7 @@ import java.util.Map;
private static final FLabel lblGold = new FLabel.Builder().text("0").icon(FSkinImage.QUEST_COINSTACK).font(FSkinFont.get(16)).insets(new Vector2(Utils.scale(5), 0)).build();
private static ItemPool<InventoryItem> decksUsingMyCards=new ItemPool<>(InventoryItem.class);
private int selected = 0;
public static void leave() {
AdventurePlayer.current().getNewCards().clear();
Forge.clearCurrentScreen();
@@ -97,12 +99,7 @@ import java.util.Map;
boolean isShop=false;
public AdventureDeckEditor(boolean createAsShop) {
super(new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e) {
leave();
}
},getPages());
super(e -> leave(),getPages());
isShop=createAsShop;
@@ -137,12 +134,7 @@ import java.util.Map;
FPopupMenu menu = new FPopupMenu() {
@Override
protected void buildMenu() {
addItem(new FMenuItem(Forge.getLocalizer().getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e1) {
FDeckViewer.copyDeckToClipboard(getDeck());
}
}));
addItem(new FMenuItem(Forge.getLocalizer().getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, e1 -> FDeckViewer.copyDeckToClipboard(getDeck())));
((DeckEditorPage)getSelectedPage()).buildDeckMenu(this);
}
};
@@ -244,12 +236,7 @@ import java.util.Map;
protected CardManagerPage(ItemManagerConfig config0, String caption0, FImage icon0) {
super(caption0, icon0);
config = config0;
cardManager.setItemActivateHandler(new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e) {
CardManagerPage.this.onCardActivated(cardManager.getSelectedItem());
}
});
cardManager.setItemActivateHandler(e -> CardManagerPage.this.onCardActivated(cardManager.getSelectedItem()));
cardManager.setContextMenuBuilder(new ItemManager.ContextMenuBuilder<PaperCard>() {
@Override
public void buildMenu(final FDropDownMenu menu, final PaperCard card) {
@@ -257,30 +244,10 @@ import java.util.Map;
}
});
}
private final Function<Map.Entry<InventoryItem, Integer>, Comparable<?>> fnNewCompare = new Function<Map.Entry<InventoryItem, Integer>, Comparable<?>>() {
@Override
public Comparable<?> apply(Map.Entry<InventoryItem, Integer> from) {
return AdventurePlayer.current().getNewCards().contains(from.getKey()) ? Integer.valueOf(1) : Integer.valueOf(0);
}
};
private final Function<Map.Entry<? extends InventoryItem, Integer>, Object> fnNewGet = new Function<Map.Entry<? extends InventoryItem, Integer>, Object>() {
@Override
public Object apply(Map.Entry<? extends InventoryItem, Integer> from) {
return AdventurePlayer.current().getNewCards().contains(from.getKey()) ? "NEW" : "";
}
};
public static final Function<Map.Entry<InventoryItem, Integer>, Comparable<?>> fnDeckCompare = new Function<Map.Entry<InventoryItem, Integer>, Comparable<?>>() {
@Override
public Comparable<?> apply(Map.Entry<InventoryItem, Integer> from) {
return decksUsingMyCards.count(from.getKey());
}
};
public static final Function<Map.Entry<? extends InventoryItem, Integer>, Object> fnDeckGet = new Function<Map.Entry<? extends InventoryItem, Integer>, Object>() {
@Override
public Object apply(Map.Entry<? extends InventoryItem, Integer> from) {
return Integer.valueOf(decksUsingMyCards.count(from.getKey())).toString();
}
};
private final Function<Map.Entry<InventoryItem, Integer>, Comparable<?>> fnNewCompare = from -> AdventurePlayer.current().getNewCards().contains(from.getKey()) ? Integer.valueOf(1) : Integer.valueOf(0);
private final Function<Map.Entry<? extends InventoryItem, Integer>, Object> fnNewGet = from -> AdventurePlayer.current().getNewCards().contains(from.getKey()) ? "NEW" : "";
public static final Function<Map.Entry<InventoryItem, Integer>, Comparable<?>> fnDeckCompare = from -> decksUsingMyCards.count(from.getKey());
public static final Function<Map.Entry<? extends InventoryItem, Integer>, Object> fnDeckGet = from -> Integer.valueOf(decksUsingMyCards.count(from.getKey())).toString();
protected void initialize() {
@@ -410,14 +377,11 @@ import java.util.Map;
if (!StringUtils.isEmpty(dest)) {
label += " " + dest;
}
menu.addItem(new FMenuItem(label, icon, new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (max == 1) {
callback.run(max);
} else {
GuiChoose.getInteger(cardManager.getSelectedItem() + " - " + verb + " " + Forge.getLocalizer().getMessage("lblHowMany"), 1, max, 20, callback);
}
menu.addItem(new FMenuItem(label, icon, e -> {
if (max == 1) {
callback.run(max);
} else {
GuiChoose.getInteger(cardManager.getSelectedItem() + " - " + verb + " " + Forge.getLocalizer().getMessage("lblHowMany"), 1, max, 20, callback);
}
}));
}
@@ -535,6 +499,30 @@ import java.util.Map;
protected CatalogPage(ItemManagerConfig config, String caption0, FImage icon0) {
super(config, caption0, icon0);
}
private void setNextSelected() {
setNextSelected(1);
}
private void setNextSelected(int val) {
if (cardManager.getItemCount() < 1)
return;
if ((cardManager.getSelectedIndex()+val) < cardManager.getItemCount()) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()+val);
} else if ((cardManager.getSelectedIndex()+1) < cardManager.getItemCount()) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()+1);
}
}
private void setPreviousSelected() {
setPreviousSelected(1);
}
private void setPreviousSelected(int val) {
if (cardManager.getItemCount() < 1)
return;
if ((cardManager.getSelectedIndex()-val) > -1) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()-val);
} else if ((cardManager.getSelectedIndex()-1) > -1) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()-1);
}
}
@Override
protected void initialize() {
@@ -660,14 +648,11 @@ import java.util.Map;
@Override
protected void buildDeckMenu(FPopupMenu menu) {
if (cardManager.getConfig().getShowUniqueCardsOption()) {
menu.addItem(new FCheckBoxMenuItem(Forge.getLocalizer().getMessage("lblUniqueCardsOnly"), cardManager.getWantUnique(), new FEvent.FEventHandler() {
@Override
public void handleEvent(FEvent e) {
boolean wantUnique = !cardManager.getWantUnique();
cardManager.setWantUnique(wantUnique);
CatalogPage.this.refresh();
cardManager.getConfig().setUniqueCardsOnly(wantUnique);
}
menu.addItem(new FCheckBoxMenuItem(Forge.getLocalizer().getMessage("lblUniqueCardsOnly"), cardManager.getWantUnique(), e -> {
boolean wantUnique = !cardManager.getWantUnique();
cardManager.setWantUnique(wantUnique);
CatalogPage.this.refresh();
cardManager.getConfig().setUniqueCardsOnly(wantUnique);
}));
}
}
@@ -676,6 +661,30 @@ import java.util.Map;
protected static class DeckSectionPage extends CardManagerPage {
private final String captionPrefix;
private final DeckSection deckSection;
private void setNextSelected() {
setNextSelected(1);
}
private void setNextSelected(int val) {
if (cardManager.getItemCount() < 1)
return;
if ((cardManager.getSelectedIndex()+val) < cardManager.getItemCount()) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()+val);
} else if ((cardManager.getSelectedIndex()+1) < cardManager.getItemCount()) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()+1);
}
}
private void setPreviousSelected() {
setPreviousSelected(1);
}
private void setPreviousSelected(int val) {
if (cardManager.getItemCount() < 1)
return;
if ((cardManager.getSelectedIndex()-val) > -1) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()-val);
} else if ((cardManager.getSelectedIndex()-1) > -1) {
cardManager.setSelectedIndex(cardManager.getSelectedIndex()-1);
}
}
protected DeckSectionPage(DeckSection deckSection0, ItemManagerConfig config) {
super(config, null, null);
@@ -836,5 +845,150 @@ import java.util.Map;
}
}
@Override
public boolean keyDown(int keyCode) {
if (keyCode == Input.Keys.BUTTON_SELECT) {
return this.tabHeader.btnBack.trigger();
} else if (keyCode == Input.Keys.BUTTON_R1) {
if (getSelectedPage() instanceof CatalogPage)
((CatalogPage) getSelectedPage()).cardManager.closeMenu();
else if (getSelectedPage() instanceof DeckSectionPage)
((DeckSectionPage) getSelectedPage()).cardManager.closeMenu();
selected++;
if (selected > 2)
selected = 0;
setSelectedPage(tabPages[selected]);
if (getSelectedPage() instanceof CatalogPage) {
((CatalogPage) getSelectedPage()).cardManager.getConfig().setPileBy(null);
((CatalogPage) getSelectedPage()).cardManager.setHideFilters(true);
} else if (getSelectedPage() instanceof DeckSectionPage) {
((DeckSectionPage) getSelectedPage()).cardManager.getConfig().setPileBy(null);
((DeckSectionPage) getSelectedPage()).cardManager.setHideFilters(true);
}
} else if (keyCode == Input.Keys.DPAD_RIGHT) {
if (getSelectedPage() instanceof CatalogPage) {
if (((CatalogPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((CatalogPage) getSelectedPage()).setNextSelected();
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((DeckSectionPage) getSelectedPage()).setNextSelected();
}
} else if (keyCode == Input.Keys.DPAD_LEFT) {
if (getSelectedPage() instanceof CatalogPage) {
if (((CatalogPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((CatalogPage) getSelectedPage()).setPreviousSelected();
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((DeckSectionPage) getSelectedPage()).setPreviousSelected();
}
} else if (keyCode == Input.Keys.DPAD_DOWN) {
if (getSelectedPage() instanceof CatalogPage) {
if (((CatalogPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
((CatalogPage) getSelectedPage()).cardManager.selectNextContext();
} else {
if (((CatalogPage) getSelectedPage()).cardManager.getSelectedIndex() < 0)
((CatalogPage) getSelectedPage()).setNextSelected();
else if (((CatalogPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((CatalogPage) getSelectedPage()).setNextSelected(((CatalogPage) getSelectedPage()).cardManager.getConfig().getImageColumnCount());
else
((CatalogPage) getSelectedPage()).setNextSelected();
}
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (((DeckSectionPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
((DeckSectionPage) getSelectedPage()).cardManager.selectNextContext();
} else {
if (((DeckSectionPage) getSelectedPage()).cardManager.getSelectedIndex() < 0)
((DeckSectionPage) getSelectedPage()).setNextSelected();
else if (((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((DeckSectionPage) getSelectedPage()).setNextSelected(((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getImageColumnCount());
else
((DeckSectionPage) getSelectedPage()).setNextSelected();
}
}
} else if (keyCode == Input.Keys.DPAD_UP) {
if (getSelectedPage() instanceof CatalogPage) {
if (((CatalogPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
((CatalogPage) getSelectedPage()).cardManager.selectPreviousContext();
} else {
if (((CatalogPage) getSelectedPage()).cardManager.getSelectedIndex() < 0)
((CatalogPage) getSelectedPage()).setNextSelected();
else if (((CatalogPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((CatalogPage) getSelectedPage()).setPreviousSelected(((CatalogPage) getSelectedPage()).cardManager.getConfig().getImageColumnCount());
else
((CatalogPage) getSelectedPage()).setPreviousSelected();
}
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (((DeckSectionPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
((DeckSectionPage) getSelectedPage()).cardManager.selectPreviousContext();
} else {
if (((DeckSectionPage) getSelectedPage()).cardManager.getSelectedIndex() < 0)
((DeckSectionPage) getSelectedPage()).setNextSelected();
else if (((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1)
((DeckSectionPage) getSelectedPage()).setPreviousSelected(((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getImageColumnCount());
else
((DeckSectionPage) getSelectedPage()).setPreviousSelected();
}
}
} else if (keyCode == Input.Keys.BUTTON_A) {
if (getSelectedPage() instanceof CatalogPage) {
if (((CatalogPage) getSelectedPage()).cardManager.isContextMenuOpen())
((CatalogPage) getSelectedPage()).cardManager.activateSelectedContext();
else
((CatalogPage) getSelectedPage()).cardManager.showMenu(true);
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (((DeckSectionPage) getSelectedPage()).cardManager.isContextMenuOpen() )
((DeckSectionPage) getSelectedPage()).cardManager.activateSelectedContext();
else
((DeckSectionPage) getSelectedPage()).cardManager.showMenu(true);
}
} else if (keyCode == Input.Keys.BUTTON_B) {
if (getSelectedPage() instanceof CatalogPage) {
if (((CatalogPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
((CatalogPage) getSelectedPage()).cardManager.closeMenu();
} else
return this.tabHeader.btnBack.trigger();
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (((DeckSectionPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
((DeckSectionPage) getSelectedPage()).cardManager.closeMenu();
} else
return this.tabHeader.btnBack.trigger();
}
} else if (keyCode == Input.Keys.BUTTON_Y) {
if (getSelectedPage() instanceof CatalogPage) {
if (!((CatalogPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
if (((CatalogPage) getSelectedPage()).cardManager.getCurrentView().getSelectionCount() > 0) {
((CatalogPage) getSelectedPage()).cardManager.getCurrentView().zoomSelected();
}
} else {
((CatalogPage) getSelectedPage()).cardManager.closeMenu();
if (((CatalogPage) getSelectedPage()).cardManager.getCurrentView().getSelectionCount() > 0) {
((CatalogPage) getSelectedPage()).cardManager.getCurrentView().zoomSelected();
}
}
} else if (getSelectedPage() instanceof DeckSectionPage) {
if (!((DeckSectionPage) getSelectedPage()).cardManager.isContextMenuOpen()) {
if (((DeckSectionPage) getSelectedPage()).cardManager.getCurrentView().getSelectionCount() > 0) {
((DeckSectionPage) getSelectedPage()).cardManager.getCurrentView().zoomSelected();
}
} else {
((DeckSectionPage) getSelectedPage()).cardManager.closeMenu();
if (((DeckSectionPage) getSelectedPage()).cardManager.getCurrentView().getSelectionCount() > 0) {
((DeckSectionPage) getSelectedPage()).cardManager.getCurrentView().zoomSelected();
}
}
}
} else if (keyCode == Input.Keys.BUTTON_L1) {
if (getSelectedPage() instanceof CatalogPage) {
((CatalogPage) getSelectedPage()).cardManager.closeMenu();
int index = ((CatalogPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1 ? 0 : 1;
((CatalogPage) getSelectedPage()).cardManager.setViewIndex(index);
} else if (getSelectedPage() instanceof DeckSectionPage) {
((DeckSectionPage) getSelectedPage()).cardManager.closeMenu();
int index = ((DeckSectionPage) getSelectedPage()).cardManager.getConfig().getViewIndex() == 1 ? 0 : 1;
((DeckSectionPage) getSelectedPage()).cardManager.setViewIndex(index);
}
}
return true;
}
}

View File

@@ -19,10 +19,11 @@ public class DeckSelectScene extends UIScene {
TextField textInput;
Table layout;
Label header;
TextButton back, edit, rename;
TextButton back, edit, rename, dialogRenameBtn, dialogAbortBtn;
int currentSlot = 0;
ScrollPane scrollPane;
private DeckSelectScene() {
public DeckSelectScene() {
super(Forge.isLandscapeMode() ? "ui/deck_selector.json" : "ui/deck_selector_portrait.json");
layout = new Table();
@@ -41,8 +42,12 @@ public class DeckSelectScene extends UIScene {
dialog.getButtonTable().add(Controls.newLabel(Forge.getLocalizer().getMessage("lblName")+": ")).align(Align.left);
dialog.getButtonTable().add(textInput).fillX().expandX();
dialog.getButtonTable().row();
dialog.getButtonTable().add(Controls.newTextButton(Forge.getLocalizer().getMessage("lblRename"), () -> DeckSelectScene.this.rename())).align(Align.left);
dialog.getButtonTable().add(Controls.newTextButton(Forge.getLocalizer().getMessage("lblAbort"), () -> dialog.hide())).align(Align.left);
dialogRenameBtn = Controls.newTextButton(Forge.getLocalizer().getMessage("lblRename"), () -> DeckSelectScene.this.rename());
dialog.getButtonTable().add(dialogRenameBtn).align(Align.left).padLeft(15);
dialogAbortBtn = Controls.newTextButton(Forge.getLocalizer().getMessage("lblAbort"), () -> dialog.hide());
dialog.getButtonTable().add(dialogAbortBtn).align(Align.right).padRight(15);
dialog.getColor().a = 0f;
dialog.hide();
back = ui.findActor("return");
back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack"));
@@ -55,23 +60,14 @@ public class DeckSelectScene extends UIScene {
ui.onButtonPress("rename", () -> {
textInput.setText(Current.player().getSelectedDeck().getName());
dialog.show(stage);
stage.setKeyboardFocus(textInput);
selectActor(textInput, false);
});
defColor = ui.findActor("return").getColor();
ScrollPane scrollPane = ui.findActor("deckSlots");
scrollPane = ui.findActor("deckSlots");
scrollPane.setActor(layout);
}
private static DeckSelectScene object;
public static DeckSelectScene instance() {
if(object==null)
object=new DeckSelectScene();
return object;
}
private TextButton addDeckSlot(String name, int i) {
TextButton button = Controls.newTextButton("-");
button.addListener(new ClickListener() {
@@ -123,15 +119,64 @@ public class DeckSelectScene extends UIScene {
@Override
public void enter() {
select(Current.player().getSelectedDeckIndex());
clearActorObjects();
for (int i = 0; i < AdventurePlayer.NUMBER_OF_DECKS; i++) {
if (buttons.containsKey(i)) {
buttons.get(i).setText(Current.player().getDeck(i).getName());
addActorObject(buttons.get(i));
}
}
addActorObject(back);
addActorObject(rename);
addActorObject(edit);
addActorObject(textInput);
addActorObject(dialogRenameBtn);
addActorObject(dialogAbortBtn);
select(Current.player().getSelectedDeckIndex());
super.enter();
}
@Override
public void resLoaded() {
super.resLoaded();
layout = new Table();
stage.addActor(layout);
header = Controls.newLabel(Forge.getLocalizer().getMessage("lblSelectYourDeck"));
layout.add(header).colspan(2).align(Align.center).pad(2, 5, 2, 5);
layout.row();
for (int i = 0; i < AdventurePlayer.NUMBER_OF_DECKS; i++)
addDeckSlot(Forge.getLocalizer().getMessage("lblDeck")+": " + (i + 1), i);
dialog = Controls.newDialog(Forge.getLocalizer().getMessage("lblSave"));
textInput = Controls.newTextField("");
dialog.getButtonTable().add(Controls.newLabel(Forge.getLocalizer().getMessage("lblNameYourSaveFile"))).colspan(2);
dialog.getButtonTable().row();
dialog.getButtonTable().add(Controls.newLabel(Forge.getLocalizer().getMessage("lblName")+": ")).align(Align.left);
dialog.getButtonTable().add(textInput).fillX().expandX();
dialog.getButtonTable().row();
dialog.getButtonTable().add(Controls.newTextButton(Forge.getLocalizer().getMessage("lblRename"), () -> DeckSelectScene.this.rename())).align(Align.left);
dialog.getButtonTable().add(Controls.newTextButton(Forge.getLocalizer().getMessage("lblAbort"), () -> dialog.hide())).align(Align.left);
back = ui.findActor("return");
back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack"));
edit = ui.findActor("edit");
edit.getLabel().setText(Forge.getLocalizer().getMessage("lblEdit"));
rename = ui.findActor("rename");
rename.getLabel().setText(Forge.getLocalizer().getMessage("lblRename"));
ui.onButtonPress("return", () -> DeckSelectScene.this.back());
ui.onButtonPress("edit", () -> DeckSelectScene.this.edit());
ui.onButtonPress("rename", () -> {
textInput.setText(Current.player().getSelectedDeck().getName());
dialog.show(stage);
stage.setKeyboardFocus(textInput);
});
defColor = ui.findActor("return").getColor();
ScrollPane scrollPane = ui.findActor("deckSlots");
scrollPane.setActor(layout);
}
private void rename() {
dialog.hide();
@@ -141,6 +186,6 @@ public class DeckSelectScene extends UIScene {
}
private void edit() {
Forge.switchScene(DeckEditScene.instance());
Forge.switchScene(SceneType.DeckEditScene.instance);
}
}

View File

@@ -146,7 +146,7 @@ public class DuelScene extends ForgeScene {
changeStartCards += data.changeStartCards;
startCards.addAll(data.startBattleWithCards());
}
player.setCardsOnBattlefield(startCards);
player.addExtraCardsOnBattlefield(startCards);
player.setStartingLife(Math.max(1, lifeMod + player.getStartingLife()));
player.setStartingHand(player.getStartingHand() + changeStartCards);
}
@@ -291,6 +291,7 @@ public class DuelScene extends ForgeScene {
rules.setMatchAnteRarity(true);
rules.setGamesPerMatch(1);
rules.setManaBurn(false);
rules.setWarnAboutAICards(false);
hostedMatch.setEndGameHook(() -> DuelScene.this.GameEnd());
hostedMatch.startMatch(rules, appliedVariants, players, guiMap);

View File

@@ -5,7 +5,6 @@ import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import forge.adventure.stage.GameHUD;
import forge.adventure.stage.GameStage;
import forge.adventure.stage.IAfterMatch;
/**
* Hud base scene
@@ -55,7 +54,11 @@ public abstract class HudScene extends Scene implements InputProcessor, IAfterMa
@Override
public boolean keyDown(int keycode) {
if (Forge.hasGamepad()) {
if (MapStage.getInstance().isDialogOnlyInput()) {
return MapStage.getInstance().buttonPress(keycode);
}
}
if (hud.keyDown(keycode))
return true;
if(isInHudOnlyMode())

View File

@@ -92,6 +92,10 @@ public class InnScene extends UIScene {
tempHitPointCost = ui.findActor("tempHitPointCost");
tempHitPointCost.setDisabled(!purchaseable);
tempHitPointCost.getLabel().setText("$" + tempHealthCost);
clearActorObjects();
addActorObject(tempHitPointCost);
addActorObject(sell);
addActorObject(leave);
}
private void sell() {
@@ -103,6 +107,24 @@ public class InnScene extends UIScene {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
done();
}
if (keycode == Input.Keys.DPAD_RIGHT) {
if (selectedActor == null)
selectActor(tempHitPointCost, false);
else
selectNextActor(false);
} else if ( keycode == Input.Keys.DPAD_LEFT) {
if (selectedActor == null)
selectActor(leave, false);
else
selectPreviousActor(false);
} else if (keycode == Input.Keys.BUTTON_B) {
performTouch(leave);
} else if (keycode == Input.Keys.BUTTON_A) {
performTouch(selectedActor);
}
return true;
}

View File

@@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Timer;
import forge.Forge;
import forge.adventure.data.ItemData;
import forge.adventure.stage.ConsoleCommandInterpreter;
@@ -261,6 +262,7 @@ public class InventoryScene extends UIScene {
}
private void updateInventory() {
clearActorObjects();
inventoryButtons.clear();
inventory.clear();
for(int i=0;i<Current.player().getItems().size;i++) {
@@ -302,6 +304,7 @@ public class InventoryScene extends UIScene {
}
}
});
addActorObject(newActor);
}
for(Map.Entry<String, Button> slot :equipmentSlots.entrySet()) {
if(slot.getValue().getChildren().size>=2)
@@ -337,6 +340,27 @@ public class InventoryScene extends UIScene {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
done();
}
if (keycode == Input.Keys.BUTTON_SELECT)
performTouch(ui.findActor("return"));
else if (keycode == Input.Keys.BUTTON_B)
performTouch(ui.findActor("return"));
else if (keycode == Input.Keys.BUTTON_A) {
if (selectedActor instanceof ImageButton) {
performTouch(equipButton);
Timer.schedule(new Timer.Task() {
@Override
public void run() {
selectCurrent();
}
}, 0.25f);
} else {
performTouch(selectedActor);
}
} else if (keycode == Input.Keys.DPAD_RIGHT || keycode == Input.Keys.DPAD_DOWN)
selectNextActor(false);
else if (keycode == Input.Keys.DPAD_LEFT || keycode == Input.Keys.DPAD_UP)
selectPreviousActor(false);
return true;
}
}

View File

@@ -3,6 +3,8 @@ package forge.adventure.scene;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
@@ -16,6 +18,7 @@ import forge.adventure.util.UIActor;
import forge.adventure.world.WorldSave;
import forge.card.ColorSet;
import forge.deck.DeckProxy;
import forge.gui.GuiBase;
import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
@@ -39,6 +42,7 @@ public class NewGameScene extends UIScene {
private Selector difficulty;
private Array<String> stringList, random, custom;
private Label colorLabel;
private int selected = -1;
private NewGameScene() {
@@ -46,6 +50,16 @@ public class NewGameScene extends UIScene {
selectedName = ui.findActor("nameField");
selectedName.setText(NameGenerator.getRandomName("Any", "Any", ""));
selectedName.addListener(new InputListener() {
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if (!GuiBase.isAndroid() && showGamepadSelector) {
//show onscreen keyboard
return true;
}
return super.touchDown(event, x, y, pointer, button);
}
});
avatarImage = ui.findActor("avatarPreview");
gender = ui.findActor("gender");
mode = ui.findActor("mode");
@@ -182,12 +196,153 @@ public class NewGameScene extends UIScene {
GamePlayerUtil.getGuiPlayer().setName(selectedName.getText());
Forge.switchScene(GameScene.instance());
}
clearActorObjects();
addActorObject(selectedName);
addActorObject(race);
addActorObject(gender);
addActorObject(difficulty);
addActorObject(colorId);
addActorObject(mode);
addActorObject(ui.findActor("back"));
addActorObject(ui.findActor("start"));
unselectActors();
}
@Override
public boolean pointerMoved(int screenX, int screenY) {
ui.screenToLocalCoordinates(pointer.set(screenX,screenY));
if (showGamepadSelector) {
unselectActors();
showGamepadSelector = false;
}
if (kbVisible)
return super.pointerMoved(screenX, screenY);
updateHovered();
return super.pointerMoved(screenX, screenY);
}
@Override
public boolean keyPressed(int keycode) {
if (Forge.hasGamepad())
showGamepadSelector = true;
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
back();
if(!kbVisible)
back();
}
if (keycode == Input.Keys.BUTTON_SELECT) {
if (showGamepadSelector) {
if(!kbVisible)
performTouch(ui.findActor("back"));
}
} else if (keycode == Input.Keys.BUTTON_START) {
if (showGamepadSelector) {
if(kbVisible)
keyOK();
else
performTouch(ui.findActor("start"));
}
} else if (keycode == Input.Keys.BUTTON_L2) {
if(!kbVisible)
selectedName.setText(NameGenerator.getRandomName("Female", "Any", selectedName.getText()));
} else if (keycode == Input.Keys.BUTTON_R2) {
if(!kbVisible)
selectedName.setText(NameGenerator.getRandomName("Male", "Any", selectedName.getText()));
} else if (keycode == Input.Keys.BUTTON_L1) {
if (showGamepadSelector) {
if (kbVisible)
toggleShiftOrBackspace(true);
else
performTouch(ui.findActor("leftAvatar"));
}
} else if (keycode == Input.Keys.BUTTON_R1) {
if (showGamepadSelector) {
if(kbVisible)
toggleShiftOrBackspace(false);
else
performTouch(ui.findActor("rightAvatar"));
}
} else if (keycode == Input.Keys.DPAD_DOWN) {
if (showGamepadSelector) {
if (kbVisible) {
setSelectedKey(keycode);
} else {
if (selectedActor == mode)
selectActor(selectedName, false);
else if (selectedActor == ui.findActor("back"))
selectActor(ui.findActor("start"), false);
else if (selectedActor == ui.findActor("start"))
selectActor(ui.findActor("back"), false);
else
selectNextActor(false);
}
}
} else if (keycode == Input.Keys.DPAD_UP) {
if (showGamepadSelector) {
if (kbVisible) {
setSelectedKey(keycode);
} else {
if (selectedActor == selectedName)
selectActor(mode, false);
else if (selectedActor == ui.findActor("start"))
selectActor(ui.findActor("back"), false);
else if (selectedActor == ui.findActor("back"))
selectActor(ui.findActor("start"), false);
else
selectPreviousActor(false);
}
}
} else if (keycode == Input.Keys.DPAD_LEFT) {
if (showGamepadSelector) {
if (kbVisible) {
setSelectedKey(keycode);
} else {
if (selectedActor == ui.findActor("back") || selectedActor == ui.findActor("start"))
selectActor(mode, false);
}
}
} else if (keycode == Input.Keys.DPAD_RIGHT) {
if (showGamepadSelector) {
if (kbVisible) {
setSelectedKey(keycode);
} else {
if (!(selectedActor == ui.findActor("back") || selectedActor == ui.findActor("start")))
selectActor(ui.findActor("start"), false);
}
}
} else if (keycode == Input.Keys.BUTTON_A) {
if (showGamepadSelector) {
if (kbVisible) {
if (selectedKey != null)
performTouch(selectedKey);
} else {
if (selectedActor != null) {
if (selectedActor instanceof TextButton)
performTouch(selectedActor);
else if (selectedActor instanceof TextField && !kbVisible) {
lastInputField = selectedActor;
showOnScreenKeyboard("");
}
}
}
}
} else if (keycode == Input.Keys.BUTTON_B) {
if (showGamepadSelector) {
if (kbVisible) {
hideOnScreenKeyboard();
} else {
performTouch(ui.findActor("back"));
}
}
} else if (keycode == Input.Keys.BUTTON_X) {
if (showGamepadSelector) {
if(!kbVisible)
if (selectedActor != null && selectedActor instanceof Selector)
performTouch(((Selector) selectedActor).getLeftArrow());
}
} else if (keycode == Input.Keys.BUTTON_Y) {
if (showGamepadSelector) {
if(!kbVisible)
if (selectedActor != null && selectedActor instanceof Selector)
performTouch(((Selector) selectedActor).getRightArrow());
}
}
return true;
}

View File

@@ -34,6 +34,7 @@ public class PlayerStatisticScene extends UIScene {
TextButton back;
private Table enemiesGroup;
Label blessingScroll;
ScrollPane scrollPane, blessing;
private PlayerStatisticScene() {
super(Forge.isLandscapeMode() ? "ui/statistic.json" : "ui/statistic_portrait.json");
@@ -98,6 +99,16 @@ public class PlayerStatisticScene extends UIScene {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
back();
}
if (keycode == Input.Keys.BUTTON_B)
performTouch(ui.findActor("return"));
else if (keycode == Input.Keys.BUTTON_A)
performTouch(selectedActor);
else if (keycode == Input.Keys.BUTTON_L1 || keycode == Input.Keys.DPAD_UP) {
scrollPane.fling(1f, 0, -300);
} else if (keycode == Input.Keys.BUTTON_R1 || keycode == Input.Keys.DPAD_DOWN) {
scrollPane.fling(1f, 0, +300);
} else if (keycode == Input.Keys.DPAD_LEFT || keycode == Input.Keys.DPAD_RIGHT || keycode == Input.Keys.DPAD_UP || keycode == Input.Keys.DPAD_DOWN)
selectActor(back, false);
return true;
}
@@ -140,20 +151,10 @@ public class PlayerStatisticScene extends UIScene {
avatar.setDrawable(new TextureRegionDrawable(Current.player().avatar()));
}
if (life != null) {
AdventurePlayer.current().onLifeChange(new Runnable() {
@Override
public void run() {
life.setText(AdventurePlayer.current().getLife() + "/" + AdventurePlayer.current().getMaxLife());
}
});
AdventurePlayer.current().onLifeChange(() -> life.setText(AdventurePlayer.current().getLife() + "/" + AdventurePlayer.current().getMaxLife()));
}
if (money != null) {
WorldSave.getCurrentSave().getPlayer().onGoldChange(new Runnable() {
@Override
public void run() {
money.setText(String.valueOf(AdventurePlayer.current().getGold()));
}
});
WorldSave.getCurrentSave().getPlayer().onGoldChange(() -> money.setText(String.valueOf(AdventurePlayer.current().getGold())));
}
if (totalWins != null) {
totalWins.setText(Current.player().getStatistic().totalWins());
@@ -193,6 +194,42 @@ public class PlayerStatisticScene extends UIScene {
}
@Override
public void resLoaded() {
super.resLoaded();
enemiesGroup = new Table(Controls.GetSkin());
enemiesGroup.row();
blessingScroll = Controls.newLabel("");
blessingScroll.setStyle(new Label.LabelStyle(Controls.getBitmapFont("default"), Color.BLACK));
blessingScroll.setAlignment(Align.topLeft);
blessingScroll.setWrap(true);
ui.onButtonPress("return", () -> PlayerStatisticScene.this.back());
avatar = ui.findActor("avatar");
avatarBorder = ui.findActor("avatarBorder");
playerName = ui.findActor("playerName");
life = ui.findActor("lifePoints");
money = ui.findActor("money");
lifeIcon = ui.findActor("lifeIcon");
goldIcon = ui.findActor("goldIcon");
wins = ui.findActor("wins");
colorFrame = ui.findActor("colorFrame");
wins.setText(Forge.getLocalizer().getMessage("lblWinProper")+":");
totalWins = ui.findActor("totalWins");
loss = ui.findActor("loss");
loss.setText(Forge.getLocalizer().getMessage("lblLossProper")+":");
totalLoss = ui.findActor("totalLoss");
winloss = ui.findActor("winloss");
winloss.setText(Forge.getLocalizer().getMessage("lblWinProper")+"/"+Forge.getLocalizer().getMessage("lblLossProper"));
lossWinRatio = ui.findActor("lossWinRatio");
back = ui.findActor("return");
back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack"));
scrollPane = ui.findActor("enemies");
scrollPane.setActor(enemiesGroup);
blessing = ui.findActor("blessingInfo");
blessing.setActor(blessingScroll);
}
@Override
public void create() {

View File

@@ -34,6 +34,7 @@ public class RewardScene extends UIScene {
return object;
}
private boolean showTooltips = false;
public enum Type {
Shop,
Loot
@@ -54,7 +55,7 @@ public class RewardScene extends UIScene {
doneButton = ui.findActor("done");
}
boolean doneClicked = false;
boolean doneClicked = false, shown = false;
float flipCountDown = 1.0f;
float exitCountDown = 0.0f; //Serves as additional check for when scene is exiting, so you can't double tap too fast.
@@ -144,11 +145,91 @@ public class RewardScene extends UIScene {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
done();
}
if (keycode == Input.Keys.BUTTON_B || keycode == Input.Keys.BUTTON_START)
showLootOrDone();
else if (keycode == Input.Keys.BUTTON_A)
performTouch(selectedActor);
else if (keycode == Input.Keys.DPAD_RIGHT) {
hideTooltips();
selectNextActor(false);
if (selectedActor != null && Type.Loot == type) {
selectedActor.fire(eventEnter);
}
showHideTooltips();
} else if (keycode == Input.Keys.DPAD_LEFT) {
hideTooltips();
selectPreviousActor(false);
if (selectedActor != null && Type.Loot == type) {
selectedActor.fire(eventEnter);
}
showHideTooltips();
} else if (keycode == Input.Keys.BUTTON_Y) {
showTooltips = !showTooltips;
showHideTooltips();
}
return true;
}
private void showHideTooltips() {
if (selectedActor instanceof RewardActor) {
if (showTooltips) {
if (((RewardActor) selectedActor).isFlipped())
((RewardActor) selectedActor).showTooltip();
} else {
((RewardActor) selectedActor).hideTooltip();
}
} else if (selectedActor instanceof BuyButton) {
if (showTooltips)
((BuyButton) selectedActor).reward.showTooltip();
else
((BuyButton) selectedActor).reward.hideTooltip();
}
}
private void hideTooltips() {
if (selectedActor instanceof RewardActor) {
((RewardActor) selectedActor).hideTooltip();
} else if (selectedActor instanceof BuyButton) {
((BuyButton) selectedActor).reward.hideTooltip();
}
}
private void showLootOrDone() {
boolean exit = true;
for (Actor actor : new Array.ArrayIterator<>(generated)) {
if (!(actor instanceof RewardActor)) {
continue;
}
RewardActor reward = (RewardActor) actor;
if (!reward.isFlipped()) {
exit = false;
break;
}
}
if (exit)
performTouch(doneButton);
else if (type == Type.Loot && !shown) {
shown = true;
for (Actor actor : new Array.ArrayIterator<>(generated)) {
if (!(actor instanceof RewardActor)) {
continue;
}
RewardActor reward = (RewardActor) actor;
AdventurePlayer.current().addReward(reward.getReward());
if (!reward.isFlipped()) {
Timer.schedule(new Timer.Task() {
@Override
public void run() {
reward.flip();
}
}, 0.09f);
}
}
} else {
performTouch(doneButton);
}
}
public void loadRewards(Array<Reward> newRewards, Type type, ShopActor shopActor) {
clearActorObjects();
this.type = type;
doneClicked = false;
for (Actor actor : new Array.ArrayIterator<>(generated)) {
@@ -283,7 +364,10 @@ public class RewardScene extends UIScene {
generated.add(buyCardButton);
if (!skipCard) {
stage.addActor(buyCardButton);
addActorObject(buyCardButton);
}
} else {
addActorObject(actor);
}
generated.add(actor);
if (!skipCard) {

View File

@@ -3,6 +3,7 @@ package forge.adventure.scene;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
@@ -43,10 +44,10 @@ public class SaveLoadScene extends UIScene {
Image previewImage;
Label previewDate;
Image previewBorder;
TextButton saveLoadButton, back;
TextButton quickSave;
TextButton autoSave;
TextButton saveLoadButton, back, quickSave, autoSave, dialogSaveBtn, dialogAbortBtn;
Actor lastHighlightedSave;
SelectBox difficulty;
ScrollPane scrollPane;
private SaveLoadScene() {
super(Forge.isLandscapeMode() ? "ui/save_load.json" : "ui/save_load_portrait.json");
@@ -160,7 +161,7 @@ public class SaveLoadScene extends UIScene {
previewImage.setVisible(true);
previewDate.setVisible(true);
if (header.saveDate != null)
previewDate.setText(DateFormat.getDateInstance().format(header.saveDate)+"\n"+DateFormat.getTimeInstance(DateFormat.SHORT).format(header.saveDate));
previewDate.setText(DateFormat.getDateInstance().format(header.saveDate) + "\n" + DateFormat.getTimeInstance(DateFormat.SHORT).format(header.saveDate));
else
previewDate.setText("");
}
@@ -176,6 +177,7 @@ public class SaveLoadScene extends UIScene {
if (buttons.containsKey(slot)) {
TextButton button = buttons.get(slot);
button.setColor(Color.RED);
selectActor(button, false);
}
return true;
@@ -188,6 +190,7 @@ public class SaveLoadScene extends UIScene {
//prevent NPE, allowed saveslot is 1 to 10..
textInput.setText(buttons.get(currentSlot).getText().toString());
dialog.show(stage);
selectActor(textInput, false);
stage.setKeyboardFocus(textInput);
}
break;
@@ -228,7 +231,6 @@ public class SaveLoadScene extends UIScene {
}
public boolean saveAbort() {
dialog.hide();
return true;
}
@@ -238,6 +240,124 @@ public class SaveLoadScene extends UIScene {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
back();
}
if (kbVisible) {
if (keycode == Input.Keys.BUTTON_START)
keyOK();
else if (keycode == Input.Keys.BUTTON_L1)
toggleShiftOrBackspace(true);
else if (keycode == Input.Keys.BUTTON_R1)
toggleShiftOrBackspace(false);
else if (keycode == Input.Keys.BUTTON_B)
hideOnScreenKeyboard();
else if (keycode == Input.Keys.BUTTON_A) {
if (selectedKey != null)
performTouch(selectedKey);
} else if (keycode == Input.Keys.DPAD_UP || keycode == Input.Keys.DPAD_DOWN || keycode == Input.Keys.DPAD_LEFT || keycode == Input.Keys.DPAD_RIGHT)
setSelectedKey(keycode);
} else if (dialog.getColor().a != 0f) {
if (keycode == Input.Keys.BUTTON_A) {
if (selectedActor == textInput) {
lastInputField = textInput;
showOnScreenKeyboard(textInput.getText());
} else if (selectedActor == dialogAbortBtn || selectedActor == dialogSaveBtn) {
performTouch(selectedActor);
if (lastSelectedSlot > 0)
select(lastSelectedSlot);
else
select(-3);
}
} else if (keycode == Input.Keys.BUTTON_B) {
performTouch(dialogAbortBtn);
if (lastSelectedSlot > 0)
select(lastSelectedSlot);
else
select(-3);
}
else if (keycode == Input.Keys.DPAD_DOWN) {
if (selectedActor == null) {
selectActor(textInput, false);
} else if (selectedActor == textInput)
selectActor(dialogSaveBtn, false);
} else if (keycode == Input.Keys.DPAD_UP) {
if (selectedActor == null)
selectActor(dialogSaveBtn, false);
else if (selectedActor == dialogSaveBtn || selectedActor == dialogAbortBtn) {
selectActor(textInput, false);
}
} else if (keycode == Input.Keys.DPAD_LEFT) {
if (selectedActor == dialogAbortBtn)
selectActor(dialogSaveBtn, false);
} else if (keycode == Input.Keys.DPAD_RIGHT) {
if (selectedActor == dialogSaveBtn)
selectActor(dialogAbortBtn, false);
}
} else {
if (keycode == Input.Keys.BUTTON_B)
performTouch(back);
else if (keycode == Input.Keys.BUTTON_Y) {
if (difficulty != null && difficulty.isVisible()) {
int index = difficulty.getSelectedIndex()-1;
if (index < 0)
index = 0;
difficulty.setSelectedIndex(index);
}
} else if (keycode == Input.Keys.BUTTON_X) {
if (difficulty != null && difficulty.isVisible()) {
int index = difficulty.getSelectedIndex()+1;
if (index >= 2)
index = 2;
difficulty.setSelectedIndex(index);
}
} else if (keycode == Input.Keys.BUTTON_L1) {
scrollPane.fling(1f, 0, -300);
} else if (keycode == Input.Keys.BUTTON_R1) {
scrollPane.fling(1f, 0, +300);
} else if (keycode == Input.Keys.BUTTON_A) {
performTouch(selectedActor);
} else if (keycode == Input.Keys.DPAD_LEFT) {
if (selectedActor == back || selectedActor == saveLoadButton) {
if (lastHighlightedSave != null)
selectActor(lastHighlightedSave, false);
else
selectActor(actorObjectMap.get(0), false);
lastHighlightedSave = selectedActor;
}
} else if (keycode == Input.Keys.DPAD_RIGHT) {
if (!(selectedActor == back || selectedActor == saveLoadButton)) {
lastHighlightedSave = selectedActor;
selectActor(saveLoadButton, false);
}
} else if (keycode == Input.Keys.DPAD_DOWN) {
int index = mode == Modes.Save ? 9 : 11;
if (selectedActor == back)
selectActor(saveLoadButton, false);
else if (selectedActorIndex == index) {
selectActor(actorObjectMap.get(0), false);
scrollPane.fling(1f, 0, +300);
} else {
selectNextActor(false);
}
if (selectedActorIndex == 6)
scrollPane.fling(1f, 0, -300);
if (!(selectedActor == back || selectedActor == saveLoadButton))
lastHighlightedSave = selectedActor;
} else if (keycode == Input.Keys.DPAD_UP) {
if (selectedActor == saveLoadButton)
selectActor(back, false);
else if (selectedActorIndex == 0) {
selectActor(buttons.get(10), false);
scrollPane.fling(1f, 0, -300);
} else {
selectPreviousActor(false);
}
if (selectedActorIndex == 5)
scrollPane.fling(1f, 0, +300);
if (!(selectedActor == back || selectedActor == saveLoadButton))
lastHighlightedSave = selectedActor;
} else if (keycode == Input.Keys.BUTTON_START) {
performTouch(saveLoadButton);
}
}
return true;
}
@@ -310,7 +430,7 @@ public class SaveLoadScene extends UIScene {
saveLoadButton.setText(Forge.getLocalizer().getMessage("lblLoad"));
break;
case NewGamePlus:
header.setText(Forge.getLocalizer().getMessage("lblNewGame")+"+");
header.setText(Forge.getLocalizer().getMessage("lblNewGame") + "+");
saveLoadButton.setText(Forge.getLocalizer().getMessage("lblStart"));
break;
}
@@ -321,6 +441,8 @@ public class SaveLoadScene extends UIScene {
@Override
public void enter() {
unselectActors();
clearActorObjects();
if (lastSelectedSlot > 0)
select(lastSelectedSlot);
else
@@ -338,7 +460,95 @@ public class SaveLoadScene extends UIScene {
difficulty.setVisible(false);
}
}
if (!autoSave.isDisabled())
addActorObject(autoSave);
if (!quickSave.isDisabled())
addActorObject(quickSave);
for (int i=0; i <= 10; i++) {
if (buttons.containsKey(i))
addActorObject(buttons.get(i));
}
addActorObject(textInput);
addActorObject(dialogSaveBtn);
addActorObject(dialogAbortBtn);
addActorObject(back);
addActorObject(saveLoadButton);
if (scrollPane != null) {
if (lastSelectedSlot >= 6) {
scrollPane.fling(1f, 0, -300);
selectActor(buttons.get(lastSelectedSlot), false);
} else if (lastSelectedSlot > 0 && lastSelectedSlot < 6) {
scrollPane.fling(1f, 0, +300);
selectActor(buttons.get(lastSelectedSlot), false);
}
}
super.enter();
}
@Override
public void resLoaded() {
super.resLoaded();
layout = new Table();
stage.addActor(layout);
dialog = Controls.newDialog(Forge.getLocalizer().getMessage("lblSave"));
textInput = Controls.newTextField("");
int c = 0;
String[] diffList = new String[Config.instance().getConfigData().difficulties.length];
for (DifficultyData diff : Config.instance().getConfigData().difficulties) {
diffList[c] = diff.name;
c++;
}
;
difficulty = Controls.newComboBox(diffList, null, o -> {
//DifficultyData difficulty1 = Config.instance().getConfigData().difficulties[difficulty.getSelectedIndex()];
return null;
});
dialog.getButtonTable().add(Controls.newLabel(Forge.getLocalizer().getMessage("lblNameYourSaveFile"))).colspan(2).pad(2, 15, 2, 15);
dialog.getButtonTable().row();
dialog.getButtonTable().add(Controls.newLabel(Forge.getLocalizer().getMessage("lblName") + ": ")).align(Align.left).pad(2, 15, 2, 2);
dialog.getButtonTable().add(textInput).fillX().expandX().padRight(15);
dialog.getButtonTable().row();
dialogSaveBtn = Controls.newTextButton(Forge.getLocalizer().getMessage("lblSave"), () -> SaveLoadScene.this.save());
dialog.getButtonTable().add(dialogSaveBtn).align(Align.left).padLeft(15);
dialogAbortBtn = Controls.newTextButton(Forge.getLocalizer().getMessage("lblAbort"), () -> SaveLoadScene.this.saveAbort());
dialog.getButtonTable().add(dialogAbortBtn).align(Align.right).padRight(15);
//makes dialog hidden immediately when you open saveload scene..
dialog.getColor().a = 0;
dialog.hide();
previewImage = ui.findActor("preview");
previewDate = ui.findActor("saveDate");
header = Controls.newLabel(Forge.getLocalizer().getMessage("lblSave"));
header.setAlignment(Align.center);
layout.add(header).pad(2).colspan(4).align(Align.center).expandX();
layout.row();
autoSave = addSaveSlot(Forge.getLocalizer().getMessage("lblAutoSave"), WorldSave.AUTO_SAVE_SLOT);
quickSave = addSaveSlot(Forge.getLocalizer().getMessage("lblQuickSave"), WorldSave.QUICK_SAVE_SLOT);
for (int i = 1; i < 11; i++)
addSaveSlot(Forge.getLocalizer().getMessage("lblSlot") + ": " + i, i);
saveLoadButton = ui.findActor("save");
saveLoadButton.getLabel().setText(Forge.getLocalizer().getMessage("lblSave"));
ui.onButtonPress("save", () -> SaveLoadScene.this.loadSave());
back = ui.findActor("return");
back.getLabel().setText(Forge.getLocalizer().getMessage("lblBack"));
ui.onButtonPress("return", () -> SaveLoadScene.this.back());
defColor = saveLoadButton.getColor();
scrollPane = ui.findActor("saveSlots");
scrollPane.setActor(layout);
ui.addActor(difficulty);
difficulty.setSelectedIndex(1);
difficulty.setAlignment(Align.center);
difficulty.getStyle().fontColor = Color.GOLD;
if (Forge.isLandscapeMode()) {
difficulty.setX(280);
difficulty.setY(220);
} else {
difficulty.setX(190);
difficulty.setY(336);
}
}
}

View File

@@ -25,10 +25,122 @@ public class SettingsScene extends UIScene {
Texture Background;
private Table settingGroup;
TextButton back;
ScrollPane scrollPane;
private SettingsScene() {
super(Forge.isLandscapeMode() ? "ui/settings.json" : "ui/settings_portrait.json");
}
@Override
public void dispose() {
if (stage != null)
stage.dispose();
}
public void renderAct(float delta) {
Gdx.gl.glClearColor(1, 0, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.getBatch().begin();
stage.getBatch().disableBlending();
stage.getBatch().draw(Background, 0, 0, getIntendedWidth(), getIntendedHeight());
stage.getBatch().enableBlending();
stage.getBatch().end();
stage.act(delta);
stage.draw();
}
@Override
public boolean keyPressed(int keycode) {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
back();
}
if (keycode == Input.Keys.BUTTON_B)
performTouch(back);
else if (keycode == Input.Keys.BUTTON_L1) {
scrollPane.fling(1f, 0, -300);
} else if (keycode == Input.Keys.BUTTON_R1) {
scrollPane.fling(1f, 0, +300);
}
return true;
}
public boolean back() {
Forge.switchToLast();
return true;
}
private void addInputField(String name, ForgePreferences.FPref pref) {
TextField box = Controls.newTextField("");
box.setText(Preference.getPref(pref));
box.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
Preference.setPref(pref, ((TextField) actor).getText());
Preference.save();
}
});
addLabel(name);
settingGroup.add(box).align(Align.right);
}
private void addCheckBox(String name, ForgePreferences.FPref pref) {
CheckBox box = Controls.newCheckBox("");
box.setChecked(Preference.getPrefBoolean(pref));
box.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
Preference.setPref(pref, ((CheckBox) actor).isChecked());
Preference.save();
}
});
addLabel(name);
settingGroup.add(box).align(Align.right);
}
private void addSettingSlider(String name, ForgePreferences.FPref pref, int min, int max) {
Slider slide = Controls.newSlider(min, max, 1, false);
slide.setValue(Preference.getPrefInt(pref));
slide.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
Preference.setPref(pref, String.valueOf((int) ((Slider) actor).getValue()));
Preference.save();
}
});
addLabel(name);
settingGroup.add(slide).align(Align.right);
}
private void addSettingField(String name, boolean value, ChangeListener change) {
CheckBox box = Controls.newCheckBox("");
box.setChecked(value);
box.addListener(change);
addLabel(name);
settingGroup.add(box).align(Align.right);
}
private void addSettingField(String name, int value, ChangeListener change) {
TextField text = Controls.newTextField(String.valueOf(value));
text.setTextFieldFilter((textField, c) -> Character.isDigit(c));
text.addListener(change);
addLabel(name);
settingGroup.add(text).align(Align.right);
}
void addLabel(String name) {
Label label = Controls.newLabel(name);
label.setWrap(true);
settingGroup.row().space(5);
int w = Forge.isLandscapeMode() ? 160 : 80;
settingGroup.add(label).align(Align.left).pad(2, 2, 2, 5).width(w).expand();
}
@Override
public void resLoaded() {
super.resLoaded();
settingGroup = new Table();
if (Preference == null) {
Preference = new ForgePreferences();

View File

@@ -23,7 +23,7 @@ public class StartScene extends UIScene {
TextButton saveButton, resumeButton, continueButton, newGameButton, newGameButtonPlus, loadButton, settingsButton, exitButton, switchButton;
Dialog dialog;
private StartScene() {
public StartScene() {
super(Forge.isLandscapeMode() ? "ui/start_menu.json" : "ui/start_menu_portrait.json");
ui.onButtonPress("Start", () -> StartScene.this.NewGame());
ui.onButtonPress("Start+", () -> NewGamePlus());
@@ -59,19 +59,14 @@ public class StartScene extends UIScene {
dialog = Controls.newDialog(Forge.getLocalizer().getMessage("lblExitForge"));
dialog.getButtonTable().add(Controls.newLabel(Forge.getLocalizer().getMessage("lblAreYouSureYouWishExitForge"))).colspan(2).pad(2, 15, 2, 15);
dialog.getButtonTable().row();
dialog.getButtonTable().add(Controls.newTextButton(Forge.getLocalizer().getMessage("lblExit"), () -> Forge.exit(true))).width(60).align(Align.left).padLeft(15);
dialog.getButtonTable().add(Controls.newTextButton(Forge.getLocalizer().getMessage("lblCancel"), () -> dialog.hide())).width(60).align(Align.right).padRight(15);
dialogOk = Controls.newTextButton(Forge.getLocalizer().getMessage("lblExit"), () -> Forge.exit(true));
dialogButtonSelected = dialogOk;
dialog.getButtonTable().add(dialogOk).width(60).align(Align.left).padLeft(15);
dialogCancel = Controls.newTextButton(Forge.getLocalizer().getMessage("lblCancel"), () -> dialog.hide());
dialog.getButtonTable().add(dialogCancel).width(60).align(Align.right).padRight(15);
dialog.getColor().a = 0;
}
private static StartScene object;
public static StartScene instance() {
if(object==null)
object=new StartScene();
return object;
}
public boolean NewGame() {
Forge.switchScene(NewGameScene.instance());
return true;
@@ -169,13 +164,213 @@ public class StartScene extends UIScene {
@Override
public boolean keyPressed(int keycode) {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
if (WorldSave.getCurrentSave().getWorld().getData() != null)
Resume();
if (Forge.hasGamepad())
showGamepadSelector = true;
if (dialog.getColor().a != 1) {
if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.BACK) {
if (WorldSave.getCurrentSave().getWorld().getData() != null) {
if (showGamepadSelector)
performTouch(resumeButton);
else
Resume();
}
}
if (keycode == Input.Keys.DPAD_DOWN) {
selected++;
if (selected == 1 && Forge.isLandscapeMode())
selected++;
if (!saveButton.isVisible() && selected == 3)
selected++;
if (!resumeButton.isVisible() && selected == 4)
selected++;
if (!continueButton.isVisible() && selected == 5)
selected++;
if (selected > 7 && Forge.isLandscapeMode())
selected = 0;
if (selected > 8 && !Forge.isLandscapeMode())
selected = 8;
setSelected(selected, false);
} else if (keycode == Input.Keys.DPAD_UP) {
selected--;
if (selected == 7 && Forge.isLandscapeMode())
selected--;
if (!continueButton.isVisible() && selected == 5)
selected--;
if (!resumeButton.isVisible() && selected == 4)
selected--;
if (!saveButton.isVisible() && selected == 3)
selected--;
if (selected == 1 && Forge.isLandscapeMode())
selected--;
if (selected < 0)
selected = Forge.isLandscapeMode() ? 7 : 0;
setSelected(selected, false);
} else if (keycode == Input.Keys.DPAD_RIGHT && Forge.isLandscapeMode()) {
if (selected == 0 || selected == 7)
selected++;
if (selected > 8)
selected = 8;
setSelected(selected, false);
} else if (keycode == Input.Keys.DPAD_LEFT && Forge.isLandscapeMode()) {
if (selected == 1 || selected == 8)
selected--;
if (selected < 0)
selected = 0;
setSelected(selected, false);
} else if (keycode == Input.Keys.BUTTON_A)
setSelected(selected, true);
} else {
if (keycode == Input.Keys.DPAD_RIGHT) {
dialogOk.fire(eventExit);
dialogCancel.fire(eventEnter);
dialogButtonSelected = dialogCancel;
} else if (keycode == Input.Keys.DPAD_LEFT) {
dialogOk.fire(eventEnter);
dialogCancel.fire(eventExit);
dialogButtonSelected = dialogOk;
} else if (keycode == Input.Keys.BUTTON_A) {
dialogOk.fire(eventExit);
dialogCancel.fire(eventExit);
performTouch(dialogButtonSelected);
}
}
return true;
}
private void setSelected(int select, boolean press) {
if (!showGamepadSelector)
return;
unSelectAll();
switch (select) {
case 0:
newGameButton.fire(eventEnter);
if (press)
performTouch(newGameButton);
break;
case 1:
newGameButtonPlus.fire(eventEnter);
if (press)
performTouch(newGameButtonPlus);
break;
case 2:
loadButton.fire(eventEnter);
if (press)
performTouch(loadButton);
break;
case 3:
saveButton.fire(eventEnter);
if (press)
performTouch(saveButton);
break;
case 4:
resumeButton.fire(eventEnter);
if (press)
performTouch(resumeButton);
break;
case 5:
continueButton.fire(eventEnter);
if (press) {
performTouch(continueButton);
setSelected(4, false);
selected = 4;
}
break;
case 6:
settingsButton.fire(eventEnter);
if (press)
performTouch(settingsButton);
break;
case 7:
if (Forge.isLandscapeMode()) {
exitButton.fire(eventEnter);
if (press)
performTouch(exitButton);
} else {
switchButton.fire(eventEnter);
if (press)
performTouch(switchButton);
}
break;
case 8:
if (Forge.isLandscapeMode()) {
switchButton.fire(eventEnter);
if (press)
performTouch(switchButton);
} else {
exitButton.fire(eventEnter);
if (press)
performTouch(exitButton);
}
break;
default:
break;
}
}
private void unSelectAll() {
if (!showGamepadSelector)
return;
newGameButton.fire(eventExit);
newGameButtonPlus.fire(eventExit);
loadButton.fire(eventExit);
saveButton.fire(eventExit);
resumeButton.fire(eventExit);
continueButton.fire(eventExit);
settingsButton.fire(eventExit);
exitButton.fire(eventExit);
switchButton.fire(eventExit);
dialogOk.fire(eventExit);
dialogCancel.fire(eventExit);
}
private void updateSelected() {
if (dialog.getColor().a == 1) {
if (Controls.actorContainsVector(dialogOk, pointer)) {
dialogCancel.fire(eventExit);
dialogOk.fire(eventEnter);
dialogButtonSelected = dialogOk;
}
if (Controls.actorContainsVector(dialogCancel, pointer)) {
dialogOk.fire(eventExit);
dialogCancel.fire(eventEnter);
dialogButtonSelected = dialogCancel;
}
return;
}
if (Controls.actorContainsVector(newGameButton, pointer)) {
newGameButton.fire(eventEnter);
selected = 0;
}
if (Controls.actorContainsVector(newGameButtonPlus, pointer)) {
newGameButtonPlus.fire(eventEnter);
selected = 1;
}
if (Controls.actorContainsVector(loadButton, pointer)) {
loadButton.fire(eventEnter);
selected = 2;
}
if (Controls.actorContainsVector(saveButton, pointer)) {
saveButton.fire(eventEnter);
selected = 3;
}
if (Controls.actorContainsVector(resumeButton, pointer)) {
resumeButton.fire(eventEnter);
selected = 4;
}
if (Controls.actorContainsVector(continueButton, pointer)) {
continueButton.fire(eventEnter);
selected = 5;
}
if (Controls.actorContainsVector(settingsButton, pointer)) {
settingsButton.fire(eventEnter);
selected = 6;
}
if (Controls.actorContainsVector(exitButton, pointer)) {
exitButton.fire(eventEnter);
selected = Forge.isLandscapeMode() ? 7 : 8;
}
if (Controls.actorContainsVector(switchButton, pointer)) {
switchButton.fire(eventEnter);
selected = Forge.isLandscapeMode() ? 8 : 7;
}
}
private void NewGamePlus() {
SaveLoadScene.instance().setMode(SaveLoadScene.Modes.NewGamePlus);

View File

@@ -1,39 +1,191 @@
package forge.adventure.scene;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextField;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.Scaling;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.viewport.ScalingViewport;
import forge.Forge;
import forge.adventure.util.Config;
import forge.adventure.util.Controls;
import forge.adventure.util.Selector;
import forge.adventure.util.UIActor;
/**
* Base class for an GUI scene where the elements are loaded from a json file
*/
public class UIScene extends Scene {
protected UIActor ui;
Stage stage;
String uiFile;
private Dialog keyboardDialog;
private Label kbLabel;
private TextButton keyA, keyB, keyC, keyD, keyE, keyF, keyG, keyH, keyI, keyJ, keyK, keyL, keyM, keyN, keyO, keyP,
keyQ, keyR, keyS, keyT, keyU, keyV, keyW, keyX, keyY, keyZ, key1, key2, key3, key4, key5, key6, key7, key8,
key9, key0, keyDot, keyComma, keyShift, keyBackspace, keySpace, keyOK;
public Actor lastInputField;
public boolean showGamepadSelector = false, lowercaseKey = true, kbVisible=false;
protected UIScene(String uiFilePath) {
public InputEvent eventEnter, eventExit, eventTouchDown, eventTouchUp;
public Vector2 pointer = new Vector2();
public ObjectMap<Integer, Actor> actorObjectMap;
public Actor selectedActor, selectedKey, lastSelectedKey;
public int selectedActorIndex = 0;
public UIScene(String uiFilePath) {
uiFile = uiFilePath;
stage = new Stage(new ScalingViewport(Scaling.stretch, getIntendedWidth(), getIntendedHeight())) {
@Override
public boolean keyUp(int keycode) {
if (Forge.hasGamepad())
return false;
return keyPressed(keycode);
}
@Override
public boolean keyDown(int keyCode) {
if (!Forge.hasGamepad())
return false;
return keyPressed(keyCode);
}
@Override
public boolean mouseMoved(int screenX, int screenY) {
pointerMoved(screenX, screenY);
return super.mouseMoved(screenX, screenY);
}
};
ui = new UIActor(Config.instance().getFile(uiFile=uiFilePath));
ui = new UIActor(Config.instance().getFile(uiFile));
screenImage = ui.findActor("lastScreen");
stage.addActor(ui);
eventTouchDown = new InputEvent();
eventTouchDown.setPointer(-1);
eventTouchDown.setType(InputEvent.Type.touchDown);
eventTouchUp = new InputEvent();
eventTouchUp.setPointer(-1);
eventTouchUp.setType(InputEvent.Type.touchUp);
eventEnter = new InputEvent();
eventEnter.setPointer(-1);
eventEnter.setType(InputEvent.Type.enter);
eventExit = new InputEvent();
eventExit.setPointer(-1);
eventExit.setType(InputEvent.Type.exit);
actorObjectMap = new ObjectMap<>();
keyboardDialog = Controls.newDialog("");
kbLabel = Controls.newLabel("");
kbLabel.setAlignment(Align.center);
kbLabel.setColor(Color.CYAN);
kbLabel.setFontScale(1.5f,1.5f);
keyA = Controls.newTextButton("A", () -> kbLabel.setText(kbLabel.getText()+transformKey("A")));
keyB = Controls.newTextButton("B", () -> kbLabel.setText(kbLabel.getText()+transformKey("B")));
keyC = Controls.newTextButton("C", () -> kbLabel.setText(kbLabel.getText()+transformKey("C")));
keyD = Controls.newTextButton("D", () -> kbLabel.setText(kbLabel.getText()+transformKey("D")));
keyE = Controls.newTextButton("E", () -> kbLabel.setText(kbLabel.getText()+transformKey("E")));
keyF = Controls.newTextButton("F", () -> kbLabel.setText(kbLabel.getText()+transformKey("F")));
keyG = Controls.newTextButton("G", () -> kbLabel.setText(kbLabel.getText()+transformKey("G")));
keyH = Controls.newTextButton("H", () -> kbLabel.setText(kbLabel.getText()+transformKey("H")));
keyI = Controls.newTextButton("I", () -> kbLabel.setText(kbLabel.getText()+transformKey("I")));
keyJ = Controls.newTextButton("J", () -> kbLabel.setText(kbLabel.getText()+transformKey("J")));
keyK = Controls.newTextButton("K", () -> kbLabel.setText(kbLabel.getText()+transformKey("K")));
keyL = Controls.newTextButton("L", () -> kbLabel.setText(kbLabel.getText()+transformKey("L")));
keyM = Controls.newTextButton("M", () -> kbLabel.setText(kbLabel.getText()+transformKey("M")));
keyN = Controls.newTextButton("N", () -> kbLabel.setText(kbLabel.getText()+transformKey("N")));
keyO = Controls.newTextButton("O", () -> kbLabel.setText(kbLabel.getText()+transformKey("O")));
keyP = Controls.newTextButton("P", () -> kbLabel.setText(kbLabel.getText()+transformKey("P")));
keyQ = Controls.newTextButton("Q", () -> kbLabel.setText(kbLabel.getText()+transformKey("Q")));
keyR = Controls.newTextButton("R", () -> kbLabel.setText(kbLabel.getText()+transformKey("R")));
keyS = Controls.newTextButton("S", () -> kbLabel.setText(kbLabel.getText()+transformKey("S")));
keyT = Controls.newTextButton("T", () -> kbLabel.setText(kbLabel.getText()+transformKey("T")));
keyU = Controls.newTextButton("U", () -> kbLabel.setText(kbLabel.getText()+transformKey("U")));
keyV = Controls.newTextButton("V", () -> kbLabel.setText(kbLabel.getText()+transformKey("V")));
keyW = Controls.newTextButton("W", () -> kbLabel.setText(kbLabel.getText()+transformKey("W")));
keyX = Controls.newTextButton("X", () -> kbLabel.setText(kbLabel.getText()+transformKey("X")));
keyY = Controls.newTextButton("Y", () -> kbLabel.setText(kbLabel.getText()+transformKey("Y")));
keyZ = Controls.newTextButton("Z", () -> kbLabel.setText(kbLabel.getText()+transformKey("Z")));
key1 = Controls.newTextButton("1", () -> kbLabel.setText(kbLabel.getText()+"1"));
key2 = Controls.newTextButton("2", () -> kbLabel.setText(kbLabel.getText()+"2"));
key3 = Controls.newTextButton("3", () -> kbLabel.setText(kbLabel.getText()+"3"));
key4 = Controls.newTextButton("4", () -> kbLabel.setText(kbLabel.getText()+"4"));
key5 = Controls.newTextButton("5", () -> kbLabel.setText(kbLabel.getText()+"5"));
key6 = Controls.newTextButton("6", () -> kbLabel.setText(kbLabel.getText()+"6"));
key7 = Controls.newTextButton("7", () -> kbLabel.setText(kbLabel.getText()+"7"));
key8 = Controls.newTextButton("8", () -> kbLabel.setText(kbLabel.getText()+"8"));
key9 = Controls.newTextButton("9", () -> kbLabel.setText(kbLabel.getText()+"9"));
key0 = Controls.newTextButton("0", () -> kbLabel.setText(kbLabel.getText()+"0"));
keyDot = Controls.newTextButton(".", () -> kbLabel.setText(kbLabel.getText()+"."));
keyComma = Controls.newTextButton(",", () -> kbLabel.setText(kbLabel.getText()+","));
keyShift = Controls.newTextButton("Aa", () -> shiftKey());
keyBackspace = Controls.newTextButton("<<", () -> kbLabel.setText(removeLastChar(String.valueOf(kbLabel.getText()))));
keySpace = Controls.newTextButton("SPACE", () -> kbLabel.setText(kbLabel.getText()+" "));
keyOK = Controls.newTextButton("OK", () -> setKeyboardDialogText());
keyboardDialog.getContentTable().add(kbLabel).width(220).height(20).colspan(10).expandX().align(Align.center);
keyboardDialog.getButtonTable().row();
keyboardDialog.getButtonTable().add(key1).width(20).height(20);
keyboardDialog.getButtonTable().add(key2).width(20).height(20);
keyboardDialog.getButtonTable().add(key3).width(20).height(20);
keyboardDialog.getButtonTable().add(key4).width(20).height(20);
keyboardDialog.getButtonTable().add(key5).width(20).height(20);
keyboardDialog.getButtonTable().add(key6).width(20).height(20);
keyboardDialog.getButtonTable().add(key7).width(20).height(20);
keyboardDialog.getButtonTable().add(key8).width(20).height(20);
keyboardDialog.getButtonTable().add(key9).width(20).height(20);
keyboardDialog.getButtonTable().add(key0).width(20).height(20);
keyboardDialog.getButtonTable().row();
keyboardDialog.getButtonTable().add(keyQ).width(20).height(20);
keyboardDialog.getButtonTable().add(keyW).width(20).height(20);
keyboardDialog.getButtonTable().add(keyE).width(20).height(20);
keyboardDialog.getButtonTable().add(keyR).width(20).height(20);
keyboardDialog.getButtonTable().add(keyT).width(20).height(20);
keyboardDialog.getButtonTable().add(keyY).width(20).height(20);
keyboardDialog.getButtonTable().add(keyU).width(20).height(20);
keyboardDialog.getButtonTable().add(keyI).width(20).height(20);
keyboardDialog.getButtonTable().add(keyO).width(20).height(20);
keyboardDialog.getButtonTable().add(keyP).width(20).height(20);
keyboardDialog.getButtonTable().row();
keyboardDialog.getButtonTable().add(keyA).width(20).height(20);
keyboardDialog.getButtonTable().add(keyS).width(20).height(20);
keyboardDialog.getButtonTable().add(keyD).width(20).height(20);
keyboardDialog.getButtonTable().add(keyF).width(20).height(20);
keyboardDialog.getButtonTable().add(keyG).width(20).height(20);
keyboardDialog.getButtonTable().add(keyH).width(20).height(20);
keyboardDialog.getButtonTable().add(keyJ).width(20).height(20);
keyboardDialog.getButtonTable().add(keyK).width(20).height(20);
keyboardDialog.getButtonTable().add(keyL).width(20).height(20);
keyboardDialog.getButtonTable().add(keyBackspace).width(20).height(20);
keyboardDialog.getButtonTable().row();
keyboardDialog.getButtonTable().add(keyShift).width(20).height(20);
keyboardDialog.getButtonTable().add(keyZ).width(20).height(20);
keyboardDialog.getButtonTable().add(keyX).width(20).height(20);
keyboardDialog.getButtonTable().add(keyC).width(20).height(20);
keyboardDialog.getButtonTable().add(keyV).width(20).height(20);
keyboardDialog.getButtonTable().add(keyB).width(20).height(20);
keyboardDialog.getButtonTable().add(keyN).width(20).height(20);
keyboardDialog.getButtonTable().add(keyM).width(20).height(20);
keyboardDialog.getButtonTable().add(keyDot).width(20).height(20);
keyboardDialog.getButtonTable().add(keyComma).width(20).height(20);
keyboardDialog.getButtonTable().row();
keyboardDialog.getButtonTable().add(keySpace).width(150).height(20).colspan(6);
keyboardDialog.getButtonTable().add(keyOK).width(100).height(20).colspan(4);
keyboardDialog.setKeepWithinStage(true);
keyboardDialog.setResizable(false);
}
@Override
@@ -62,32 +214,531 @@ public class UIScene extends Scene {
return true;
}
public boolean pointerMoved(int screenX, int screenY) {
return false;
}
public void performTouch(Actor actor) {
if (actor == null)
return;
actor.fire(eventTouchDown);
Timer.schedule(new Timer.Task() {
@Override
public void run() {
actor.fire(eventTouchUp);
}
}, 0.10f);
}
private String transformKey(String c) {
return lowercaseKey ? c.toLowerCase() : c.toUpperCase();
}
public void toggleShiftOrBackspace(boolean shift) {
if (shift)
performTouch(keyShift);
else
performTouch(keyBackspace);
}
public void hideOnScreenKeyboard() {
kbVisible = false;
keyboardDialog.hide();
selectedActor = lastInputField;
}
private void shiftKey() {
lowercaseKey = !lowercaseKey;
keyShift.getLabel().setColor(lowercaseKey ? Color.WHITE : Color.CYAN);
keyA.getLabel().setText(lowercaseKey ? "a" : "A");
keyB.getLabel().setText(lowercaseKey ? "b" : "B");
keyC.getLabel().setText(lowercaseKey ? "c" : "C");
keyD.getLabel().setText(lowercaseKey ? "d" : "D");
keyE.getLabel().setText(lowercaseKey ? "e" : "E");
keyF.getLabel().setText(lowercaseKey ? "f" : "F");
keyG.getLabel().setText(lowercaseKey ? "g" : "G");
keyH.getLabel().setText(lowercaseKey ? "h" : "H");
keyI.getLabel().setText(lowercaseKey ? "i" : "I");
keyJ.getLabel().setText(lowercaseKey ? "j" : "J");
keyK.getLabel().setText(lowercaseKey ? "k" : "K");
keyL.getLabel().setText(lowercaseKey ? "l" : "L");
keyM.getLabel().setText(lowercaseKey ? "m" : "M");
keyN.getLabel().setText(lowercaseKey ? "n" : "N");
keyO.getLabel().setText(lowercaseKey ? "o" : "O");
keyP.getLabel().setText(lowercaseKey ? "p" : "P");
keyQ.getLabel().setText(lowercaseKey ? "q" : "Q");
keyR.getLabel().setText(lowercaseKey ? "r" : "R");
keyS.getLabel().setText(lowercaseKey ? "s" : "S");
keyT.getLabel().setText(lowercaseKey ? "t" : "T");
keyU.getLabel().setText(lowercaseKey ? "u" : "U");
keyV.getLabel().setText(lowercaseKey ? "v" : "V");
keyW.getLabel().setText(lowercaseKey ? "w" : "W");
keyX.getLabel().setText(lowercaseKey ? "x" : "X");
keyY.getLabel().setText(lowercaseKey ? "y" : "Y");
keyZ.getLabel().setText(lowercaseKey ? "z" : "Z");
}
public void setSelectedKey(int keyCode) {
switch(keyCode) {
case Input.Keys.DPAD_DOWN:
if (selectedKey == null)
selectActor(key1, false);
else if (selectedKey == key1)
selectActor(keyQ, false);
else if (selectedKey == keyQ)
selectActor(keyA, false);
else if (selectedKey == keyA)
selectActor(keyShift, false);
else if (selectedKey == keyShift)
selectActor(keySpace, false);
else if (selectedKey == key2)
selectActor(keyW, false);
else if (selectedKey == keyW)
selectActor(keyS, false);
else if (selectedKey == keyS)
selectActor(keyZ, false);
else if (selectedKey == keyZ)
selectActor(keySpace, false);
else if (selectedKey == key3)
selectActor(keyE, false);
else if (selectedKey == keyE)
selectActor(keyD, false);
else if (selectedKey == keyD)
selectActor(keyX, false);
else if (selectedKey == keyX)
selectActor(keySpace, false);
else if (selectedKey == key4)
selectActor(keyR, false);
else if (selectedKey == keyR)
selectActor(keyF, false);
else if (selectedKey == keyF)
selectActor(keyC, false);
else if (selectedKey == keyC)
selectActor(keySpace, false);
else if (selectedKey == key5)
selectActor(keyT, false);
else if (selectedKey == keyT)
selectActor(keyG, false);
else if (selectedKey == keyG)
selectActor(keyV, false);
else if (selectedKey == keyV)
selectActor(keySpace, false);
else if (selectedKey == key6)
selectActor(keyY, false);
else if (selectedKey == keyY)
selectActor(keyH, false);
else if (selectedKey == keyH)
selectActor(keyB, false);
else if (selectedKey == keyB)
selectActor(keySpace, false);
else if (selectedKey == key7)
selectActor(keyU, false);
else if (selectedKey == keyU)
selectActor(keyJ, false);
else if (selectedKey == keyJ)
selectActor(keyN, false);
else if (selectedKey == keyN)
selectActor(keyOK, false);
else if (selectedKey == key8)
selectActor(keyI, false);
else if (selectedKey == keyI)
selectActor(keyK, false);
else if (selectedKey == keyK)
selectActor(keyM, false);
else if (selectedKey == keyM)
selectActor(keyOK, false);
else if (selectedKey == key9)
selectActor(keyO, false);
else if (selectedKey == keyO)
selectActor(keyL, false);
else if (selectedKey == keyL)
selectActor(keyDot, false);
else if (selectedKey == keyDot)
selectActor(keyOK, false);
else if (selectedKey == key0)
selectActor(keyP, false);
else if (selectedKey == keyP)
selectActor(keyBackspace, false);
else if (selectedKey == keyBackspace)
selectActor(keyComma, false);
else if (selectedKey == keyComma)
selectActor(keyOK, false);
break;
case Input.Keys.DPAD_UP:
if (selectedKey == null)
selectActor(key1, false);
else if (selectedKey == keySpace || selectedKey == keyOK)
selectActor(lastSelectedKey, false);
else if (selectedKey == keyShift)
selectActor(keyA, false);
else if (selectedKey == keyA)
selectActor(keyQ, false);
else if (selectedKey == keyQ)
selectActor(key1, false);
else if (selectedKey == keyZ)
selectActor(keyS, false);
else if (selectedKey == keyS)
selectActor(keyW, false);
else if (selectedKey == keyW)
selectActor(key2, false);
else if (selectedKey == keyX)
selectActor(keyD, false);
else if (selectedKey == keyD)
selectActor(keyE, false);
else if (selectedKey == keyE)
selectActor(key3, false);
else if (selectedKey == keyC)
selectActor(keyF, false);
else if (selectedKey == keyF)
selectActor(keyR, false);
else if (selectedKey == keyR)
selectActor(key4, false);
else if (selectedKey == keyV)
selectActor(keyG, false);
else if (selectedKey == keyG)
selectActor(keyT, false);
else if (selectedKey == keyT)
selectActor(key5, false);
else if (selectedKey == keyB)
selectActor(keyH, false);
else if (selectedKey == keyH)
selectActor(keyY, false);
else if (selectedKey == keyY)
selectActor(key6, false);
else if (selectedKey == keyN)
selectActor(keyJ, false);
else if (selectedKey == keyJ)
selectActor(keyU, false);
else if (selectedKey == keyU)
selectActor(key7, false);
else if (selectedKey == keyM)
selectActor(keyK, false);
else if (selectedKey == keyK)
selectActor(keyI, false);
else if (selectedKey == keyI)
selectActor(key8, false);
else if (selectedKey == keyDot)
selectActor(keyL, false);
else if (selectedKey == keyL)
selectActor(keyO, false);
else if (selectedKey == keyO)
selectActor(key9, false);
else if (selectedKey == keyComma)
selectActor(keyBackspace, false);
else if (selectedKey == keyBackspace)
selectActor(keyP, false);
else if (selectedKey == keyP)
selectActor(key0, false);
break;
case Input.Keys.DPAD_LEFT:
if (selectedKey == null)
selectActor(key1, false);
else if (selectedKey == keyOK)
selectActor(keySpace, false);
else if (selectedKey == keyComma)
selectActor(keyDot, false);
else if (selectedKey == keyDot)
selectActor(keyM, false);
else if (selectedKey == keyM)
selectActor(keyN, false);
else if (selectedKey == keyN)
selectActor(keyB, false);
else if (selectedKey == keyB)
selectActor(keyV, false);
else if (selectedKey == keyV)
selectActor(keyC, false);
else if (selectedKey == keyC)
selectActor(keyX, false);
else if (selectedKey == keyX)
selectActor(keyZ, false);
else if (selectedKey == keyZ)
selectActor(keyShift, false);
else if (selectedKey == keyBackspace)
selectActor(keyL, false);
else if (selectedKey == keyL)
selectActor(keyK, false);
else if (selectedKey == keyK)
selectActor(keyJ, false);
else if (selectedKey == keyJ)
selectActor(keyH, false);
else if (selectedKey == keyH)
selectActor(keyG, false);
else if (selectedKey == keyG)
selectActor(keyF, false);
else if (selectedKey == keyF)
selectActor(keyD, false);
else if (selectedKey == keyD)
selectActor(keyS, false);
else if (selectedKey == keyS)
selectActor(keyA, false);
else if (selectedKey == keyP)
selectActor(keyO, false);
else if (selectedKey == keyO)
selectActor(keyI, false);
else if (selectedKey == keyI)
selectActor(keyU, false);
else if (selectedKey == keyU)
selectActor(keyY, false);
else if (selectedKey == keyY)
selectActor(keyT, false);
else if (selectedKey == keyT)
selectActor(keyR, false);
else if (selectedKey == keyR)
selectActor(keyE, false);
else if (selectedKey == keyE)
selectActor(keyW, false);
else if (selectedKey == keyW)
selectActor(keyQ, false);
else if (selectedKey == key0)
selectActor(key9, false);
else if (selectedKey == key9)
selectActor(key8, false);
else if (selectedKey == key8)
selectActor(key7, false);
else if (selectedKey == key7)
selectActor(key6, false);
else if (selectedKey == key6)
selectActor(key5, false);
else if (selectedKey == key5)
selectActor(key4, false);
else if (selectedKey == key4)
selectActor(key3, false);
else if (selectedKey == key3)
selectActor(key2, false);
else if (selectedKey == key2)
selectActor(key1, false);
break;
case Input.Keys.DPAD_RIGHT:
if (selectedKey == null)
selectActor(key1, false);
else if (selectedKey == key1)
selectActor(key2, false);
else if (selectedKey == key2)
selectActor(key3, false);
else if (selectedKey == key3)
selectActor(key4, false);
else if (selectedKey == key4)
selectActor(key5, false);
else if (selectedKey == key5)
selectActor(key6, false);
else if (selectedKey == key6)
selectActor(key7, false);
else if (selectedKey == key7)
selectActor(key8, false);
else if (selectedKey == key8)
selectActor(key9, false);
else if (selectedKey == key9)
selectActor(key0, false);
else if (selectedKey == keyQ)
selectActor(keyW, false);
else if (selectedKey == keyW)
selectActor(keyE, false);
else if (selectedKey == keyE)
selectActor(keyR, false);
else if (selectedKey == keyR)
selectActor(keyT, false);
else if (selectedKey == keyT)
selectActor(keyY, false);
else if (selectedKey == keyY)
selectActor(keyU, false);
else if (selectedKey == keyU)
selectActor(keyI, false);
else if (selectedKey == keyI)
selectActor(keyO, false);
else if (selectedKey == keyO)
selectActor(keyP, false);
else if (selectedKey == keyA)
selectActor(keyS, false);
else if (selectedKey == keyS)
selectActor(keyD, false);
else if (selectedKey == keyD)
selectActor(keyF, false);
else if (selectedKey == keyF)
selectActor(keyG, false);
else if (selectedKey == keyG)
selectActor(keyH, false);
else if (selectedKey == keyH)
selectActor(keyJ, false);
else if (selectedKey == keyJ)
selectActor(keyK, false);
else if (selectedKey == keyK)
selectActor(keyL, false);
else if (selectedKey == keyL)
selectActor(keyBackspace, false);
else if (selectedKey == keyShift)
selectActor(keyZ, false);
else if (selectedKey == keyZ)
selectActor(keyX, false);
else if (selectedKey == keyX)
selectActor(keyC, false);
else if (selectedKey == keyC)
selectActor(keyV, false);
else if (selectedKey == keyV)
selectActor(keyB, false);
else if (selectedKey == keyB)
selectActor(keyN, false);
else if (selectedKey == keyN)
selectActor(keyM, false);
else if (selectedKey == keyM)
selectActor(keyDot, false);
else if (selectedKey == keyDot)
selectActor(keyComma, false);
else if (selectedKey == keySpace)
selectActor(keyOK, false);
break;
default:
break;
}
}
private String removeLastChar(String s) {
return (s == null || s.length() == 0)
? ""
: (s.substring(0, s.length() - 1));
}
private void setKeyboardDialogText() {
if (lastInputField == null)
return;
if (lastInputField instanceof TextField) {
if (!kbLabel.getText().isEmpty()) {
((TextField) lastInputField).setText(String.valueOf(kbLabel.getText()));
kbLabel.setText("");
}
}
kbVisible = false;
keyboardDialog.hide();
selectActor(lastInputField, false);
}
public void showOnScreenKeyboard(String text) {
kbVisible = true;
if (lowercaseKey)
shiftKey();
kbLabel.setText(text);
keyboardDialog.show(stage);
selectActor(key1, false);
}
public void keyOK() {
selectActor(keyOK, false);
}
public void clearActorObjects() {
actorObjectMap.clear();
selectedActor = null;
}
public void addActorObject(Actor actor) {
int index = actorObjectMap.size;
actorObjectMap.put(index, actor);
}
public void unselectActors() {
if (actorObjectMap.isEmpty())
return;
for (Actor actor : actorObjectMap.values()) {
if (actor != null) {
if (actor instanceof TextButton)
((TextButton) actor).fire(eventExit);
else if (actor instanceof Selector)
((Selector) actor).getLabel().fire(eventExit);
else if (actor instanceof TextField) {
if (stage.getKeyboardFocus() == actor)
stage.setKeyboardFocus(null);
} else if (actor instanceof ImageButton) {
((ImageButton) actor).setChecked(false);
} else {
actor.fire(eventExit);
}
}
}
}
public void selectNextActor(boolean press) {
if (actorObjectMap.isEmpty())
return;
if (selectedActor == null) {
selectActor(actorObjectMap.get(0), press);
} else {
selectActor(actorObjectMap.get(selectedActorIndex+1), press);
}
}
public void selectPreviousActor(boolean press) {
if (actorObjectMap.isEmpty())
return;
if (selectedActor == null) {
selectActor(actorObjectMap.get(0), press);
} else {
selectActor(actorObjectMap.get(selectedActorIndex-1), press);
}
}
public void selectActor(Actor actor, boolean press) {
if (actor == null)
return;
if (kbVisible) {
if (selectedKey != null) {
selectedKey.fire(eventExit);
if (selectedKey instanceof TextButton)
if (!(((TextButton) selectedKey) == keyOK || ((TextButton) selectedKey) == keySpace))
lastSelectedKey = selectedKey;
}
selectedKey = actor;
selectedKey.fire(eventEnter);
if (press)
performTouch(selectedKey);
} else {
unselectActors();
if (actorObjectMap.isEmpty())
return;
Integer key = actorObjectMap.findKey(actor, true);
if (key == null)
return;
Actor a = actorObjectMap.get(key);
if (a != null) {
if (a instanceof TextButton)
((TextButton) a).fire(eventEnter);
else if (a instanceof Selector)
((Selector) a).getLabel().fire(eventEnter);
else if (a instanceof TextField) {
stage.setKeyboardFocus(a);
} else if (a instanceof ImageButton) {
((ImageButton) a).setChecked(true);
}
selectedActor = a;
selectedActorIndex = key;
if (press)
performTouch(a);
}
}
}
public void selectCurrent() {
Actor current = actorObjectMap.get(selectedActorIndex);
if (current == null)
current = actorObjectMap.get(0);
selectActor(current, false);
}
public void updateHovered() {
for (Actor a : actorObjectMap.values()) {
if (a != null && Controls.actorContainsVector(a, pointer)) {
selectActor(a, false);
break;
}
}
}
Image screenImage;
TextureRegion backgroundTexture;
TextureRegion market, tavern;
@Override
public void enter() {
if (screenImage != null) {
if (backgroundTexture != null)
backgroundTexture.getTexture().dispose();
final Pixmap pixmap = Pixmap.createFromFrameBuffer(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
final Pixmap potPixmap = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Pixmap.Format.RGBA8888);
potPixmap.setBlending(Pixmap.Blending.SourceOver);
potPixmap.drawPixmap(pixmap, 0, 0);
potPixmap.setColor(0, 0, 0, 0.75f);
potPixmap.fillRectangle(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
backgroundTexture = new TextureRegion(new Texture(potPixmap), 0, Gdx.graphics.getHeight(), Gdx.graphics.getWidth(), -Gdx.graphics.getHeight());
screenImage.setDrawable(new TextureRegionDrawable(backgroundTexture));
pixmap.dispose();
potPixmap.dispose();
//create from lastPreview from header...
try {
backgroundTexture = new TextureRegion(Forge.lastPreview);
backgroundTexture.flip(false, true);
screenImage.setDrawable(new TextureRegionDrawable(backgroundTexture));
} catch (Exception e) {
e.printStackTrace();
}
}
Gdx.input.setInputProcessor(stage); //Start taking input from the ui
super.enter();
}
@Override
public boolean leave() {
clearActorObjects();
selectedActor = null;
return super.leave();
}
}

View File

@@ -10,18 +10,17 @@ import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.Touchpad;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Scaling;
import com.badlogic.gdx.utils.viewport.ScalingViewport;
import forge.Forge;
import forge.adventure.player.AdventurePlayer;
import forge.adventure.scene.*;
import forge.adventure.scene.Scene;
import forge.adventure.scene.SceneType;
import forge.adventure.util.Config;
import forge.adventure.util.Controls;
import forge.adventure.util.Current;
@@ -121,12 +120,14 @@ public class GameHUD extends Stage {
avatarborder.addListener(new ConsoleToggleListener());
gamehud.addListener(new ConsoleToggleListener());
}
WorldSave.getCurrentSave().onLoad(new Runnable() {
@Override
public void run() {
GameHUD.this.enter();
}
});
WorldSave.getCurrentSave().onLoad(() -> GameHUD.this.enter());
eventTouchDown = new InputEvent();
eventTouchDown.setPointer(-1);
eventTouchDown.setType(InputEvent.Type.touchDown);
eventTouchUp = new InputEvent();
eventTouchUp.setPointer(-1);
eventTouchUp.setType(InputEvent.Type.touchUp);
Controllers.addListener(this);
}
private void openMap() {
@@ -317,8 +318,31 @@ public class GameHUD extends Stage {
showButtons();
}
}
if (keycode == Input.Keys.BUTTON_B) {
performTouch(statsActor);
}
if (keycode == Input.Keys.BUTTON_Y) {
performTouch(inventoryActor);
}
if (keycode == Input.Keys.BUTTON_X) {
performTouch(deckActor);
}
if (keycode == Input.Keys.BUTTON_A) {
performTouch(menuActor);
}
return super.keyDown(keycode);
}
public void performTouch(Actor actor) {
if (actor == null)
return;
actor.fire(eventTouchDown);
Timer.schedule(new Timer.Task() {
@Override
public void run() {
actor.fire(eventTouchUp);
}
}, 0.10f);
}
public void hideButtons() {
if (isShowing)
return;
@@ -345,6 +369,123 @@ public class GameHUD extends Stage {
deckActor.addAction(Actions.sequence(Actions.delay(0.25f), Actions.parallel(Actions.show(), Actions.alpha(opacity,0.1f), Actions.moveTo(referenceX, deckActor.getY(), 0.25f))));
FThreads.delayInEDT(300, () -> isShowing = false);
}
@Override
public void connected(Controller controller) {
}
@Override
public void disconnected(Controller controller) {
}
@Override
public boolean buttonDown(Controller controller, int buttonIndex) {
if (Forge.getCurrentScene() instanceof HudScene) {
if (controller.getMapping().buttonA == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.BUTTON_A);
if (controller.getMapping().buttonB == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.BUTTON_B);
if (controller.getMapping().buttonX == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.BUTTON_X);
if (controller.getMapping().buttonY == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.BUTTON_Y);
if (controller.getMapping().buttonDpadUp == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_UP);
if (controller.getMapping().buttonDpadRight == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_RIGHT);
if (controller.getMapping().buttonDpadDown == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_DOWN);
if (controller.getMapping().buttonDpadLeft == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_LEFT);
} else if (Forge.getCurrentScene() instanceof UIScene) {
if (controller.getMapping().buttonDpadUp == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.DPAD_UP);
if (controller.getMapping().buttonDpadRight == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.DPAD_RIGHT);
if (controller.getMapping().buttonDpadDown == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.DPAD_DOWN);
if (controller.getMapping().buttonDpadLeft == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.DPAD_LEFT);
if (controller.getMapping().buttonA == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_A);
if (controller.getMapping().buttonB == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_B);
if (controller.getMapping().buttonX == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_X);
if (controller.getMapping().buttonY == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_Y);
if (controller.getMapping().buttonR1 == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_R1);
if (controller.getMapping().buttonL1 == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_L1);
if (controller.getMapping().buttonR2 == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_R2);
if (controller.getMapping().buttonL2 == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_L2);
if (controller.getMapping().buttonBack == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_SELECT);
if (controller.getMapping().buttonStart == buttonIndex)
return ((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_START);
}
return false;
}
@Override
public boolean buttonUp(Controller controller, int buttonIndex) {
if (Forge.getCurrentScene() instanceof HudScene) {
if (controller.getMapping().buttonA == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.BUTTON_A);
if (controller.getMapping().buttonB == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.BUTTON_B);
if (controller.getMapping().buttonX == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.BUTTON_X);
if (controller.getMapping().buttonY == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.BUTTON_Y);
if (controller.getMapping().buttonDpadUp == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_UP);
if (controller.getMapping().buttonDpadRight == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_RIGHT);
if (controller.getMapping().buttonDpadDown == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_DOWN);
if (controller.getMapping().buttonDpadLeft == buttonIndex)
return ((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_LEFT);
}
return false;
}
@Override
public boolean axisMoved(Controller controller, int axisIndex, float value) {
if (Forge.hasGamepad()) {
if (Forge.getCurrentScene() instanceof HudScene) {
if (controller.getAxis(controller.getMapping().axisLeftX) > 0.5f) {
((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_RIGHT);
} else if (controller.getAxis(controller.getMapping().axisLeftX) < -0.5f) {
((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_LEFT);
} else {
((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_LEFT);
((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_RIGHT);
}
if (controller.getAxis(controller.getMapping().axisLeftY) > 0.5f) {
((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_DOWN);
} else if (controller.getAxis(controller.getMapping().axisLeftY) < -0.5f) {
((HudScene) Forge.getCurrentScene()).keyDown(Input.Keys.DPAD_UP);
} else {
((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_UP);
((HudScene) Forge.getCurrentScene()).keyUp(Input.Keys.DPAD_DOWN);
}
} else if (Forge.getCurrentScene() instanceof UIScene) {
if (controller.getAxis(4) == 1f) //L2
((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_L2);
if (controller.getAxis(5) == 1f) //R2
((UIScene) Forge.getCurrentScene()).keyPressed(Input.Keys.BUTTON_R2);
}
}
return true;
}
class ConsoleToggleListener extends ActorGestureListener {
public ConsoleToggleListener() {
getGestureDetector().setLongPressSeconds(0.6f);

View File

@@ -98,7 +98,7 @@ public abstract class GameStage extends Stage {
return;
foregroundSprites.removeActor(player);
player = null;
GameStage.this.getPlayerSprite();
GameStage.this.GetPlayer();
}
});
camera = (OrthographicCamera) getCamera();
@@ -211,19 +211,19 @@ public abstract class GameStage extends Stage {
@Override
public boolean keyDown(int keycode) {
super.keyDown(keycode);
if (keycode == Input.Keys.LEFT || keycode == Input.Keys.A)//todo config
if (keycode == Input.Keys.LEFT || keycode == Input.Keys.A || keycode == Input.Keys.DPAD_LEFT)//todo config
{
player.getMovementDirection().x = -1;
}
if (keycode == Input.Keys.RIGHT || keycode == Input.Keys.D)//todo config
if (keycode == Input.Keys.RIGHT || keycode == Input.Keys.D || keycode == Input.Keys.DPAD_RIGHT)//todo config
{
player.getMovementDirection().x = +1;
}
if (keycode == Input.Keys.UP || keycode == Input.Keys.W)//todo config
if (keycode == Input.Keys.UP || keycode == Input.Keys.W || keycode == Input.Keys.DPAD_UP)//todo config
{
player.getMovementDirection().y = +1;
}
if (keycode == Input.Keys.DOWN || keycode == Input.Keys.S)//todo config
if (keycode == Input.Keys.DOWN || keycode == Input.Keys.S || keycode == Input.Keys.DPAD_DOWN)//todo config
{
player.getMovementDirection().y = -1;
}

View File

@@ -16,6 +16,7 @@ import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
@@ -79,7 +80,10 @@ public class MapStage extends GameStage {
//These maps are defined as embedded properties within the Tiled maps.
private EffectData effect; //"Dungeon Effect": Character Effect applied to all adversaries within the map.
private boolean preventEscape = false; //Prevents player from escaping the dungeon by any means that aren't an exit.
private boolean foundPlayerSpawn;
private ObjectMap<Integer, TextButton> dialogButtonMap;
private int selected = 0;
public InputEvent eventEnter, eventExit, eventTouchDown, eventTouchUp;
TextButton selectedKey;
public boolean getDialogOnlyInput() {
@@ -120,12 +124,23 @@ public class MapStage extends GameStage {
private MapStage()
{
dialog = Controls.newDialog("");
eventTouchDown = new InputEvent();
eventTouchDown.setPointer(-1);
eventTouchDown.setType(InputEvent.Type.touchDown);
eventTouchUp = new InputEvent();
eventTouchUp.setPointer(-1);
eventTouchUp.setType(InputEvent.Type.touchUp);
eventEnter = new InputEvent();
eventEnter.setPointer(-1);
eventEnter.setType(InputEvent.Type.enter);
eventExit = new InputEvent();
eventExit.setPointer(-1);
eventExit.setType(InputEvent.Type.exit);
}
public static MapStage getInstance() {
return instance == null ? instance = new MapStage() : instance;
}
public void addMapActor(MapObject obj, MapActor newActor) {
newActor.setWidth(Float.parseFloat(obj.getProperties().get("width").toString()));
newActor.setHeight(Float.parseFloat(obj.getProperties().get("height").toString()));
@@ -421,7 +436,7 @@ public class MapStage extends GameStage {
float y = Float.parseFloat(prop.get("y").toString());
float w = Float.parseFloat(prop.get("width").toString());
float h = Float.parseFloat(prop.get("height").toString());
String targetMap=prop.get("teleport").toString();
boolean spawnPlayerThere=(targetMap==null||targetMap.isEmpty()&&sourceMap.isEmpty())||//if target is null and "from world"
!sourceMap.isEmpty()&&targetMap.equals(sourceMap);
@@ -669,6 +684,8 @@ public class MapStage extends GameStage {
break;
} else if (actor instanceof RewardSprite) {
Gdx.input.vibrate(50);
if (Controllers.getCurrent() != null && Controllers.getCurrent().canVibrate())
Controllers.getCurrent().startVibration(100,1);
startPause(0.1f, () -> { //Switch to item pickup scene.
RewardSprite RS = (RewardSprite) actor;
RewardScene.instance().loadRewards(RS.getRewards(), RewardScene.Type.Loot, null);
@@ -690,6 +707,9 @@ public class MapStage extends GameStage {
mob.setAnimation(CharacterSprite.AnimationTypes.Attack);
SoundSystem.instance.play(SoundEffectType.Block, false);
Gdx.input.vibrate(50);
int duration = mob.getData().boss ? 400 : 200;
if (Controllers.getCurrent() != null && Controllers.getCurrent().canVibrate())
Controllers.getCurrent().startVibration(duration,1);
startPause(0.8f, () -> {
Forge.setCursor(null, Forge.magnifyToggle ? "1" : "2");
SoundSystem.instance.play(SoundEffectType.ManaBurn, false);
@@ -717,16 +737,30 @@ public class MapStage extends GameStage {
public boolean isInMap() {
return isInMap;
}
public boolean isDialogOnlyInput() {
return dialogOnlyInput;
}
public void showDialog() {
if (dialogButtonMap == null)
dialogButtonMap = new ObjectMap<>();
else
dialogButtonMap.clear();
for (int i = 0; i < dialog.getButtonTable().getCells().size; i++) {
dialogButtonMap.put(i, (TextButton) dialog.getButtonTable().getCells().get(i).getActor());
}
dialog.show(dialogStage, Actions.show());
dialog.setPosition((dialogStage.getWidth() - dialog.getWidth()) / 2, (dialogStage.getHeight() - dialog.getHeight()) / 2);
dialogOnlyInput = true;
if (Forge.hasGamepad())
selectDialogButton(dialogButtonMap.get(0), false);
}
public void hideDialog() {
dialog.hide(Actions.sequence(Actions.sizeTo(dialog.getOriginX(), dialog.getOriginY(), 0.3f), Actions.hide()));
dialogOnlyInput = false;
selected = 0;
selectedKey = null;
}
public void setDialogStage(Stage dialogStage) {
@@ -762,4 +796,62 @@ public class MapStage extends GameStage {
public void resetQuestFlags() {
changes.getMapFlags().clear();
}
public boolean buttonPress(int keycode) {
if (dialogOnlyInput) {
if (keycode == Input.Keys.DPAD_UP) {
selectPreviousDialogButton();
}
if (keycode == Input.Keys.DPAD_DOWN) {
selectNextDialogButton();
}
if (keycode == Input.Keys.BUTTON_A) {
selectDialogButton(selectedKey, true);
}
}
return true;
}
private void selectDialogButton(TextButton dialogButton, boolean press) {
if (dialogOnlyInput) {
if (selectedKey != null)
selectedKey.fire(eventExit);
if (dialogButton != null && dialogButton.isVisible()) {
dialogButton.fire(eventEnter);
selectedKey = dialogButton;
selected = getButtonIndexKey(dialogButton);
if (press)
performTouch(dialogButton);
}
}
}
public void performTouch(Actor actor) {
if (actor == null)
return;
actor.fire(eventTouchDown);
Timer.schedule(new Timer.Task() {
@Override
public void run() {
actor.fire(eventTouchUp);
}
}, 0.10f);
}
private int getButtonIndexKey(TextButton dialogbutton) {
if (dialogButtonMap.isEmpty())
return 0;
Integer key = dialogButtonMap.findKey(dialogbutton, true);
if (key == null)
return 0;
return key;
}
private void selectNextDialogButton() {
if (dialogButtonMap.size < 2)
return;
selectDialogButton(dialogButtonMap.get(selected+1), false);
}
private void selectPreviousDialogButton() {
if (dialogButtonMap.size < 2)
return;
selectDialogButton(dialogButtonMap.get(selected-1), false);
}
}

View File

@@ -1,7 +1,7 @@
package forge.adventure.stage;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.controllers.Controllers;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Actor;
@@ -115,6 +115,9 @@ public class WorldStage extends GameStage implements SaveFileContent {
mob.setAnimation(CharacterSprite.AnimationTypes.Attack);
SoundSystem.instance.play(SoundEffectType.Block, false);
Gdx.input.vibrate(50);
int duration = mob.getData().boss ? 400 : 200;
if (Controllers.getCurrent() != null && Controllers.getCurrent().canVibrate())
Controllers.getCurrent().startVibration(duration,1);
startPause(0.8f, () -> {
Forge.setCursor(null, Forge.magnifyToggle ? "1" : "2");
SoundSystem.instance.play(SoundEffectType.ManaBurn, false);

Some files were not shown because too many files have changed in this diff Show More