diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java index 321776041..28370b662 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/DeckRequestHandler.java @@ -140,7 +140,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri int fpCount = 0; int shadowCount = 0; - for (String card : deck.getAdventureCards()) { + for (String card : deck.getDrawDeckCards()) { Side side = _library.getLotroCardBlueprint(card).getSide(); if (side == Side.SHADOW) shadowCount++; @@ -369,7 +369,7 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri result.append("Ring: " + generateCardTooltip(_library.getLotroCardBlueprint(ring), ring) + "
"); DefaultCardCollection deckCards = new DefaultCardCollection(); - for (String card : deck.getAdventureCards()) + for (String card : deck.getDrawDeckCards()) deckCards.addItem(_library.getBaseBlueprintId(card), 1); for (String site : deck.getSites()) deckCards.addItem(_library.getBaseBlueprintId(site), 1); @@ -577,13 +577,19 @@ public class DeckRequestHandler extends LotroServerRequestHandler implements Uri deckElem.appendChild(ring); } + if (deck.getMap() != null) { + Element map = doc.createElement("map"); + map.setAttribute("blueprintId", deck.getMap()); + deckElem.appendChild(map); + } + for (CardItem cardItem : _sortAndFilterCards.process("sort:siteNumber,twilight", createCardItems(deck.getSites()), _library, _formatLibrary)) { Element site = doc.createElement("site"); site.setAttribute("blueprintId", cardItem.getBlueprintId()); deckElem.appendChild(site); } - for (CardItem cardItem : _sortAndFilterCards.process("sort:cardType,culture,name", createCardItems(deck.getAdventureCards()), _library, _formatLibrary)) { + for (CardItem cardItem : _sortAndFilterCards.process("sort:cardType,culture,name", createCardItems(deck.getDrawDeckCards()), _library, _formatLibrary)) { Element card = doc.createElement("card"); String side; try { diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/deckBuild.html b/gemp-lotr/gemp-lotr-async/src/main/web/deckBuild.html index c32beb048..006a32c21 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/deckBuild.html +++ b/gemp-lotr/gemp-lotr-async/src/main/web/deckBuild.html @@ -127,7 +127,7 @@ Map
(Click here to select your Map.) -

(Maps are now required for PC-Movie decks. They determine what site path you will use.) +

See here for details.
diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/PC_Cards.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/PC_Cards.js index 231c89f26..1e43b0632 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/PC_Cards.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/PC_Cards.js @@ -623,8 +623,12 @@ var PCCards = { //Aragorn,Elessar Telcontar FA '10_127' : 'https://i.lotrtcgpc.net/promos/LOTR-EN10U025.0_card.jpg', //Arwen, Queen of Elves and Men FA - '10_128' : 'https://i.lotrtcgpc.net/promos/LOTR-EN10U006.0_card.jpg' + '10_128' : 'https://i.lotrtcgpc.net/promos/LOTR-EN10U006.0_card.jpg', + //Maps + '100_2' : 'https://i.lotrtcgpc.net/sets/vset0/LOTR-ENV0S002.0_card.jpg', + '100_3' : 'https://i.lotrtcgpc.net/sets/vset0/LOTR-ENV0S003.0_card.jpg', + '100_4' : 'https://i.lotrtcgpc.net/sets/vset0/LOTR-ENV0S004.0_card.jpg' } diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js index 790c28f02..16f1ee1aa 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-022/deckBuildingUi.js @@ -842,6 +842,15 @@ var GempLotrDeckBuildingUI = Class.extend({ cards.push($(this).data("card").blueprintId); }); result += cards; + + let formatCode = this.formatSelect.val(); + if(formatCode == "pc_movie" || formatCode == "test_pc_movie") { + result += "|"; + var map = $(".card", this.mapDiv); + if (map.length > 0) + result += map.data("card").blueprintId; + } + return result; }, @@ -1075,6 +1084,10 @@ var GempLotrDeckBuildingUI = Class.extend({ if (ring.length > 0) this.addCardToContainer(ring[0].getAttribute("blueprintId"), "deck", this.ringDiv, false).addClass("cardInDeck"); + var map = root.getElementsByTagName("map"); + if (map.length > 0) + this.addCardToContainer(map[0].getAttribute("blueprintId"), "deck", this.mapDiv, false).addClass("cardInDeck"); + var sites = root.getElementsByTagName("site"); for (var i = 0; i < sites.length; i++) this.addCardToContainer(sites[i].getAttribute("blueprintId"), "deck", this.siteDiv, false).addClass("cardInDeck"); @@ -1158,7 +1171,7 @@ var GempLotrDeckBuildingUI = Class.extend({ this.mapDiv.css({ display:"block", position:"absolute", left:padding, top:manageHeight + 2 * padding+ rowHeight, width:Math.floor((sitesWidth - padding) / 2), height:rowHeight }); this.mapGroup.setBounds(0, 0, Math.floor((sitesWidth - padding) / 2), rowHeight); - this.siteDiv.css({ position:"absolute", left:padding, top:manageHeight + 3 * padding + 2 * rowHeight, width:sitesWidth, height:deckHeight - rowHeight - 2 * padding}); + this.siteDiv.css({ position:"absolute", left:padding, top:manageHeight + 3 * padding + 2 * rowHeight, width:sitesWidth, height:deckHeight - 2*rowHeight - 2 * padding}); this.siteGroup.setBounds(0, 0, sitesWidth, deckHeight - 2*rowHeight - 2 * padding); } else { diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV00/V0-maps.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV00/V0-maps.hjson new file mode 100644 index 000000000..8fc9a7b97 --- /dev/null +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/cards/unofficial/pc/setV00/V0-maps.hjson @@ -0,0 +1,122 @@ +{ + 100_2: { + cardInfo: { + imagePath: sets/LOTR-ENV0S002.0.jpg + javaClass: false + version: 0 + collInfo: V0 2 + rarity: X + setNum: V0 + cardNum: 2 + style: Standard + } + title: Path of the Fellowship + unique: false + type: Map + twilight: 0 + effects: [ + { + type: DeckBuildingRestriction + pile: sites + #We do it this way instead of checking for fellowship + # so that the error message shows all sites that don't + # match, instead of listing all the ones that do and + # making the user figure out which one isn't listed. + filter: or(siteblock(towers),siteblock(king),siteblock(shadows)) + max: 0 + text: Adventure Deck must only contain sites from the Fellowship block path. + } + ] + gametext: Before the game begins, play this to your support area. Your adventure deck must only contain cards from the Fellowship site path. + lore: "" + promotext: "" + alts: { + promos: { + } + errata: { + } + } + } + + 100_3: { + cardInfo: { + imagePath: sets/LOTR-ENV0S003.0.jpg + javaClass: false + version: 0 + collInfo: V0 3 + rarity: X + setNum: V0 + cardNum: 3 + style: Standard + } + title: Road to the Towers + unique: false + type: Map + twilight: 0 + effects: [ + { + type: DeckBuildingRestriction + pile: sites + #We do it this way instead of checking for fellowship + # so that the error message shows all sites that don't + # match, instead of listing all the ones that do and + # making the user figure out which one isn't listed. + filter: or(siteblock(fellowship),siteblock(king),siteblock(shadows)) + max: 0 + text: Adventure deck must only contain sites from the Towers block site path. + } + ] + gametext: Before the game begins, play this to your support area. Your adventure deck must only contain cards from the Towers site path. + lore: "" + promotext: "" + alts: { + promos: { + } + errata: { + } + } + } + + 100_4: { + cardInfo: { + imagePath: sets/LOTR-ENV0S004.0.jpg + javaClass: false + //parentId: 1_319 + //One of: Variant, Errata, Reprint + //parentType: Variant + //parentPath: alts/promo + version: 0 + collInfo: V0 4 + rarity: X + setNum: V0 + cardNum: 4 + style: Standard + } + title: Journey of the King + unique: false + type: Map + twilight: 0 + effects: [ + { + type: DeckBuildingRestriction + pile: sites + #We do it this way instead of checking for fellowship + # so that the error message shows all sites that don't + # match, instead of listing all the ones that do and + # making the user figure out which one isn't listed. + filter: or(siteblock(fellowship),siteblock(towers),siteblock(shadows)) + max: 0 + text: Adventure Deck must only contain sites from the King block site path. + } + ] + gametext: Before the game begins, play this to your support area. Your adventure deck must only contain cards from the King site path. + lore: "" + promotext: "" + alts: { + promos: { + } + errata: { + } + } + } +} \ No newline at end of file diff --git a/gemp-lotr/gemp-lotr-cards/src/main/resources/lotrFormats.hjson b/gemp-lotr/gemp-lotr-cards/src/main/resources/lotrFormats.hjson index 1240d1b19..001ca5de2 100644 --- a/gemp-lotr/gemp-lotr-cards/src/main/resources/lotrFormats.hjson +++ b/gemp-lotr/gemp-lotr-cards/src/main/resources/lotrFormats.hjson @@ -53,11 +53,15 @@ name: Movie Block (PC) code: pc_movie order: 4 - sites: KING + sites: MULTIPATH + usesMaps: true winAtEndOfRegroup: true discardPileIsPublic: true set: [ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 101 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101 + ] + banned: [ + "100_1" ] erratasets: [ 51,52,53,54,55,56,57,58,59,60 @@ -595,6 +599,7 @@ sites: MULTIPATH winAtEndOfRegroup: true discardPileIsPublic: true + usesMaps: true hall: true playtest: true set: [ diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/CardType.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/CardType.java index 7579e4b7e..a9ca85e3f 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/CardType.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/CardType.java @@ -1,5 +1,18 @@ package com.gempukku.lotro.common; public enum CardType implements Filterable { - THE_ONE_RING, SITE, COMPANION, ALLY, MINION, POSSESSION, ARTIFACT, EVENT, CONDITION, FOLLOWER, ADVENTURE + THE_ONE_RING, + SITE, + //Characters + COMPANION, ALLY, MINION, + //Items + POSSESSION, ARTIFACT, + EVENT, + CONDITION, + FOLLOWER, + //Unused + ADVENTURE, + + //Player's Council card types + MAP } diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/JSONDefs.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/JSONDefs.java index 3ff56d786..7829d1d68 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/JSONDefs.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/JSONDefs.java @@ -48,6 +48,7 @@ public class JSONDefs { public int minimumDeckSize = 60; public int maximumSameName = 4; public boolean mulliganRule = true; + public boolean usesMaps = false; public ArrayList set; public ArrayList banned = new ArrayList<>(); public ArrayList restricted = new ArrayList<>(); diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PileType.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PileType.java new file mode 100644 index 000000000..e992afd00 --- /dev/null +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/PileType.java @@ -0,0 +1,30 @@ +package com.gempukku.lotro.common; + + +/** + * Represents the different kinds of deck piles that the player comes to + * the table with. + */ +public enum PileType implements Filterable { + FREE_PEOPLES, SHADOW, ADVENTURE, RING_BEARER, RING, MAP; + + public static PileType Parse(String value) { + value = value + .toUpperCase() + .replace(" ", "_") + .replace("-", "_"); + + if(value.contains("FREEPS") || value.contains("FREE") || value.contains("PEOPLE")) + return FREE_PEOPLES; + + if(value.contains("SITE") || value.contains("ADVENTURE")) + return ADVENTURE; + + for (PileType type : values()) { + if (type.toString().equalsIgnoreCase(value)) + return type; + } + + return null; + } +} diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Result.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Result.java new file mode 100644 index 000000000..f3e00cf76 --- /dev/null +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/lotro/common/Result.java @@ -0,0 +1,4 @@ +package com.gempukku.lotro.common; + +public record Result(boolean success, String message) { +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/BuiltLotroCardBlueprint.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/BuiltLotroCardBlueprint.java index ad4daa119..0703d334c 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/BuiltLotroCardBlueprint.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/BuiltLotroCardBlueprint.java @@ -5,6 +5,7 @@ import com.gempukku.lotro.filters.Filters; import com.gempukku.lotro.game.ExtraPlayCost; import com.gempukku.lotro.game.LotroCardBlueprint; import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.game.PhysicalCardImpl; import com.gempukku.lotro.game.state.LotroGame; import com.gempukku.lotro.logic.PlayUtils; import com.gempukku.lotro.logic.actions.*; @@ -82,8 +83,14 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint { private ExtraPossessionClassTest extraPossessionClassTest; + private PreGameDeckValidation deckValidation; + // Building methods + public void setDeckValidation(PreGameDeckValidation validation) { + this.deckValidation = validation; + } + public void setAllyHomeSites(SitesBlock block, int[] numbers) { this.allyHomeBlock = block; this.allyHomeSites = numbers; @@ -332,6 +339,14 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint { // Implemented methods + @Override + public Result validatePreGameDeckCheck(List freeps, List shadow, + List sites, PhysicalCardImpl rb, PhysicalCardImpl ring, PhysicalCardImpl map) { + if(deckValidation != null) + return deckValidation.validatePreGameDeckCheck(freeps, shadow, sites, rb, ring, map); + + return new Result(true, null); + } @Override public Side getSide() { return side; @@ -975,10 +990,10 @@ public class BuiltLotroCardBlueprint implements LotroCardBlueprint { throw new InvalidCardDefinitionException("Card has to have a title"); if (cardType == null) throw new InvalidCardDefinitionException("Card has to have a type"); - if (cardType != CardType.THE_ONE_RING && cardType != CardType.SITE && side == null) - throw new InvalidCardDefinitionException("Only The One Ring does not have a side defined"); - if (cardType != CardType.THE_ONE_RING && cardType != CardType.SITE && culture == null) - throw new InvalidCardDefinitionException("Only The One Ring does not have a culture defined"); + if (cardType != CardType.THE_ONE_RING && cardType != CardType.SITE && cardType != CardType.MAP && side == null) + throw new InvalidCardDefinitionException("All cards except The One Ring, Sites, and Maps must have a side defined"); + if (cardType != CardType.THE_ONE_RING && cardType != CardType.SITE && cardType != CardType.MAP && culture == null) + throw new InvalidCardDefinitionException("All cards except The One Ring, Sites, and Maps have a culture defined"); if (siteNumber != 0 && cardType != CardType.SITE && cardType != CardType.MINION) diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/LotroCardBlueprintBuilder.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/LotroCardBlueprintBuilder.java index defaac68c..cbf10d24b 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/LotroCardBlueprintBuilder.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/LotroCardBlueprintBuilder.java @@ -33,7 +33,7 @@ public class LotroCardBlueprintBuilder implements CardGenerationEnvironment { fieldProcessors.put("itemclass", new PossessionClassFieldProcessor()); fieldProcessors.put("keyword", new KeywordFieldProcessor()); fieldProcessors.put("keywords", new KeywordFieldProcessor()); - fieldProcessors.put("twilight", new CostFieldProcessor()); + fieldProcessors.put("twilight", new TwilightCostFieldProcessor()); fieldProcessors.put("strength", new StrengthFieldProcessor()); fieldProcessors.put("vitality", new VitalityFieldProcessor()); fieldProcessors.put("resistance", new ResistanceFieldProcessor()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/PreGameDeckValidation.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/PreGameDeckValidation.java new file mode 100644 index 000000000..e73551d0b --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/PreGameDeckValidation.java @@ -0,0 +1,13 @@ +package com.gempukku.lotro.cards.build; + +import com.gempukku.lotro.common.Result; +import com.gempukku.lotro.game.PhysicalCard; +import com.gempukku.lotro.game.PhysicalCardImpl; +import com.gempukku.lotro.game.state.LotroGame; + +import java.util.List; + +public interface PreGameDeckValidation { + Result validatePreGameDeckCheck(List freeps, List shadow, + List sites, PhysicalCardImpl rb, PhysicalCardImpl ring, PhysicalCardImpl map); +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/EffectFieldProcessor.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/EffectFieldProcessor.java index 49efc98fa..9e042c8b1 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/EffectFieldProcessor.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/EffectFieldProcessor.java @@ -22,6 +22,7 @@ public class EffectFieldProcessor implements FieldProcessor { effectProcessors.put("activatedtrigger", new ActivatedTriggerEffectProcessor()); effectProcessors.put("aidcost", new AidCost()); effectProcessors.put("copycard", new CopyCard()); + effectProcessors.put("deckbuildingrestriction", new DeckBuildingRestrictionGameTextProcessor()); effectProcessors.put("discardedfromplaytrigger", new DiscardedFromPlayTriggerEffectProcessor()); effectProcessors.put("discount", new PotentialDiscount()); effectProcessors.put("event", new EventEffectProcessor()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java index 638a20ea6..89dfef54f 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/FieldUtils.java @@ -21,7 +21,7 @@ public class FieldUtils { if (value == null) return defaultValue; if (!(value instanceof Number)) - throw new InvalidCardDefinitionException("Unknown type in " + key + " field"); + throw new InvalidCardDefinitionException("Value in " + key + " field must be an integer, not an evaluated value."); return ((Number) value).intValue(); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/CostFieldProcessor.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/TwilightCostFieldProcessor.java similarity index 89% rename from gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/CostFieldProcessor.java rename to gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/TwilightCostFieldProcessor.java index ebdf1bde8..0b0d9e124 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/CostFieldProcessor.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/TwilightCostFieldProcessor.java @@ -5,7 +5,7 @@ import com.gempukku.lotro.cards.build.CardGenerationEnvironment; import com.gempukku.lotro.cards.build.FieldProcessor; import com.gempukku.lotro.cards.build.InvalidCardDefinitionException; -public class CostFieldProcessor implements FieldProcessor { +public class TwilightCostFieldProcessor implements FieldProcessor { @Override public void processField(String key, Object value, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { blueprint.setCost(FieldUtils.getInteger(value, key)); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/DeckBuildingRestrictionGameTextProcessor.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/DeckBuildingRestrictionGameTextProcessor.java new file mode 100644 index 000000000..b292b8acf --- /dev/null +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/cards/build/field/effect/DeckBuildingRestrictionGameTextProcessor.java @@ -0,0 +1,99 @@ +package com.gempukku.lotro.cards.build.field.effect; + +import com.gempukku.lotro.cards.build.*; +import com.gempukku.lotro.cards.build.field.EffectProcessor; +import com.gempukku.lotro.cards.build.field.FieldUtils; +import com.gempukku.lotro.common.PileType; +import com.gempukku.lotro.common.Filterable; +import com.gempukku.lotro.common.Result; +import com.gempukku.lotro.filters.Filter; +import com.gempukku.lotro.filters.Filters; +import com.gempukku.lotro.game.LotroCardBlueprint; +import com.gempukku.lotro.game.PhysicalCardImpl; +import com.gempukku.lotro.logic.GameUtils; +import org.apache.commons.lang3.StringUtils; +import org.json.simple.JSONObject; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class DeckBuildingRestrictionGameTextProcessor implements EffectProcessor { + @Override + public void processEffect(JSONObject effectObj, BuiltLotroCardBlueprint blueprint, CardGenerationEnvironment environment) throws InvalidCardDefinitionException { + FieldUtils.validateAllowedFields(effectObj, "filter", "pile", "min", "max", "text"); + + final int max = FieldUtils.getInteger(effectObj.get("max"), "max", 1000); + final int min = FieldUtils.getInteger(effectObj.get("max"), "min", 0); + final String pileStr = FieldUtils.getString(effectObj.get("pile"), "pile"); + final PileType pileType = PileType.Parse(pileStr); + final String failureMsg = FieldUtils.getString(effectObj.get("text"), "text"); + + if(StringUtils.isBlank(failureMsg)) + throw new InvalidCardDefinitionException("'text' field is required for deck validation operations to communicate to the player what validation they are faling in the deckbuilder. Ensure it is user friendly."); + if(max < min) + throw new InvalidCardDefinitionException("'max' field may not be less than 'min' field for deck validations."); + if(min < 0) + throw new InvalidCardDefinitionException("'min' field may not be less than zero for deck validations."); + + final String filterStr = FieldUtils.getString(effectObj.get("filter"), "attachedTo", "any"); + final var filterSource = environment.getFilterFactory().generateFilter(filterStr, environment); + + + + blueprint.setDeckValidation( + (freeps, shadow, sites, rb, ring, map) -> { + + var filter = Filters.and(filterSource.getFilterable(null)); + var found = new ArrayList(); + + if(pileType == null || pileType == PileType.FREE_PEOPLES) { + found.addAll(validate(freeps, filter)); + } + if(pileType == null || pileType == PileType.SHADOW) { + found.addAll(validate(shadow, filter)); + } + if(pileType == null || pileType == PileType.ADVENTURE) { + found.addAll(validate(sites, filter)); + } + if(pileType == null || pileType == PileType.RING_BEARER) { + found.addAll(validate(Collections.singletonList(rb), filter)); + } + if(pileType == null || pileType == PileType.RING) { + found.addAll(validate(Collections.singletonList(ring), filter)); + } + if(pileType == null || pileType == PileType.MAP) { + found.addAll(validate(Collections.singletonList(map), filter)); + } + + final String successMsg = "Deck meets restrictions placed by " + GameUtils.getFullName(blueprint) + "."; + final String fullFailureMsg = "Deck does not meet restrictions placed by " + GameUtils.getFullName(blueprint) + ": " + + failureMsg + ". "; + + if(found.size() > max || found.size() < min) + return new Result(false, fullFailureMsg + "Found " + found.size() + ": " + + found.stream().map(GameUtils::getFullName).collect(Collectors.joining(", "))); + + return new Result(true, successMsg); + }); + + blueprint.setExtraPossessionClassTest( + (game, self, attachedTo) -> { + DefaultActionContext actionContext = new DefaultActionContext(self.getOwner(), game, self, null, null); + final Filterable attachedFilterable = filterSource.getFilterable(actionContext); + return Filters.and(attachedFilterable).accepts(game, attachedTo); + }); + } + + protected List validate(List cards, Filter filter) { + var found = new ArrayList(); + for(var card : cards) { + if(filter.accepts(null, card)) { + found.add(card.getBlueprint()); + } + } + + return found; + } +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java index 382d43326..f8c379796 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroCardBlueprint.java @@ -129,4 +129,9 @@ public interface LotroCardBlueprint { void appendAidCosts(LotroGame game, CostToEffectAction action, PhysicalCard self); boolean skipUniquenessCheck(); + + default Result validatePreGameDeckCheck(List freeps, List shadow, + List sites, PhysicalCardImpl rb, PhysicalCardImpl ring, PhysicalCardImpl map) { + return new Result(true, null); + } } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroFormat.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroFormat.java index 883508cae..42688ec8b 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroFormat.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/LotroFormat.java @@ -8,61 +8,62 @@ import java.util.List; import java.util.Map; public interface LotroFormat { - public boolean isOrderedSites(); + boolean isOrderedSites(); - public boolean canCancelRingBearerSkirmish(); + boolean canCancelRingBearerSkirmish(); - public boolean hasRuleOfFour(); + boolean hasRuleOfFour(); + boolean usesMaps(); - public boolean hasMulliganRule(); + boolean hasMulliganRule(); - public boolean winWhenShadowReconciles(); + boolean winWhenShadowReconciles(); - public boolean discardPileIsPublic(); + boolean discardPileIsPublic(); - public boolean winOnControlling5Sites(); + boolean winOnControlling5Sites(); - public boolean isPlaytest(); - public boolean hallVisible(); + boolean isPlaytest(); + boolean hallVisible(); - public String getName(); + String getName(); - public String getCode(); - public int getOrder(); + String getCode(); + int getOrder(); - public String validateCard(String cardId); + String validateCard(String cardId); - public List validateDeck(LotroDeck deck); - public String validateDeckForHall(LotroDeck deck); + List validateDeck(LotroDeck deck); + String validateDeckForHall(LotroDeck deck); - public LotroDeck applyErrata(LotroDeck deck); + LotroDeck applyErrata(LotroDeck deck); - public List getValidSets(); + List getValidSets(); - public List getBannedCards(); + List getBannedCards(); - public List getRestrictedCards(); + List getRestrictedCards(); - public List getValidCards(); + List getValidCards(); - public List getLimit2Cards(); + List getLimit2Cards(); - public List getLimit3Cards(); + List getLimit3Cards(); - public List getRestrictedCardNames(); + List getRestrictedCardNames(); - public Map getErrataCardMap(); + Map getErrataCardMap(); - public String applyErrata(String bpID); + String applyErrata(String bpID); - public List findBaseCards(String bpID); + List findBaseCards(String bpID); - public SitesBlock getSiteBlock(); + SitesBlock getSiteBlock(); - public String getSurveyUrl(); + String getSurveyUrl(); - public int getHandSize(); + int getHandSize(); - public Adventure getAdventure(); - public JSONDefs.Format Serialize(); + Adventure getAdventure(); + JSONDefs.Format Serialize(); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/EventSerializer.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/EventSerializer.java index 7991048f1..1b03dbd63 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/EventSerializer.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/EventSerializer.java @@ -94,7 +94,7 @@ public class EventSerializer { deckElement.setAttribute("rb", deck.getRingBearer()); deckElement.setAttribute("ring", deck.getRing()); deckElement.setAttribute("sites", String.join(",", deck.getSites())); - deckElement.setAttribute("deck", String.join(",", deck.getAdventureCards())); + deckElement.setAttribute("deck", String.join(",", deck.getDrawDeckCards())); eventElem.appendChild(deckElement); } diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java index cccf79096..ed47c3667 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/timing/DefaultLotroGame.java @@ -62,7 +62,7 @@ public class DefaultLotroGame implements LotroGame { LotroDeck lotroDeck = decks.get(playerId); deck.addAll(lotroDeck.getSites()); - deck.addAll(lotroDeck.getAdventureCards()); + deck.addAll(lotroDeck.getDrawDeckCards()); cards.put(playerId, deck); ringBearers.put(playerId, lotroDeck.getRingBearer()); diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/vo/LotroDeck.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/vo/LotroDeck.java index 35c420a8b..e0b7a12d7 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/vo/LotroDeck.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/logic/vo/LotroDeck.java @@ -7,6 +7,7 @@ import java.util.List; public class LotroDeck { private String _ringBearer; private String _ring; + private String _map; private final List _siteCards = new ArrayList<>(); private final List _nonSiteCards = new ArrayList<>(); private final String _deckName; @@ -29,6 +30,7 @@ public class LotroDeck { public void setRing(String ring) { _ring = ring; } + public void setMap(String map) { _map = map; } public void addCard(String card) { _nonSiteCards.add(card); @@ -38,7 +40,7 @@ public class LotroDeck { _siteCards.add(card); } - public List getAdventureCards() { + public List getDrawDeckCards() { return Collections.unmodifiableList(_nonSiteCards); } @@ -54,6 +56,10 @@ public class LotroDeck { return _ring; } + public String getMap() { + return _map; + } + public String getTargetFormat() { return _targetFormat; } public void setTargetFormat(String value) { _targetFormat = value; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/DeckRenderer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/DeckRenderer.java index 4cd61c188..497c20c0e 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/DeckRenderer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/collection/DeckRenderer.java @@ -1,7 +1,6 @@ package com.gempukku.lotro.collection; import com.gempukku.lotro.common.Names; -import com.gempukku.lotro.competitive.PlayerStanding; import com.gempukku.lotro.game.*; import com.gempukku.lotro.game.formats.LotroFormatLibrary; import com.gempukku.lotro.logic.GameUtils; @@ -137,7 +136,7 @@ public class DeckRenderer { } DefaultCardCollection deckCards = new DefaultCardCollection(); - for (String card : deck.getAdventureCards()) { + for (String card : deck.getDrawDeckCards()) { deckCards.addItem(_bpLibrary.getBaseBlueprintId(card), 1); } for (String site : deck.getSites()) { @@ -216,7 +215,7 @@ public class DeckRenderer { } DefaultCardCollection deckCards = new DefaultCardCollection(); - for (String card : deck.getAdventureCards()) { + for (String card : deck.getDrawDeckCards()) { deckCards.addItem(_bpLibrary.getBaseBlueprintId(card), 1); } for (String site : deck.getSites()) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/DeckSerialization.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/DeckSerialization.java index 9c6eac47f..cb970f456 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/DeckSerialization.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/db/DeckSerialization.java @@ -17,10 +17,14 @@ public class DeckSerialization { sb.append(deck.getSites().get(i)); } sb.append("|"); - for (int i = 0; i < deck.getAdventureCards().size(); i++) { + for (int i = 0; i < deck.getDrawDeckCards().size(); i++) { if (i > 0) sb.append(","); - sb.append(deck.getAdventureCards().get(i)); + sb.append(deck.getDrawDeckCards().get(i)); + } + if (deck.getMap() != null) { + sb.append("|"); + sb.append(deck.getMap()); } return sb.toString(); @@ -47,6 +51,11 @@ public class DeckSerialization { if (!card.equals("")) deck.addCard(card); } + if (parts.length > 4) + for (String card : parts[4].split(",")) { + if (!card.equals("")) + deck.setMap(card); + } return deck; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/CollectionUtils.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/CollectionUtils.java index 3e6930f2a..810132ed2 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/CollectionUtils.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/CollectionUtils.java @@ -17,7 +17,7 @@ public class CollectionUtils { incrementCardCount(counts, ringBearer, 1); for (String site : deck.getSites()) incrementCardCount(counts, site, 1); - for (String adventureCard : deck.getAdventureCards()) + for (String adventureCard : deck.getDrawDeckCards()) incrementCardCount(counts, adventureCard, 1); return counts; } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java index e96080ad6..6b4bd85ae 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/GameRecorder.java @@ -199,7 +199,7 @@ public class GameRecorder { deckElement.setAttribute("rb", deck.getRingBearer()); deckElement.setAttribute("ring", deck.getRing()); deckElement.setAttribute("sites", String.join(",", deck.getSites())); - deckElement.setAttribute("deck", String.join(",", deck.getAdventureCards())); + deckElement.setAttribute("deck", String.join(",", deck.getDrawDeckCards())); info.appendChild(deckElement); } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java index 80ada48fa..15c760607 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/LotroServer.java @@ -188,7 +188,7 @@ public class LotroServer extends AbstractServer { cnt++; } - if (cnt != 3) + if (cnt < 3 || cnt > 4) return null; return _deckDao.buildDeckFromContents(deckName, contents, targetFormat, notes); diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ReplayMetadata.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ReplayMetadata.java index 84e1b6526..09c4f2531 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ReplayMetadata.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ReplayMetadata.java @@ -57,7 +57,7 @@ public class ReplayMetadata { TargetFormat = deck.getTargetFormat(); DeckName = deck.getDeckName(); AdventureDeck = deck.getSites(); - DrawDeck = deck.getAdventureCards(); + DrawDeck = deck.getDrawDeckCards(); RingBearer = deck.getRingBearer(); Ring = deck.getRing(); }}; diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java index e538b07ca..46e96f1a3 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/formats/DefaultLotroFormat.java @@ -21,6 +21,7 @@ public class DefaultLotroFormat implements LotroFormat { private boolean _validateShadowFPCount = true; private int _maximumSameName = 4; private final boolean _mulliganRule; + private final boolean _usesMaps; private final boolean _canCancelRingBearerSkirmish; private final boolean _hasRuleOfFour; private final boolean _winAtEndOfRegroup; @@ -40,10 +41,28 @@ public class DefaultLotroFormat implements LotroFormat { private final List _limit3Cards = new ArrayList<>(); private final Map _errataCardMap = new TreeMap<>(); + public DefaultLotroFormat(AdventureLibrary adventureLibrary, LotroCardBlueprintLibrary library, JSONDefs.Format def) throws InvalidPropertiesFormatException{ - this(library, adventureLibrary.getAdventure(def.adventure), def.name, def.code, def.order, def.surveyUrl, SitesBlock.findBlock(def.sites), - def.validateShadowFPCount, def.minimumDeckSize, def.maximumSameName, def.mulliganRule, def.cancelRingBearerSkirmish, - def.ruleOfFour, def.winAtEndOfRegroup, def.discardPileIsPublic, def.winOnControlling5Sites, def.playtest, def.hall); + + _adventure = adventureLibrary.getAdventure(def.adventure); + _library = library; + _name = def.name; + _code = def.code; + _order = def.order; + _surveyUrl = def.surveyUrl; + _siteBlock = SitesBlock.findBlock(def.sites); + _validateShadowFPCount = def.validateShadowFPCount; + _minimumDeckSize = def.minimumDeckSize; + _maximumSameName = def.maximumSameName; + _mulliganRule = def.mulliganRule; + _usesMaps = def.usesMaps; + _canCancelRingBearerSkirmish = def.cancelRingBearerSkirmish; + _hasRuleOfFour = def.ruleOfFour; + _winAtEndOfRegroup = def.winAtEndOfRegroup; + _discardPileIsPublic = def.discardPileIsPublic; + _winOnControlling5Sites = def.winOnControlling5Sites; + _isPlaytest = def.playtest; + _hallVisible = def.hall; if(def.set != null) def.set.forEach(this::addValidSet); @@ -68,32 +87,6 @@ public class DefaultLotroFormat implements LotroFormat { def.errata.forEach(this::addCardErrata); } - public DefaultLotroFormat(LotroCardBlueprintLibrary library, - Adventure adventure, String name, String code, int order, String surveyUrl, - SitesBlock siteBlock, - boolean validateShadowFPCount, int minimumDeckSize, int maximumSameName, boolean mulliganRule, - boolean canCancelRingBearerSkirmish, boolean hasRuleOfFour, boolean winAtEndOfRegroup, boolean discardPileIsPublic, - boolean winOnControlling5Sites, boolean playtest, boolean hallVisible) { - _adventure = adventure; - _library = library; - _name = name; - _code = code; - _order = order; - _surveyUrl = surveyUrl; - _siteBlock = siteBlock; - _validateShadowFPCount = validateShadowFPCount; - _minimumDeckSize = minimumDeckSize; - _maximumSameName = maximumSameName; - _mulliganRule = mulliganRule; - _canCancelRingBearerSkirmish = canCancelRingBearerSkirmish; - _hasRuleOfFour = hasRuleOfFour; - _winAtEndOfRegroup = winAtEndOfRegroup; - _discardPileIsPublic = discardPileIsPublic; - _winOnControlling5Sites = winOnControlling5Sites; - _isPlaytest = playtest; - _hallVisible = hallVisible; - } - @Override public Adventure getAdventure() { return _adventure; @@ -144,6 +137,11 @@ public class DefaultLotroFormat implements LotroFormat { return _hasRuleOfFour; } + @Override + public boolean usesMaps() { + return _usesMaps; + } + @Override public boolean winOnControlling5Sites() { return _winOnControlling5Sites; @@ -296,7 +294,7 @@ public class DefaultLotroFormat implements LotroFormat { if (_validCards.contains(blueprintId) || _errataCardMap.containsValue(blueprintId)) return null; - if (_validSets.size() > 0 && !isValidInSets(blueprintId)) + if (!_validSets.isEmpty() && !isValidInSets(blueprintId)) return "Deck contains card not from valid set: " + GameUtils.getFullName(_library.getLotroCardBlueprint(blueprintId)); // Banned cards @@ -362,6 +360,12 @@ public class DefaultLotroFormat implements LotroFormat { result.add(valid); } + // Map + valid = validateMap(deck); + if(valid != null && !valid.isEmpty()) { + result.add(valid); + } + // Deck valid = validateDeckStructure(deck); if(valid != null && !valid.isEmpty()) { @@ -370,7 +374,7 @@ public class DefaultLotroFormat implements LotroFormat { String prevLine = ""; String newLine = ""; - for (String card : deck.getAdventureCards()){ + for (String card : deck.getDrawDeckCards()){ newLine = validateCard(card); if(newLine == null || newLine.isEmpty()) continue; @@ -413,7 +417,7 @@ public class DefaultLotroFormat implements LotroFormat { if (deck.getRingBearer() != null) { processCardCounts(deck.getRingBearer(), cardCountByName, cardCountByBaseBlueprintId); } - for (String blueprintId : deck.getAdventureCards()) + for (String blueprintId : deck.getDrawDeckCards()) processCardCounts(blueprintId, cardCountByName, cardCountByBaseBlueprintId); for (String blueprintId : deck.getSites()) processCardCounts(blueprintId, cardCountByName, cardCountByBaseBlueprintId); @@ -475,7 +479,7 @@ public class DefaultLotroFormat implements LotroFormat { if (deck.getRing() != null) { deckWithErrata.setRing(applyErrata(deck.getRing())); } - for (String card : deck.getAdventureCards()) { + for (String card : deck.getDrawDeckCards()) { deckWithErrata.addCard(applyErrata(card)); } for (String site : deck.getSites()) { @@ -510,13 +514,13 @@ public class DefaultLotroFormat implements LotroFormat { private String validateDeckStructure(LotroDeck deck) { String result = ""; - if (deck.getAdventureCards().size() < _minimumDeckSize) { - result += "Deck contains below minimum number of cards: " + deck.getAdventureCards().size() + "<" + _minimumDeckSize + ".\n"; + if (deck.getDrawDeckCards().size() < _minimumDeckSize) { + result += "Deck contains below minimum number of cards: " + deck.getDrawDeckCards().size() + "<" + _minimumDeckSize + ".\n"; } if (_validateShadowFPCount) { int shadow = 0; int fp = 0; - for (String blueprintId : deck.getAdventureCards()) { + for (String blueprintId : deck.getDrawDeckCards()) { try { LotroCardBlueprint card = _library.getLotroCardBlueprint(blueprintId); if (card.getSide() == Side.SHADOW) @@ -673,6 +677,52 @@ public class DefaultLotroFormat implements LotroFormat { return validateCard(ringbp); } + private String validateMap(LotroDeck deck) { + String mapBP = deck.getMap(); + if (!_usesMaps) + return null; + if (mapBP == null) + return "Deck doesn't have a Map (try the King map if converting a Movie deck)."; + try { + var map = _library.getLotroCardBlueprint(mapBP); + if (map.getCardType() != CardType.MAP) + return "Card assigned as Map is not a Map card."; + + var check = validateCard(mapBP); + if(check != null) + return check; + + var freeps = new ArrayList(); + var shadow = new ArrayList(); + var sites = new ArrayList(); + for(var bp : deck.getDrawDeckCards()) { + var blueprint = _library.getLotroCardBlueprint(bp); + if(blueprint.getSide() == Side.FREE_PEOPLE) { + freeps.add(new PhysicalCardImpl(0, bp, "", blueprint)); + } + else if(blueprint.getSide() == Side.SHADOW) { + shadow.add(new PhysicalCardImpl(0, bp, "", blueprint)); + } + } + + for(var bp : deck.getSites()) { + sites.add(new PhysicalCardImpl(0, bp, "", _library.getLotroCardBlueprint(bp))); + } + + var rb = new PhysicalCardImpl(0, deck.getRingBearer(), "", _library.getLotroCardBlueprint(deck.getRingBearer())); + var ring = new PhysicalCardImpl(0, deck.getRing(), "", _library.getLotroCardBlueprint(deck.getRing())); + + var result = map.validatePreGameDeckCheck(freeps, shadow, sites, rb, ring, new PhysicalCardImpl(0, mapBP, "", map)); + if(!result.success()) + return result.message(); + return null; + } + catch(CardNotFoundException exception) + { + return CardRemovedError + ": " + mapBP; + } + } + private String validateRingBearer(LotroDeck deck) { String rb = deck.getRingBearer(); if (rb == null) @@ -730,6 +780,7 @@ public class DefaultLotroFormat implements LotroFormat { minimumDeckSize = _minimumDeckSize; maximumSameName = _maximumSameName; mulliganRule = _mulliganRule; + usesMaps = _usesMaps; set = null; banned = null; restricted = null; diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java index 75a5b9525..6b24b5606 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallServer.java @@ -23,7 +23,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; import java.sql.SQLException; -import java.time.ZonedDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReadWriteLock; @@ -602,7 +601,7 @@ public class HallServer extends AbstractServer { for (String site : lotroDeck.getSites()) filteredSpecialCardsDeck.addSite(filterCard(site, ownedCollection)); - for (Map.Entry cardCount : CollectionUtils.getTotalCardCount(lotroDeck.getAdventureCards()).entrySet()) { + for (Map.Entry cardCount : CollectionUtils.getTotalCardCount(lotroDeck.getDrawDeckCards()).entrySet()) { String blueprintId = cardCount.getKey(); int count = cardCount.getValue();