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();