Merge remote-tracking branch 'upstream/master' into collector-number-in-card-list-and-card-db-refactoring

This commit is contained in:
leriomaggio
2021-07-06 08:36:40 +01:00
1192 changed files with 9811 additions and 4628 deletions

View File

@@ -21,7 +21,7 @@ import forge.util.storage.StorageBase;
public class NetDeckCategory extends StorageBase<Deck> {
public static final String PREFIX = "NET_DECK_";
private static Map<String, NetDeckCategory> constructed, commander, brawl;
private static Map<String, NetDeckCategory> constructed, commander, brawl, oathbreaker, tinyleaders;
private static Map<String, NetDeckCategory> loadCategories(String filename) {
Map<String, NetDeckCategory> categories = new TreeMap<>();
@@ -64,6 +64,18 @@ public class NetDeckCategory extends StorageBase<Deck> {
}
categories = brawl;
break;
case Oathbreaker:
if (oathbreaker == null) {
oathbreaker = loadCategories(ForgeConstants.NET_DECKS_OATHBREAKER_LIST_FILE);
}
categories = oathbreaker;
break;
case TinyLeaders:
if (tinyleaders == null) {
tinyleaders = loadCategories(ForgeConstants.NET_DECKS_TINYLEADERS_LIST_FILE);
}
categories = tinyleaders;
break;
default:
return null;
}

View File

@@ -87,7 +87,7 @@ public class BoosterDraft implements IBoosterDraft {
protected boolean generateProduct() {
switch (this.draftFormat) {
case Full: // Draft from all cards in Forge
final Supplier<List<PaperCard>> s = new UnOpenedProduct(SealedProduct.Template.genericBooster);
final Supplier<List<PaperCard>> s = new UnOpenedProduct(SealedProduct.Template.genericDraftBooster);
for (int i = 0; i < 3; i++) {
this.product.add(s);

View File

@@ -107,7 +107,7 @@ public class CustomLimited extends DeckBase {
slots.add(ImmutablePair.of(kv[1], Integer.parseInt(kv[0])));
}
} else
slots = SealedProduct.Template.genericBooster.getSlots();
slots = SealedProduct.Template.genericDraftBooster.getSlots();
final CustomLimited cd = new CustomLimited(data.get("Name"), slots);
cd.landSetCode = data.get("LandSetCode");

View File

@@ -164,7 +164,7 @@ public class SealedCardPoolGenerator {
switch(poolType) {
case Full:
// Choose number of boosters
if (!chooseNumberOfBoosters(new UnOpenedProduct(SealedProduct.Template.genericBooster))) {
if (!chooseNumberOfBoosters(new UnOpenedProduct(SealedProduct.Template.genericDraftBooster))) {
return;
}
landSetCode = CardEdition.Predicates.getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions()).getCode();
@@ -209,7 +209,7 @@ public class SealedCardPoolGenerator {
code = pieces[1];
}
// Generate boosters
// Generate draft boosters
for(int i = 0; i < num; i++) {
this.product.add(new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(code)));
}

View File

@@ -271,7 +271,7 @@ public abstract class InputPayMana extends InputSyncronizedBase {
}
// Store some information about color costs to help with any mana choices
if (colorNeeded == 0) { // only colorless left
if (colorNeeded == 0) { // only colorless left
if (saPaidFor.getHostCard() != null && saPaidFor.getHostCard().hasSVar("ManaNeededToAvoidNegativeEffect")) {
String[] negEffects = saPaidFor.getHostCard().getSVar("ManaNeededToAvoidNegativeEffect").split(",");
for (String negColor : negEffects) {

View File

@@ -72,7 +72,6 @@ public class InputPayManaOfCostPayment extends InputPayMana {
msg.append(messagePrefix).append("\n");
}
if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DETAILED_SPELLDESC_IN_PROMPT)) {
// msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", ""));
if (saPaidFor.isSpell()) {
msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")).append("\n\n");
} else {

View File

@@ -126,7 +126,6 @@ public class InputProxy implements Observer {
public final boolean selectCard(final CardView cardView, final List<CardView> otherCardViewsToSelect, final ITriggerEvent triggerEvent) {
final Input inp = getInput();
//System.out.println("Selectcard " +cardView + " input: " +inp);
if (inp != null) {
final Card card = getCard(cardView);
if (card != null) {

View File

@@ -32,7 +32,7 @@ public class InputSelectEntitiesFromList<T extends GameEntity> extends InputSele
public InputSelectEntitiesFromList(final PlayerControllerHuman controller, final int min, final int max, final FCollectionView<T> validChoices0, final SpellAbility sa0) {
super(controller, Math.min(min, validChoices0.size()), Math.min(max, validChoices0.size()), sa0);
validChoices = validChoices0;
if (min > validChoices.size()) { // pfps does this really do anything useful??
if (min > validChoices.size()) { // pfps does this really do anything useful??
System.out.println(String.format("Trying to choose at least %d things from a list with only %d things!", min, validChoices.size()));
}
ArrayList<CardView> vCards = new ArrayList<>();

View File

@@ -8,7 +8,6 @@ import java.util.Map;
import java.util.Map.Entry;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import forge.game.GameEntity;
@@ -129,10 +128,10 @@ public final class InputSelectTargets extends InputSyncronizedBase {
"(Targeting ERROR)", "");
showMessage(message, sa.getView());
if (sa.isDividedAsYouChoose() && sa.getMinTargets() == 0 && sa.getTargets().size() == 0) {
if ((divisionValues != null && !divisionValues.isEmpty()) && sa.getMinTargets() == 0 && sa.getTargets().size() == 0) {
// extra logic for Divided with min targets = 0, should only work if num targets are 0 too
getController().getGui().updateButtons(getOwner(), true, true, false);
} else if (!sa.isMinTargetChosen() || sa.isDividedAsYouChoose()) {
} else if (!sa.isMinTargetChosen() || (divisionValues != null && !divisionValues.isEmpty())){
// If reached Minimum targets, enable OK button
if (mandatory && tgt.hasCandidates(sa, true)) {
// Player has to click on a target
@@ -280,7 +279,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
return false;
}
if (sa.isDividedAsYouChoose()) {
if ((divisionValues != null && !divisionValues.isEmpty())) {
Boolean val = onDividedAsYouChoose(card);
if (val != null) {
return val;
@@ -322,7 +321,7 @@ public final class InputSelectTargets extends InputSyncronizedBase {
return;
}
if (sa.isDividedAsYouChoose()) {
if ((divisionValues != null && !divisionValues.isEmpty())) {
Boolean val = onDividedAsYouChoose(player);
if (val != null) {
return;
@@ -332,57 +331,25 @@ public final class InputSelectTargets extends InputSyncronizedBase {
}
protected Boolean onDividedAsYouChoose(GameObject go) {
if (divisionValues != null) {
if (divisionValues.isEmpty()) {
return false;
}
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
}
else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
}
else if (sa.getApi() == ApiType.PutCounter) {
apiBasedMessage = "Select how many counters to distribute to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(go.toString());
final Integer chosen = getController().getGui().oneOrNone(sb.toString(), Lists.newArrayList(divisionValues));
if (chosen == null) {
return true; //still return true since there was a valid choice
}
divisionValues.remove(chosen);
sa.addDividedAllocation(go, chosen);
} else {
final int stillToDivide = sa.getStillToDivide();
int allocatedPortion = 0;
// allow allocation only if the max targets isn't reached and there are more candidates
if ((sa.getTargets().size() + 1 < sa.getMaxTargets()) && (tgt.getNumCandidates(sa, true) - 1 > 0) && stillToDivide > 1) {
final ImmutableList.Builder<Integer> choices = ImmutableList.builder();
for (int i = 1; i <= stillToDivide; i++) {
choices.add(Integer.valueOf(i));
}
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
} else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(go.toString());
final Integer chosen = getController().getGui().oneOrNone(sb.toString(), choices.build());
if (null == chosen) {
return true;
}
allocatedPortion = chosen;
} else { // otherwise assign the rest of the damage/protection
allocatedPortion = stillToDivide;
}
sa.addDividedAllocation(go, allocatedPortion);
String apiBasedMessage = "Distribute how much to ";
if (sa.getApi() == ApiType.DealDamage) {
apiBasedMessage = "Select how much damage to deal to ";
}
else if (sa.getApi() == ApiType.PreventDamage) {
apiBasedMessage = "Select how much damage to prevent to ";
}
else if (sa.getApi() == ApiType.PutCounter) {
apiBasedMessage = "Select how many counters to distribute to ";
}
final StringBuilder sb = new StringBuilder();
sb.append(apiBasedMessage);
sb.append(go.toString());
final Integer chosen = getController().getGui().oneOrNone(sb.toString(), Lists.newArrayList(divisionValues));
if (chosen == null) {
return true; //still return true since there was a valid choice
}
divisionValues.remove(chosen);
sa.addDividedAllocation(go, chosen);
return null;
}
@@ -419,7 +386,8 @@ public final class InputSelectTargets extends InputSyncronizedBase {
}
private boolean hasAllTargets() {
return sa.isMaxTargetChosen() || (sa.isDividedAsYouChoose() && sa.getStillToDivide() == 0);
return sa.isMaxTargetChosen() || (divisionValues != null && sa.getStillToDivide() == 0)
|| (sa.isDividedAsYouChoose() && sa.getTargets().size() == sa.getStillToDivide());
}
@Override

View File

@@ -207,7 +207,7 @@ public class NetGuiGame extends AbstractGuiGame {
}
@Override
public Map<GameEntityView, Integer> assignGenericAmount(final CardView effectSource, final Map<GameEntityView, Integer> targets, final int amount, final boolean atLeastOne, final String amountLabel) {
public Map<Object, Integer> assignGenericAmount(final CardView effectSource, final Map<Object, Integer> targets, final int amount, final boolean atLeastOne, final String amountLabel) {
return sendAndWait(ProtocolMethod.divideShield, effectSource, targets, amount, atLeastOne, amountLabel);
}

View File

@@ -69,20 +69,23 @@ public final class BoosterUtils {
};
private static final GameFormat.Collection formats = FModel.getFormats();
private static final Predicate<CardEdition> filterExt = formats.getExtended().editionLegalPredicate;
private static final Predicate<CardEdition> filterPioneer = formats.getPioneer().editionLegalPredicate;
private static final Predicate<CardEdition> filterModern= formats.getModern().editionLegalPredicate;
/** The filter t2booster. */
private static final Predicate<CardEdition> filterT2booster = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER,
private static final Predicate<CardEdition> filterStandard = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER,
formats.getStandard().editionLegalPredicate);
/** The filter ext but t2. */
private static final Predicate<CardEdition> filterExtButT2 = Predicates.and(
private static final Predicate<CardEdition> filterPioneerNotStandard = Predicates.and(
CardEdition.Predicates.CAN_MAKE_BOOSTER,
Predicates.and(filterExt, formats.getStandard().editionLegalPredicate));
Predicates.and(filterPioneer, Predicates.not(formats.getStandard().editionLegalPredicate)));
private static final Predicate<CardEdition> filterModernNotPioneer = Predicates.and(
CardEdition.Predicates.CAN_MAKE_BOOSTER,
Predicates.and(filterModern, Predicates.not(filterPioneer)));
/** The filter not ext. */
private static final Predicate<CardEdition> filterNotExt = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER,
Predicates.not(filterExt));
private static final Predicate<CardEdition> filterNotModern = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER,
Predicates.not(filterModern));
/**
* Gets the quest starter deck.
@@ -169,7 +172,19 @@ public final class BoosterUtils {
return generateRandomBoosterPacks(quantity, isLegalInQuestFormat(questController.getFormat()));
} else {
final int rollD100 = MyRandom.getRandom().nextInt(100);
return generateRandomBoosterPacks(quantity, rollD100 < 40 ? filterT2booster : (rollD100 < 75 ? filterExtButT2 : filterNotExt));
// 30% Standard, 20% Pioneer, pre-standard -> 20% Modern, pre-pioneer -> 30% Pre-modern
Predicate<CardEdition> rolledFilter;
if (rollD100 < 30) {
rolledFilter = filterStandard;
} else if (rollD100 < 50) {
rolledFilter = filterPioneerNotStandard;
} else if (rollD100 < 70) {
rolledFilter = filterModernNotPioneer;
} else {
rolledFilter = filterNotModern;
}
return generateRandomBoosterPacks(quantity, rolledFilter);
}
}

View File

@@ -5,6 +5,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
@@ -589,7 +590,15 @@ public class QuestWinLoseController {
final IUnOpenedProduct product = new UnOpenedProduct(getBoosterTemplate(), cards);
cardsWon = product.get();
} else {
final IUnOpenedProduct product = new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(chooseEd.getCode()));
final IUnOpenedProduct product;
List<String> boosterTypes = Lists.newArrayList(chooseEd.getAvailableBoosterTypes());
String setAffix = "";
String type = SGuiChoose.one("Which booster type do you choose?", boosterTypes);
if (!type.equals("Draft")) {
setAffix = type;
}
product = new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(chooseEd.getCode() + setAffix));
cardsWon = product.get();
}

View File

@@ -231,15 +231,10 @@ public class QuestWorld implements Comparable<QuestWorld>{
*/
@Override
public int compareTo(QuestWorld other) {
if (null == other) {
if (null == other)
return 1;
}
if (name == other.name) {
return 0;
}
if (null == name) {
return -1;
}
if (this.name == null)
return -1; // dummy, no format!
return name.compareTo(other.name);
}

View File

@@ -64,7 +64,7 @@ public final class GameFormatQuest extends GameFormat {
public GameFormatQuest(final GameFormat toCopy, boolean allowSetUnlocks) {
super(toCopy.getName(), toCopy.getEffectiveDate(), toCopy.getAllowedSetCodes(), toCopy.getBannedCardNames(), toCopy.getRestrictedCards(),
toCopy.isRestrictedLegendary(),toCopy.getAdditionalCards(), toCopy.getAllowedRarities(),
toCopy.getIndex(), FormatType.Custom, FormatSubType.Custom);
toCopy.getIndex(), FormatType.CUSTOM, FormatSubType.CUSTOM);
allowUnlocks = allowSetUnlocks;
}

View File

@@ -126,7 +126,7 @@ public class CardDetailUtil {
public static String getCurrentColors(final CardStateView c) {
ColorSet curColors = c.getColors();
String strCurColors = "";
String strCurColors = "";
if (curColors.hasWhite()) { strCurColors += "{W}"; }
if (curColors.hasBlue()) { strCurColors += "{U}"; }
@@ -140,7 +140,7 @@ public class CardDetailUtil {
return strCurColors;
}
public static DetailColors getRarityColor(final CardRarity rarity) {
switch (rarity) {
case Uncommon:
@@ -251,7 +251,7 @@ public class CardDetailUtil {
origIdent = origCard != null ? getCurrentColors(origCard.isFaceDown() ? CardView.get(origCard).getState(false) : CardView.get(origCard).getCurrentState()) : "";
} catch(Exception ex) {
System.err.println("Unexpected behavior: card " + card.getName() + "[" + card.getId() + "] tripped an exception when trying to process current card colors.");
}
}
isChanged = !curColors.equals(origIdent);
}
@@ -477,6 +477,15 @@ public class CardDetailUtil {
area.append(")");
}
// dungeon room
if (card.getCurrentRoom() != null && !card.getCurrentRoom().isEmpty()) {
if (area.length() != 0) {
area.append("\n");
}
area.append("(In room: ");
area.append(card.getCurrentRoom()).append(")");
}
// a card has something attached to it
if (card.hasCardAttachments()) {
if (area.length() != 0) {

View File

@@ -69,7 +69,8 @@ public interface IGuiGame {
void setPanelSelection(CardView hostCard);
SpellAbilityView getAbilityToPlay(CardView hostCard, List<SpellAbilityView> abilities, ITriggerEvent triggerEvent);
Map<CardView, Integer> assignCombatDamage(CardView attacker, List<CardView> blockers, int damage, GameEntityView defender, boolean overrideOrder);
Map<GameEntityView, Integer> assignGenericAmount(CardView effectSource, Map<GameEntityView, Integer> target, int amount, final boolean atLeastOne, final String amountLabel);
// The Object passed should be GameEntityView for most case. Can be Byte for "generate mana of any combination" effect
Map<Object, Integer> assignGenericAmount(CardView effectSource, Map<Object, Integer> target, int amount, final boolean atLeastOne, final String amountLabel);
void message(String message);
void message(String message, String title);

View File

@@ -59,6 +59,8 @@ public interface IDevModeCheats {
void planeswalkTo();
void askAI();
/**
* Implementation of {@link IDevModeCheats} that disallows cheating by
* performing no action whatsoever when any of its methods is called.
@@ -141,6 +143,9 @@ public interface IDevModeCheats {
@Override
public void removeCardsFromGame() {
}
@Override
public void askAI() {
}
};
}

View File

@@ -48,6 +48,8 @@ public final class ForgeConstants {
public static final String NET_DECKS_LIST_FILE = LISTS_DIR + "net-decks.txt";
public static final String NET_DECKS_COMMANDER_LIST_FILE = LISTS_DIR + "net-decks-commander.txt";
public static final String NET_DECKS_BRAWL_LIST_FILE = LISTS_DIR + "net-decks-brawl.txt";
public static final String NET_DECKS_OATHBREAKER_LIST_FILE = LISTS_DIR + "net-decks-oathbreaker.txt";
public static final String NET_DECKS_TINYLEADERS_LIST_FILE = LISTS_DIR + "net-decks-tinyleaders.txt";
public static final String BORDERLESS_CARD_LIST_FILE = LISTS_DIR + "borderlessCardList.txt";
public static final String SKINS_LIST_FILE = LISTS_DIR + "skinsList.txt";
public static final String CJK_FONTS_LIST_FILE = LISTS_DIR + "font-list.txt";

View File

@@ -166,7 +166,7 @@ public class MetaSet {
switch(type) {
case Full:
return new UnOpenedProduct(SealedProduct.Template.genericBooster);
return new UnOpenedProduct(SealedProduct.Template.genericDraftBooster);
case Booster:
return new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(data));
@@ -179,7 +179,7 @@ public class MetaSet {
case JoinedSet:
Predicate<PaperCard> predicate = IPaperCard.Predicates.printedInSets(data.split(" "));
return new UnOpenedProduct(SealedProduct.Template.genericBooster, predicate);
return new UnOpenedProduct(SealedProduct.Template.genericDraftBooster, predicate);
case Choose: return UnOpenedMeta.choose(data);
case Random: return UnOpenedMeta.random(data);

View File

@@ -1096,6 +1096,10 @@ public class HumanCostDecision extends CostDecisionMakerBase {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
if (c != null && c == 0) {
return PaymentDecision.number(0);
}
if (sameType) {
final CardCollection list2 = typeList;
typeList = CardLists.filter(typeList, new Predicate<Card>() {
@@ -1109,9 +1113,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
return false;
}
});
if (c == 0) {
return PaymentDecision.number(0);
}
final CardCollection tapped = new CardCollection();
while (c > 0) {
final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, typeList, ability);

View File

@@ -105,7 +105,6 @@ public class HumanPlay {
sa = AbilityUtils.addSpliceEffects(sa);
// System.out.println("Playing:" + sa.getDescription() + " of " + sa.getHostCard() + " new = " + newAbility);
final HumanPlaySpellAbility req = new HumanPlaySpellAbility(controller, sa);
if (!req.playAbility(true, false, false)) {
if (flippedToCast && !castFaceDown) {
@@ -674,7 +673,7 @@ public class HumanPlay {
final Card offering = ability.getSacrificedAsOffering();
offering.setUsedToPay(false);
if (!manaInputCancelled) {
game.getAction().sacrifice(offering, ability, table);
game.getAction().sacrifice(offering, ability, table, null);
}
ability.resetSacrificedAsOffering();
}
@@ -682,7 +681,7 @@ public class HumanPlay {
final Card emerge = ability.getSacrificedAsEmerge();
emerge.setUsedToPay(false);
if (!manaInputCancelled) {
game.getAction().sacrifice(emerge, ability, table);
game.getAction().sacrifice(emerge, ability, table, null);
}
ability.resetSacrificedAsEmerge();
}
@@ -786,7 +785,7 @@ public class HumanPlay {
if (ability.getSacrificedAsOffering() != null) {
System.out.println("Finishing up Offering");
offering.setUsedToPay(false);
activator.getGame().getAction().sacrifice(offering, ability, null);
activator.getGame().getAction().sacrifice(offering, ability, null, null);
ability.resetSacrificedAsOffering();
}
}
@@ -797,7 +796,7 @@ public class HumanPlay {
if (ability.getSacrificedAsEmerge() != null) {
System.out.println("Finishing up Emerge");
emerge.setUsedToPay(false);
activator.getGame().getAction().sacrifice(emerge, ability, null);
activator.getGame().getAction().sacrifice(emerge, ability, null, null);
ability.resetSacrificedAsEmerge();
}
}

View File

@@ -12,6 +12,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -36,6 +38,7 @@ import com.google.common.collect.Multimap;
import forge.LobbyPlayer;
import forge.StaticData;
import forge.ai.GameState;
import forge.ai.PlayerControllerAi;
import forge.card.CardDb;
import forge.card.CardStateName;
import forge.card.CardType;
@@ -393,11 +396,11 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Map<GameEntity, Integer> divideShield(Card effectSource, Map<GameEntity, Integer> affected, int shieldAmount) {
final CardView vSource = CardView.get(effectSource);
final Map<GameEntityView, Integer> vAffected = new HashMap<>(affected.size());
final Map<Object, Integer> vAffected = new HashMap<>(affected.size());
for (Map.Entry<GameEntity, Integer> e : affected.entrySet()) {
vAffected.put(GameEntityView.get(e.getKey()), e.getValue());
}
final Map<GameEntityView, Integer> vResult = getGui().assignGenericAmount(vSource, vAffected, shieldAmount, false,
final Map<Object, Integer> vResult = getGui().assignGenericAmount(vSource, vAffected, shieldAmount, false,
localizer.getMessage("lblShield"));
Map<GameEntity, Integer> result = new HashMap<>(vResult.size());
for (Map.Entry<GameEntity, Integer> e : affected.entrySet()) {
@@ -408,6 +411,28 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return result;
}
@Override
public Map<Byte, Integer> specifyManaCombo(SpellAbility sa, ColorSet colorSet, int manaAmount, boolean different) {
final CardView vSource = CardView.get(sa.getHostCard());
final Map<Object, Integer> vAffected = new LinkedHashMap<>(manaAmount);
Integer maxAmount = different ? 1 : manaAmount;
Iterator<Byte> it = colorSet.iterator();
while (it.hasNext()) {
vAffected.put(it.next(), maxAmount);
}
final Map<Object, Integer> vResult = getGui().assignGenericAmount(vSource, vAffected, manaAmount, false,
localizer.getMessage("lblMana").toLowerCase());
Map<Byte, Integer> result = new HashMap<>(vResult.size());
it = colorSet.iterator();
while (it.hasNext()) {
Byte color = it.next();
if (vResult.containsKey(color)) {
result.put(color, vResult.get(color));
}
}
return result;
}
@Override
public Integer announceRequirements(final SpellAbility ability, final String announce) {
int max = Integer.MAX_VALUE;
@@ -487,7 +512,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
private boolean useSelectCardsInput(final FCollectionView<? extends GameEntity> sourceList) {
// can't use InputSelect from GUI thread (e.g., DevMode Tutor)
if ( FThreads.isGuiThread() ) { return false; }
if (FThreads.isGuiThread()) { return false; }
// if UI_SELECT_FROM_CARD_DISPLAYS not set use InputSelect only for battlefield and player hand
// if UI_SELECT_FROM_CARD_DISPLAYS set and using desktop GUI use InputSelect for any zone that can be shown
@@ -576,8 +601,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
tempShow(delayedReveal.getCards());
}
GameEntityViewMap<T, GameEntityView> gameCacheChoose = GameEntityView.getMap(optionList);
if (useSelectCardsInput(optionList)) {
final InputSelectEntitiesFromList<T> input = new InputSelectEntitiesFromList<>(this, isOptional ? 0 : 1, 1,
optionList, sa);
@@ -588,6 +611,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
return Iterables.getFirst(input.getSelected(), null);
}
GameEntityViewMap<T, GameEntityView> gameCacheChoose = GameEntityView.getMap(optionList);
final GameEntityView result = getGui().chooseSingleEntityForEffect(title,
gameCacheChoose.getTrackableKeys(), delayedReveal, isOptional);
endTempShowCards();
@@ -601,8 +625,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public <T extends GameEntity> List<T> chooseEntitiesForEffect(final FCollectionView<T> optionList, final int min, final int max,
final DelayedReveal delayedReveal, final SpellAbility sa, final String title, final Player targetedPlayer, Map<String, Object> params) {
// useful details for debugging problems with the mass select logic
Sentry.getContext().addExtra("Card", sa.getCardView().toString());
Sentry.getContext().addExtra("SpellAbility", sa.toString());
@@ -630,6 +652,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
endTempShowCards();
return (List<T>) input.getSelected();
}
GameEntityViewMap<T, GameEntityView> gameCacheEntity = GameEntityView.getMap(optionList);
final List<GameEntityView> views = getGui().chooseEntitiesForEffect(title, gameCacheEntity.getTrackableKeys(), min, max, delayedReveal);
endTempShowCards();
@@ -675,8 +698,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
Map<SpellAbilityView, SpellAbility> spellViewCache = SpellAbilityView.getMap(spells);
Object choice = getGui().one(title, Lists.newArrayList(spellViewCache.keySet()));
// Human is supposed to read the message and understand from it what to
// choose
// Human is supposed to read the message and understand from it what to choose
return spellViewCache.get(choice);
}
@@ -923,8 +945,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
CardCollection toTop = null;
tempShowCards(topN);
if ( FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) &&
(!GuiBase.getInterface().isLibgdxPort()) && (!GuiBase.isNetworkplay())) { //prevent crash for desktop vs mobile port it will crash the netplay since mobile doesnt have manipulatecardlist, send the alternate below
if (FModel.getPreferences().getPrefBoolean(FPref.UI_SELECT_FROM_CARD_DISPLAYS) &&
(!GuiBase.getInterface().isLibgdxPort()) && (!GuiBase.isNetworkplay())) { //prevent crash for desktop vs mobile port it will crash the netplay since mobile doesnt have manipulatecardlist, send the alternate below
CardCollectionView cardList = player.getCardsIn(ZoneType.Library);
ImmutablePair<CardCollection, CardCollection> result =
arrangeForMove(localizer.getMessage("lblMoveCardstoToporBbottomofLibrary"), cardList, topN, true, true);
@@ -1541,8 +1563,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public List<SpellAbility> chooseSaToActivateFromOpeningHand(final List<SpellAbility> usableFromOpeningHand) {
final CardCollection srcCards = new CardCollection();
for (final SpellAbility sa : usableFromOpeningHand) {
srcCards.add(sa.getHostCard());
@@ -1950,7 +1970,44 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
checkSA = checkSA.getSubAbility();
}
return select.chooseTargets(null, null, null, false, canFilterMustTarget);
boolean result = select.chooseTargets(null, null, null, false, canFilterMustTarget);
// assign divided as you choose values
if (result && currentAbility.isDividedAsYouChoose() && currentAbility.getStillToDivide() > 0) {
int amount = currentAbility.getStillToDivide();
final List<GameEntity> targets = currentAbility.getTargets().getTargetEntities();
if (targets.size() == 1) {
currentAbility.addDividedAllocation(targets.get(0), amount);
} else if (targets.size() == amount) {
for (GameEntity e : targets) {
currentAbility.addDividedAllocation(e, 1);
}
} else if (targets.size() > amount) {
return false;
} else {
String label = "lblDamage";
if (currentAbility.getApi() == ApiType.PreventDamage) {
label = "lblShield";
} else if (currentAbility.getApi() == ApiType.PutCounter) {
label = "lblCounters";
}
label = localizer.getMessage(label).toLowerCase();
final CardView vSource = CardView.get(currentAbility.getHostCard());
final Map<Object, Integer> vTargets = new HashMap<>(targets.size());
for (GameEntity e : targets) {
vTargets.put(GameEntityView.get(e), amount);
}
final Map<Object, Integer> vResult = getGui().assignGenericAmount(vSource, vTargets, amount, true, label);
for (GameEntity e : targets) {
currentAbility.addDividedAllocation(e, vResult.get(GameEntityView.get(e)));
}
if (currentAbility.getStillToDivide() > 0) {
return false;
}
}
}
return result;
}
@Override
@@ -2431,7 +2488,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (subtract) {
card.subtractCounter(counter, count);
} else {
card.addCounter(counter, count, card.getController(), false, null);
card.addCounter(counter, count, card.getController(), null, false, null);
}
}
@@ -2495,7 +2552,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
*/
@Override
public void setPlayerLife() {
GameEntityViewMap<Player, PlayerView> gameCachePlayer = GameEntityView.getMap(getGame().getPlayers());
final PlayerView pv = getGui().oneOrNone(localizer.getMessage("lblSetLifeforWhichPlayer"), gameCachePlayer.getTrackableKeys());
@@ -2942,6 +2998,18 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
}
});
}
public void askAI() {
PlayerControllerAi ai = new PlayerControllerAi(player.getGame(), player, player.getOriginalLobbyPlayer());
player.runWithController(new Runnable() {
@Override
public void run() {
List<SpellAbility> sas = ai.chooseSpellAbilityToPlay();
SpellAbility chosen = sas == null ? null : sas.get(0);
getGui().message(chosen == null ? "AI doesn't want to play anything right now" : chosen.getHostCard().toString(), "AI Play Suggestion");
}
}, ai);
}
}
private IMacroSystem macros;

View File

@@ -73,7 +73,7 @@ public abstract class ImageFetcher {
System.err.println("Paper card not found for: " + imageKey);
return;
}
final boolean backFace = ImageUtil.hasBackFacePicture(paperCard);
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
final String filename = ImageUtil.getImageKey(paperCard, backFace, true);
destFile = new File(ForgeConstants.CACHE_CARD_PICS_DIR, filename + ".jpg");