mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 20:28:00 +00:00
Merge remote-tracking branch 'upstream/master' into collector-number-in-card-list-and-card-db-refactoring
This commit is contained in:
@@ -14,9 +14,9 @@ import forge.model.FModel;
|
||||
public class CardThemedDeckGenerator extends DeckProxy implements Comparable<CardThemedDeckGenerator> {
|
||||
public static List<DeckProxy> getMatrixDecks(GameFormat format, boolean isForAi){
|
||||
final List<DeckProxy> decks = new ArrayList<>();
|
||||
for(String card: CardArchetypeLDAGenerator.ldaPools.get(format.getName()).keySet()) {
|
||||
for (String card: CardArchetypeLDAGenerator.ldaPools.get(format.getName()).keySet()) {
|
||||
//exclude non AI playables as keycards for AI decks
|
||||
if(isForAi&&FModel.getMagicDb().getCommonCards().getUniqueByName(card).getRules().getAiHints().getRemAIDecks()){
|
||||
if (isForAi&&FModel.getMagicDb().getCommonCards().getUniqueByName(card).getRules().getAiHints().getRemAIDecks()) {
|
||||
continue;
|
||||
}
|
||||
decks.add(new CardThemedDeckGenerator(card, format, isForAi));
|
||||
@@ -42,7 +42,6 @@ public class CardThemedDeckGenerator extends DeckProxy implements Comparable<Car
|
||||
return CardEdition.UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
|
||||
@@ -189,17 +189,13 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
|
||||
// to try and avoid adding purely random cards.
|
||||
addThirdColorCards(numSpellsNeeded - deckList.size());
|
||||
|
||||
// 8. Check for DeckNeeds cards.
|
||||
checkRemRandomDeckCards();
|
||||
|
||||
// 9. If there are still less than 22 non-land cards add off-color
|
||||
// cards. This should be avoided.
|
||||
addRandomCards(numSpellsNeeded - deckList.size());
|
||||
|
||||
// 10. Add non-basic lands that were drafted.
|
||||
// 8. Add non-basic lands that were drafted.
|
||||
addNonBasicLands();
|
||||
|
||||
// 11. Fill up with basic lands.
|
||||
// 9. Check for DeckNeeds cards.
|
||||
checkRemRandomDeckCards();
|
||||
|
||||
// 10. Fill up with basic lands.
|
||||
final int[] clrCnts = calculateLandNeeds();
|
||||
if (landsNeeded > 0) {
|
||||
addLands(clrCnts, landSetCode);
|
||||
@@ -352,33 +348,40 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
|
||||
|
||||
// total of all ClrCnts
|
||||
int totalColor = 0;
|
||||
int numColors = 0;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
totalColor += clrCnts[i];
|
||||
if (clrCnts[i] > 0) {
|
||||
numColors++;
|
||||
}
|
||||
}
|
||||
if (totalColor == 0) {
|
||||
// TODO: Technically this can happen in a colorless deck.
|
||||
throw new RuntimeException("Add Lands to empty deck list!");
|
||||
}
|
||||
|
||||
// do not update landsNeeded until after the loop, because the
|
||||
// calculation involves landsNeeded
|
||||
|
||||
// First, add 2 land of each required color. This prevents the AI from including
|
||||
// a splash card with no viable way to cast it.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (clrCnts[i] > 0) {
|
||||
// calculate number of lands for each color
|
||||
float p = (float) clrCnts[i] / (float) totalColor;
|
||||
if (numColors == 2) {
|
||||
// In the normal two-color case, constrain to within 40% and 60% so that the AI
|
||||
// doesn't put too few lands of the lesser color, risking getting screwed on that color.
|
||||
// Don't do this for the odd case where a third color had to be added to the deck.
|
||||
p = Math.min(Math.max(p, 0.4f), 0.6f);
|
||||
int nLand = 2;
|
||||
System.out.printf("Basics[%s]: %d cards%n", MagicColor.Constant.BASIC_LANDS.get(i), nLand);
|
||||
for (int j = 0; j < nLand; j++) {
|
||||
deckList.add(getBasicLand(i, landSetCode));
|
||||
}
|
||||
int nLand = Math.round(landsNeeded * p); // desired truncation to int
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int slotsRemaining = 40-deckList.size(); // How many to still distribute
|
||||
if (clrCnts[i] > 0) {
|
||||
// calculate proportion of mana symbols for each remaining color
|
||||
float p = (float) clrCnts[i] / (float) totalColor;
|
||||
|
||||
// Rounding prefers WUBRG order, as a side effect.
|
||||
int nLand = Math.round(slotsRemaining * p); // Round up/down
|
||||
|
||||
if (logToConsole) {
|
||||
System.out.printf("Basics[%s]: %d/%d = %f%% = %d cards%n", MagicColor.Constant.BASIC_LANDS.get(i), clrCnts[i], totalColor, 100*p, nLand);
|
||||
}
|
||||
|
||||
totalColor -= clrCnts[i];
|
||||
|
||||
// if appropriate snow-covered lands are available, add them
|
||||
for (final PaperCard cp : basicLands) {
|
||||
@@ -394,14 +397,6 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
|
||||
}
|
||||
}
|
||||
|
||||
// A common problem at this point is that p in the above loop was exactly 1/2,
|
||||
// and nLand rounded up for both colors, so that one too many lands was added.
|
||||
// So if the deck size is > 40, remove the last land added.
|
||||
// Otherwise, the fixDeckSize() method would remove random cards.
|
||||
while (deckList.size() > 40) {
|
||||
deckList.remove(deckList.size() - 1);
|
||||
}
|
||||
|
||||
deckList.addAll(snowLands);
|
||||
aiPlayables.removeAll(snowLands);
|
||||
}
|
||||
@@ -505,7 +500,7 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
|
||||
|
||||
hasColor = Predicates.or(new DeckGeneratorBase.MatchColorIdentity(colors),
|
||||
DeckGeneratorBase.COLORLESS_CARDS);
|
||||
final Iterable<PaperCard> threeColorList = Iterables.filter(aiPlayables,
|
||||
final Iterable<PaperCard> threeColorList = Iterables.filter(rankedOthers,
|
||||
Predicates.compose(hasColor, PaperCard.FN_GET_RULES));
|
||||
for (final PaperCard card : threeColorList) {
|
||||
if (num > 0) {
|
||||
@@ -611,6 +606,8 @@ public class LimitedDeckBuilder extends DeckGeneratorBase {
|
||||
availableList.add(card);
|
||||
if (card.getRules().getType().isCreature()) {
|
||||
numCreatures++;
|
||||
} else if (card.getRules().getType().isLand()) {
|
||||
// Do nothing, it will be replaced with basics later.
|
||||
} else {
|
||||
numOthers++;
|
||||
}
|
||||
|
||||
@@ -153,8 +153,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
setCurrentPlayer(Iterables.getFirst(gameControllers.keySet(), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
gameControllers.put(player, gameController);
|
||||
}
|
||||
}
|
||||
@@ -270,7 +269,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
|
||||
private final Set<CardView> selectableCards = Sets.newHashSet();
|
||||
public void setSelectables(final Iterable<CardView> cards) {
|
||||
for ( CardView cv : cards ) { selectableCards.add(cv); }
|
||||
for (CardView cv : cards) { selectableCards.add(cv); }
|
||||
}
|
||||
public void clearSelectables() {
|
||||
selectableCards.clear();
|
||||
@@ -285,12 +284,12 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
public void setgamePause(boolean pause) { gamePause = pause; }
|
||||
public void pauseMatch() {
|
||||
IGameController controller = spectator;
|
||||
if(controller != null && !isGamePaused())
|
||||
if (controller != null && !isGamePaused())
|
||||
controller.selectButtonOk();
|
||||
}
|
||||
public void resumeMatch() {
|
||||
IGameController controller = spectator;
|
||||
if(controller != null && isGamePaused())
|
||||
if (controller != null && isGamePaused())
|
||||
controller.selectButtonOk();
|
||||
}
|
||||
|
||||
@@ -315,12 +314,10 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
// Concede each player on this Gui (except mind-controlled players)
|
||||
c.concede();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return !ignoreConcedeChain;
|
||||
}
|
||||
if (gameView.isGameOver()) {
|
||||
|
||||
@@ -392,8 +392,8 @@ public final class InputSelectTargets extends InputSyncronizedBase {
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getController().getGui().clearSelectables();
|
||||
super.onStop();
|
||||
getController().getGui().clearSelectables();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ public class Puzzle extends GameState implements InventoryItem, Comparable<Puzzl
|
||||
goalCard.setOwner(human);
|
||||
goalCard.setImageKey("t:puzzle");
|
||||
goalCard.setName("Puzzle Goal");
|
||||
goalCard.addType("Effect");
|
||||
goalCard.setImmutable(true);
|
||||
goalCard.setOracleText(getGoalDescription());
|
||||
|
||||
int turnCorr = 0;
|
||||
|
||||
@@ -200,8 +200,7 @@ public class CardDetailUtil {
|
||||
if (ptText.length() > 0) {
|
||||
ptText.insert(0, "P/T: ");
|
||||
ptText.append(" - ").append("Loy: ");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ptText.append("Loyalty: ");
|
||||
}
|
||||
|
||||
@@ -221,7 +220,7 @@ public class CardDetailUtil {
|
||||
String curColors = "";
|
||||
|
||||
// do not show current colors for temp effect cards, emblems and the like
|
||||
if (state.getType().isEmblem() || state.getType().hasSubtype("Effect")) {
|
||||
if (state.getCard().isImmutable()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -275,16 +274,14 @@ public class CardDetailUtil {
|
||||
|
||||
// Token
|
||||
if (card.isToken()) {
|
||||
if(card.getCurrentState().getType().hasSubtype("Effect"))
|
||||
area.append("Effect");
|
||||
else if(card.getCurrentState().getType().isEmblem())
|
||||
area.append("Emblem");
|
||||
else
|
||||
area.append("Token");
|
||||
area.append("Token");
|
||||
} else if (card.isTokenCard()) {
|
||||
area.append("Token card");
|
||||
} else if (card.isEmblem()) {
|
||||
area.append("Emblem");
|
||||
} else if (card.isImmutable()) {
|
||||
area.append("Effect");
|
||||
}
|
||||
|
||||
// card text
|
||||
if (area.length() != 0) {
|
||||
area.append("\n");
|
||||
@@ -299,7 +296,6 @@ public class CardDetailUtil {
|
||||
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null) :
|
||||
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(card.getLeftSplitState().getName(), card.getRightSplitState().getName()) : null );
|
||||
|
||||
|
||||
// LEVEL [0-9]+-[0-9]+
|
||||
// LEVEL [0-9]+\+
|
||||
|
||||
@@ -575,7 +571,7 @@ public class CardDetailUtil {
|
||||
if (area.length() != 0) {
|
||||
area.append("\n");
|
||||
}
|
||||
area.append("Until leaves the Battlefield: ").append(card.getUntilLeavesBattlefield());
|
||||
area.append("Exiled until this leaves the battlefield: ").append(card.getUntilLeavesBattlefield());
|
||||
}
|
||||
|
||||
// must block
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class CardScriptInfo {
|
||||
final String filename = name.toLowerCase().replaceAll("[^-a-z0-9\\s]","").replaceAll("[-\\s]","_").replaceAll("__","_") + ".txt";
|
||||
String[] folders = { String.valueOf(filename.charAt(0)), "upcoming"};
|
||||
|
||||
for(String folder : folders){
|
||||
for (String folder : folders) {
|
||||
final File file = new File(ForgeConstants.CARD_DATA_DIR + folder + File.separator + filename);
|
||||
if (file.exists()) {
|
||||
script = new CardScriptInfo(FileUtil.readFileToString(file), file);
|
||||
|
||||
@@ -104,7 +104,7 @@ public final class GamePlayerUtil {
|
||||
final String oldPlayerName = FModel.getPreferences().getPref(FPref.PLAYER_NAME);
|
||||
|
||||
String newPlayerName;
|
||||
try{
|
||||
try {
|
||||
if (StringUtils.isBlank(oldPlayerName)) {
|
||||
newPlayerName = getVerifiedPlayerName(getPlayerNameUsingFirstTimePrompt(), oldPlayerName);
|
||||
} else {
|
||||
|
||||
@@ -277,8 +277,6 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return exileFromSame(cost, list, c, payableZone);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Inputs
|
||||
|
||||
// Exile<Num/Type{/TypeDescription}>
|
||||
@@ -482,6 +480,22 @@ public class HumanCostDecision extends CostDecisionMakerBase {
|
||||
return PaymentDecision.number(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentDecision visit(final CostRollDice cost) {
|
||||
final String amount = cost.getAmount();
|
||||
Integer c = cost.convertAmount();
|
||||
|
||||
if (c == null) {
|
||||
c = AbilityUtils.calculateAmount(source, amount, ability);
|
||||
}
|
||||
|
||||
if (!player.getController().confirmPayment(cost, Localizer.getInstance().getMessage("lblDoYouWantRollNDiceAction", String.valueOf(c), "d" + cost.getType()), ability)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return PaymentDecision.number(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentDecision visit(final CostGainControl cost) {
|
||||
final String amount = cost.getAmount();
|
||||
|
||||
@@ -349,6 +349,18 @@ public class HumanPlay {
|
||||
else
|
||||
part.payAsDecided(p, pd, sourceAbility);
|
||||
}
|
||||
else if (part instanceof CostRollDice) {
|
||||
if (!part.canPay(sourceAbility, p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PaymentDecision pd = part.accept(hcd);
|
||||
|
||||
if (pd == null)
|
||||
return false;
|
||||
else
|
||||
part.payAsDecided(p, pd, sourceAbility);
|
||||
}
|
||||
else if (part instanceof CostDamage) {
|
||||
if (!part.canPay(sourceAbility, p)) {
|
||||
return false;
|
||||
|
||||
@@ -334,7 +334,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
String errMsg;
|
||||
if (newMain.size() < deckMinSize) {
|
||||
errMsg = TextUtil.concatNoSpace(localizer.getMessage("lblTooFewCardsMainDeck", String.valueOf(deckMinSize)));
|
||||
|
||||
} else {
|
||||
errMsg = TextUtil.concatNoSpace(localizer.getMessage("lblTooManyCardsSideboard", String.valueOf(sbMax)));
|
||||
}
|
||||
@@ -1324,7 +1323,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
}
|
||||
if (sa.hasParam("TokenScript")) {
|
||||
sa.setActivatingPlayer(player);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, null);
|
||||
for (String type : protoType.getType().getCreatureTypes()) {
|
||||
Integer count = typesInDeck.get(type);
|
||||
if (count == null) {
|
||||
@@ -1340,7 +1339,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
|
||||
if (sa != null) {
|
||||
if (sa.hasParam("TokenScript")) {
|
||||
sa.setActivatingPlayer(player);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa);
|
||||
Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, null);
|
||||
for (String type : protoType.getType().getCreatureTypes()) {
|
||||
Integer count = typesInDeck.get(type);
|
||||
if (count == null) {
|
||||
|
||||
Reference in New Issue
Block a user