diff --git a/.classpath b/.classpath index b16f6f148..08f3d781d 100644 --- a/.classpath +++ b/.classpath @@ -1,11 +1,11 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/.project b/.project index 5fc51296e..f6a001b2f 100644 --- a/.project +++ b/.project @@ -1,23 +1,23 @@ - - - JCloisterZone - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - - + + + JCloisterZone + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + diff --git a/pom.xml b/pom.xml index 800981358..92f8a0519 100644 --- a/pom.xml +++ b/pom.xml @@ -1,170 +1,170 @@ - - 4.0.0 - jcloisterzone - jcloisterzone - JCloisterZone - 2-SNAPSHOT - Carcassonne board game Java implementation - http://www.jcloisterzone.org/ - - - - gettext-commons-site - http://gettext-commons.googlecode.com/svn/maven-repository/ - - - - - - gettext-commons-site - http://gettext-commons.googlecode.com/svn/maven-repository/ - - daily - - - - - - - - com.google.guava - guava - 15.0 - - - org.slf4j - slf4j-simple - 1.7.5 - - - org.apache.mina - mina-core - 2.0.7 - - - org.ini4j - ini4j - 0.5.2 - - - com.miglayout - miglayout - 3.7.4 - - - org.xnap.commons - gettext-commons - 0.9.6 - - - com.apple - AppleJavaExtensions - 1.4 - - - - - junit - junit - 4.10 - test - - - org.mockito - mockito-all - 1.9.0 - test - - - - - - - - src/main/resources - - **/* - - - - src/main/config - - **/* - - - config.ini - debug.ini - - - - - - maven-compiler-plugin - - 1.7 - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-shade-plugin - 2.1 - - - package - - shade - - - JCloisterZone - build - - - - com.jcloisterzone.ui.Bootstrap - sysimages/jcloisterzone.png - . - - - - true - - - jcloisterzone:jcloisterzone - - config.ini - debug.ini - **/.gitignore - plugins/** - - - - - - - - - - - prepare-package - - dist - - - - org.xnap.commons - maven-gettext-plugin - 1.2.3 - - ${basedir}/po - ${project.build.sourceDirectory} - ${project.build.outputDirectory} - Messages - - - - + + 4.0.0 + jcloisterzone + jcloisterzone + JCloisterZone + 2-SNAPSHOT + Carcassonne board game Java implementation + http://www.jcloisterzone.org/ + + + + gettext-commons-site + http://gettext-commons.googlecode.com/svn/maven-repository/ + + + + + + gettext-commons-site + http://gettext-commons.googlecode.com/svn/maven-repository/ + + daily + + + + + + + + com.google.guava + guava + 15.0 + + + org.slf4j + slf4j-simple + 1.7.5 + + + org.apache.mina + mina-core + 2.0.7 + + + org.ini4j + ini4j + 0.5.2 + + + com.miglayout + miglayout + 3.7.4 + + + org.xnap.commons + gettext-commons + 0.9.6 + + + com.apple + AppleJavaExtensions + 1.4 + + + + + junit + junit + 4.10 + test + + + org.mockito + mockito-all + 1.9.0 + test + + + + + + + + src/main/resources + + **/* + + + + src/main/config + + **/* + + + config.ini + debug.ini + + + + + + maven-compiler-plugin + + 1.7 + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.1 + + + package + + shade + + + JCloisterZone + build + + + + com.jcloisterzone.ui.Bootstrap + sysimages/jcloisterzone.png + . + + + + true + + + jcloisterzone:jcloisterzone + + config.ini + debug.ini + **/.gitignore + plugins/** + + + + + + + + + + + prepare-package + + dist + + + + org.xnap.commons + maven-gettext-plugin + 1.2.3 + + ${basedir}/po + ${project.build.sourceDirectory} + ${project.build.outputDirectory} + Messages + + + + \ No newline at end of file diff --git a/src/main/config/simplelogger.properties b/src/main/config/simplelogger.properties index 639281a48..04f3dff8a 100644 --- a/src/main/config/simplelogger.properties +++ b/src/main/config/simplelogger.properties @@ -1,2 +1,2 @@ -org.slf4j.simpleLogger.logFile=System.out +org.slf4j.simpleLogger.logFile=System.out org.slf4j.simpleLogger.defaultLogLevel=WARN \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/AppUpdate.java b/src/main/java/com/jcloisterzone/AppUpdate.java index 682bb0cb3..6cadee9d0 100644 --- a/src/main/java/com/jcloisterzone/AppUpdate.java +++ b/src/main/java/com/jcloisterzone/AppUpdate.java @@ -1,52 +1,52 @@ -package com.jcloisterzone; - -import java.net.URL; - -import org.w3c.dom.Element; - -public class AppUpdate { - - private String version; - private String description; - private String downloadUrl; - - public static AppUpdate fetch(URL url) { - Element el = XmlUtils.parseDocument(url).getDocumentElement(); - String version = XmlUtils.childValue(el, "number"); - String description = XmlUtils.childValue(el, "description"); - String downloadUrl = XmlUtils.childValue(el, "url"); - return new AppUpdate(version, description, downloadUrl); - } - - public AppUpdate(String version, String description, String downloadUrl) { - this.version = version; - this.description = description; - this.downloadUrl = downloadUrl; - } - - @Override - public String toString() { - return this.version + " " + this.description; - } - - public String getVersion() { - return version; - } - public void setVersion(String version) { - this.version = version; - } - public String getDescription() { - return description; - } - public void setDescription(String description) { - this.description = description; - } - public String getDownloadUrl() { - return downloadUrl; - } - public void setDownloadUrl(String downloadUrl) { - this.downloadUrl = downloadUrl; - } - - -} +package com.jcloisterzone; + +import java.net.URL; + +import org.w3c.dom.Element; + +public class AppUpdate { + + private String version; + private String description; + private String downloadUrl; + + public static AppUpdate fetch(URL url) { + Element el = XmlUtils.parseDocument(url).getDocumentElement(); + String version = XmlUtils.childValue(el, "number"); + String description = XmlUtils.childValue(el, "description"); + String downloadUrl = XmlUtils.childValue(el, "url"); + return new AppUpdate(version, description, downloadUrl); + } + + public AppUpdate(String version, String description, String downloadUrl) { + this.version = version; + this.description = description; + this.downloadUrl = downloadUrl; + } + + @Override + public String toString() { + return this.version + " " + this.description; + } + + public String getVersion() { + return version; + } + public void setVersion(String version) { + this.version = version; + } + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + public String getDownloadUrl() { + return downloadUrl; + } + public void setDownloadUrl(String downloadUrl) { + this.downloadUrl = downloadUrl; + } + + +} diff --git a/src/main/java/com/jcloisterzone/Application.java b/src/main/java/com/jcloisterzone/Application.java index a95c1e4c6..fc0c341f5 100644 --- a/src/main/java/com/jcloisterzone/Application.java +++ b/src/main/java/com/jcloisterzone/Application.java @@ -1,18 +1,18 @@ -package com.jcloisterzone; - -/** - * Various application constants. - * @author Roman Krejcik - */ -public interface Application { - -// public String VERSION = "2.3"; -// public String BUILD_DATE = "YYYY-MM-DD"; - - public String VERSION = "dev-snapshot"; - public String BUILD_DATE = ""; - - public int PROTCOL_VERSION = 15; - - public static final String ILLEGAL_STATE_MSG = "Method '{}' called in invalid state"; -} +package com.jcloisterzone; + +/** + * Various application constants. + * @author Roman Krejcik + */ +public interface Application { + +// public String VERSION = "2.3"; +// public String BUILD_DATE = "YYYY-MM-DD"; + + public String VERSION = "dev-snapshot"; + public String BUILD_DATE = ""; + + public int PROTCOL_VERSION = 15; + + public static final String ILLEGAL_STATE_MSG = "Method '{}' called in invalid state"; +} diff --git a/src/main/java/com/jcloisterzone/Expansion.java b/src/main/java/com/jcloisterzone/Expansion.java index ec069594e..f77a7d2e9 100644 --- a/src/main/java/com/jcloisterzone/Expansion.java +++ b/src/main/java/com/jcloisterzone/Expansion.java @@ -1,131 +1,131 @@ -package com.jcloisterzone; - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.capability.AbbeyCapability; -import com.jcloisterzone.game.capability.BarnCapability; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.game.capability.BigFollowerCapability; -import com.jcloisterzone.game.capability.BridgeCapability; -import com.jcloisterzone.game.capability.BuilderCapability; -import com.jcloisterzone.game.capability.CastleCapability; -import com.jcloisterzone.game.capability.CathedralCapability; -import com.jcloisterzone.game.capability.ClothWineGrainCapability; -import com.jcloisterzone.game.capability.CornCircleCapability; -import com.jcloisterzone.game.capability.CountCapability; -import com.jcloisterzone.game.capability.DragonCapability; -import com.jcloisterzone.game.capability.FairyCapability; -import com.jcloisterzone.game.capability.FestivalCapability; -import com.jcloisterzone.game.capability.FlierCapability; -import com.jcloisterzone.game.capability.InnCapability; -import com.jcloisterzone.game.capability.KingScoutCapability; -import com.jcloisterzone.game.capability.MayorCapability; -import com.jcloisterzone.game.capability.PhantomCapability; -import com.jcloisterzone.game.capability.PigCapability; -import com.jcloisterzone.game.capability.PlagueCapability; -import com.jcloisterzone.game.capability.PortalCapability; -import com.jcloisterzone.game.capability.PrincessCapability; -import com.jcloisterzone.game.capability.RiverCapability; -import com.jcloisterzone.game.capability.ShrineCapability; -import com.jcloisterzone.game.capability.SiegeCapability; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.game.capability.TunnelCapability; -import com.jcloisterzone.game.capability.WagonCapability; -import com.jcloisterzone.game.capability.WindRoseCapability; - -@SuppressWarnings("unchecked") -public enum Expansion { - //Basic sets - BASIC("BA", _("Basic game")), - WINTER("WI", _("Winter Edition")), - WHEEL_OF_FORTUNE("WF", _("Wheel of Fortune"), false), - - //Big expansions - INNS_AND_CATHEDRALS("IC", _("Inns & Cathedrals"), - new Class[] { BigFollowerCapability.class ,InnCapability.class, CathedralCapability.class}), - TRADERS_AND_BUILDERS("TB", _("Traders & Builders"), - new Class[] { PigCapability.class, BuilderCapability.class, ClothWineGrainCapability.class }), - PRINCESS_AND_DRAGON("DG", _("The Princess & the Dragon"), - new Class[] { FairyCapability.class, DragonCapability.class, PortalCapability.class, PrincessCapability.class }), - TOWER("TO", _("The Tower"), - new Class[] { TowerCapability.class }), - ABBEY_AND_MAYOR("AM", _("Abbey & Mayor"), - new Class[] { AbbeyCapability.class, WagonCapability.class, MayorCapability.class, BarnCapability.class }), - CATAPULT("CA", _("The Catapult") + " (" + _("tiles only") + ")"), - BRIDGES_CASTLES_AND_BAZAARS("BB", _("Bridges, Castles and Bazaars"), - new Class[] { BridgeCapability.class, CastleCapability.class, BazaarCapability.class }), - - //Small expansion - KING_AND_SCOUT("KS", _("King and Scout"), new Class[] { KingScoutCapability.class }), - RIVER("R1", _("The River"), new Class[] { RiverCapability.class }), - RIVER_II("R2", _("The River II"), new Class[] { RiverCapability.class }), - CATHARS("SI", _("The Cathars / Siege"), new Class[] { SiegeCapability.class }), - COUNT("CO", _("The Count of Carcassonne") + " (" + _("tiles only") + ")", new Class[] { CountCapability.class }), - GQ11("GQ", _("The Mini Expansion (GQ11)")), - CULT("CU", _("The Cult"), new Class[] { ShrineCapability.class }), - TUNNEL("TU", _("The Tunnel"), new Class[] { TunnelCapability.class }), - CORN_CIRCLES("CC", _("The Corn Circles"), new Class[] { CornCircleCapability.class }), - PLAGUE("PL", _("The Plague") + " (" + _("tiles only") + ")", new Class[] { /*PlagueCapability.class*/ }), - PHANTOM("PH", _("The Phantom"), new Class[] { PhantomCapability.class }), - FESTIVAL("FE", _("The Festival (10th an.)"), new Class[] { FestivalCapability.class }), - HOUSES("LB", _("Little Buildings"), false), - WIND_ROSE("WR", _("The Wind Rose"), new Class[] { WindRoseCapability.class }), - - //minis expansion line - FLIER("FL", "#1 - " + _("The Flier"), new Class[] { FlierCapability.class }), - MESSAGES("ME", "#2 - " + _("The Messages"), false), - FERRIES("FR", "#3 - " + _("The Ferries"), false), - GOLDMINES("GO", "#4 - " + _("The Goldmines"), false), - MAGE_WITCH("MW", "#5 - " + _("Mage & Witch"), false), - ROBBER("RO", "#6 - " + _("The Robber"), false), - CORN_CIRCLES_II("C2", "#7 - " + _("The Corn circles II"), new Class[] { CornCircleCapability.class }); - - //promo/one tile expansions - //LA_PORXADA("PX", _("La porxada"), false), - //SCHOOL("SC", _("The school"), false); - - String code; - String label; - boolean enabled = true; - Class[] capabilities; - - Expansion(String code, String label) { - this(code, label, null); - } - - Expansion(String code, String label, boolean enabled) { - this(code, label, null); - this.enabled = enabled; - } - - Expansion(String code, String label, Class[] capabilities) { - this.code = code; - this.label = label; - this.capabilities = capabilities == null ? new Class[0] : capabilities; - } - - public String getCode() { - return code; - } - - public boolean isEnabled() { - return enabled; - } - - public Class[] getCapabilities() { - return capabilities; - } - - @Override - public String toString() { - return label; - } - - public static Expansion valueOfCode(String code) { - for (Expansion exp : values()) { - if (exp.code.equals(code)) return exp; - } - return null; - } +package com.jcloisterzone; + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.capability.AbbeyCapability; +import com.jcloisterzone.game.capability.BarnCapability; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.game.capability.BigFollowerCapability; +import com.jcloisterzone.game.capability.BridgeCapability; +import com.jcloisterzone.game.capability.BuilderCapability; +import com.jcloisterzone.game.capability.CastleCapability; +import com.jcloisterzone.game.capability.CathedralCapability; +import com.jcloisterzone.game.capability.ClothWineGrainCapability; +import com.jcloisterzone.game.capability.CornCircleCapability; +import com.jcloisterzone.game.capability.CountCapability; +import com.jcloisterzone.game.capability.DragonCapability; +import com.jcloisterzone.game.capability.FairyCapability; +import com.jcloisterzone.game.capability.FestivalCapability; +import com.jcloisterzone.game.capability.FlierCapability; +import com.jcloisterzone.game.capability.InnCapability; +import com.jcloisterzone.game.capability.KingScoutCapability; +import com.jcloisterzone.game.capability.MayorCapability; +import com.jcloisterzone.game.capability.PhantomCapability; +import com.jcloisterzone.game.capability.PigCapability; +import com.jcloisterzone.game.capability.PlagueCapability; +import com.jcloisterzone.game.capability.PortalCapability; +import com.jcloisterzone.game.capability.PrincessCapability; +import com.jcloisterzone.game.capability.RiverCapability; +import com.jcloisterzone.game.capability.ShrineCapability; +import com.jcloisterzone.game.capability.SiegeCapability; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.game.capability.TunnelCapability; +import com.jcloisterzone.game.capability.WagonCapability; +import com.jcloisterzone.game.capability.WindRoseCapability; + +@SuppressWarnings("unchecked") +public enum Expansion { + //Basic sets + BASIC("BA", _("Basic game")), + WINTER("WI", _("Winter Edition")), + WHEEL_OF_FORTUNE("WF", _("Wheel of Fortune"), false), + + //Big expansions + INNS_AND_CATHEDRALS("IC", _("Inns & Cathedrals"), + new Class[] { BigFollowerCapability.class ,InnCapability.class, CathedralCapability.class}), + TRADERS_AND_BUILDERS("TB", _("Traders & Builders"), + new Class[] { PigCapability.class, BuilderCapability.class, ClothWineGrainCapability.class }), + PRINCESS_AND_DRAGON("DG", _("The Princess & the Dragon"), + new Class[] { FairyCapability.class, DragonCapability.class, PortalCapability.class, PrincessCapability.class }), + TOWER("TO", _("The Tower"), + new Class[] { TowerCapability.class }), + ABBEY_AND_MAYOR("AM", _("Abbey & Mayor"), + new Class[] { AbbeyCapability.class, WagonCapability.class, MayorCapability.class, BarnCapability.class }), + CATAPULT("CA", _("The Catapult") + " (" + _("tiles only") + ")"), + BRIDGES_CASTLES_AND_BAZAARS("BB", _("Bridges, Castles and Bazaars"), + new Class[] { BridgeCapability.class, CastleCapability.class, BazaarCapability.class }), + + //Small expansion + KING_AND_SCOUT("KS", _("King and Scout"), new Class[] { KingScoutCapability.class }), + RIVER("R1", _("The River"), new Class[] { RiverCapability.class }), + RIVER_II("R2", _("The River II"), new Class[] { RiverCapability.class }), + CATHARS("SI", _("The Cathars / Siege"), new Class[] { SiegeCapability.class }), + COUNT("CO", _("The Count of Carcassonne") + " (" + _("tiles only") + ")", new Class[] { CountCapability.class }), + GQ11("GQ", _("The Mini Expansion (GQ11)")), + CULT("CU", _("The Cult"), new Class[] { ShrineCapability.class }), + TUNNEL("TU", _("The Tunnel"), new Class[] { TunnelCapability.class }), + CORN_CIRCLES("CC", _("The Corn Circles"), new Class[] { CornCircleCapability.class }), + PLAGUE("PL", _("The Plague") + " (" + _("tiles only") + ")", new Class[] { /*PlagueCapability.class*/ }), + PHANTOM("PH", _("The Phantom"), new Class[] { PhantomCapability.class }), + FESTIVAL("FE", _("The Festival (10th an.)"), new Class[] { FestivalCapability.class }), + HOUSES("LB", _("Little Buildings"), false), + WIND_ROSE("WR", _("The Wind Rose"), new Class[] { WindRoseCapability.class }), + + //minis expansion line + FLIER("FL", "#1 - " + _("The Flier"), new Class[] { FlierCapability.class }), + MESSAGES("ME", "#2 - " + _("The Messages"), false), + FERRIES("FR", "#3 - " + _("The Ferries"), false), + GOLDMINES("GO", "#4 - " + _("The Goldmines"), false), + MAGE_WITCH("MW", "#5 - " + _("Mage & Witch"), false), + ROBBER("RO", "#6 - " + _("The Robber"), false), + CORN_CIRCLES_II("C2", "#7 - " + _("The Corn circles II"), new Class[] { CornCircleCapability.class }); + + //promo/one tile expansions + //LA_PORXADA("PX", _("La porxada"), false), + //SCHOOL("SC", _("The school"), false); + + String code; + String label; + boolean enabled = true; + Class[] capabilities; + + Expansion(String code, String label) { + this(code, label, null); + } + + Expansion(String code, String label, boolean enabled) { + this(code, label, null); + this.enabled = enabled; + } + + Expansion(String code, String label, Class[] capabilities) { + this.code = code; + this.label = label; + this.capabilities = capabilities == null ? new Class[0] : capabilities; + } + + public String getCode() { + return code; + } + + public boolean isEnabled() { + return enabled; + } + + public Class[] getCapabilities() { + return capabilities; + } + + @Override + public String toString() { + return label; + } + + public static Expansion valueOfCode(String code) { + for (Expansion exp : values()) { + if (exp.code.equals(code)) return exp; + } + return null; + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/FileTeeStream.java b/src/main/java/com/jcloisterzone/FileTeeStream.java index a3bc46c61..d133dc34a 100644 --- a/src/main/java/com/jcloisterzone/FileTeeStream.java +++ b/src/main/java/com/jcloisterzone/FileTeeStream.java @@ -1,53 +1,53 @@ -package com.jcloisterzone; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; - -public class FileTeeStream extends PrintStream { - - PrintStream fileOut; - String fileName; - - public FileTeeStream(PrintStream err, String fileName) { - super(err); - this.fileName = fileName; - } - - @Override - public void write(byte buf[], int off, int len) { - if (fileOut == null && fileName != null) { - try { - fileOut = new PrintStream(new FileOutputStream(fileName), true); - } catch (FileNotFoundException e) { - fileName = null; - e.printStackTrace(); - } - } - super.write(buf, off, len); - if (fileOut != null) { - fileOut.write(buf, off, len); - if (fileOut.checkError()) { - System.err.println("File stream write error."); - fileOut = null; - fileName = null; - } - } - } - - @Override - public void flush() { - super.flush(); - if (fileOut != null) { - fileOut.flush(); - } - } - - @Override - public void close() { - super.close(); - if (fileOut != null) { - fileOut.close(); - } - } -} +package com.jcloisterzone; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; + +public class FileTeeStream extends PrintStream { + + PrintStream fileOut; + String fileName; + + public FileTeeStream(PrintStream err, String fileName) { + super(err); + this.fileName = fileName; + } + + @Override + public void write(byte buf[], int off, int len) { + if (fileOut == null && fileName != null) { + try { + fileOut = new PrintStream(new FileOutputStream(fileName), true); + } catch (FileNotFoundException e) { + fileName = null; + e.printStackTrace(); + } + } + super.write(buf, off, len); + if (fileOut != null) { + fileOut.write(buf, off, len); + if (fileOut.checkError()) { + System.err.println("File stream write error."); + fileOut = null; + fileName = null; + } + } + } + + @Override + public void flush() { + super.flush(); + if (fileOut != null) { + fileOut.flush(); + } + } + + @Override + public void close() { + super.close(); + if (fileOut != null) { + fileOut.close(); + } + } +} diff --git a/src/main/java/com/jcloisterzone/Player.java b/src/main/java/com/jcloisterzone/Player.java index e4286ac50..62a9a1398 100644 --- a/src/main/java/com/jcloisterzone/Player.java +++ b/src/main/java/com/jcloisterzone/Player.java @@ -1,154 +1,154 @@ -package com.jcloisterzone; - -import java.io.Serializable; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.Special; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.PlayerSlot; - - -/** - * Represents one player in game. Contains information about figures, points and - * control informations.
- * - * @author Roman Krejcik - */ -public class Player implements Serializable { - - private static final long serialVersionUID = -7276471952562769832L; - - private int points; - private final Map pointStats = new HashMap<>(); - - private final List followers = new ArrayList(SmallFollower.QUANTITY + 3); - private final List specialMeeples = new ArrayList(3); - private final Iterable meeples = Iterables.concat(followers, specialMeeples); - - - final private String nick; - final private int index; - private PlayerSlot slot; - - public Player(String nick, int index, PlayerSlot slot) { - this.nick = nick; - this.index = index; - this.slot = slot; - } - - public void addMeeple(Meeple meeple) { - if (meeple instanceof Follower) { - followers.add((Follower) meeple); - } else { - specialMeeples.add((Special) meeple); - } - } - - public List getFollowers() { - return followers; - } - - public List getSpecialMeeples() { - return specialMeeples; - } - - public Iterable getMeeples() { - return meeples; - } - - public boolean hasSpecialMeeple(Class clazz) { - assert !Modifier.isAbstract(clazz.getModifiers()); - return Iterables.any(specialMeeples, Predicates.and(MeeplePredicates.inSupply(), MeeplePredicates.type(clazz))); - } - - public boolean hasFollower() { - return Iterables.any(followers, MeeplePredicates.inSupply()); - } - - public boolean hasFollower(Class clazz) { - assert !Modifier.isAbstract(clazz.getModifiers()); - //chcek equality not instanceOf - phantom is subclass of small follower - return Iterables.any(followers, Predicates.and(MeeplePredicates.inSupply(), MeeplePredicates.type(clazz))); - } - - - public Meeple getMeepleFromSupply(Class clazz) { - assert !Modifier.isAbstract(clazz.getModifiers()); - Iterable collection = (Follower.class.isAssignableFrom(clazz) ? followers : specialMeeples); - return Iterables.find(collection, Predicates.and(MeeplePredicates.inSupply(), MeeplePredicates.type(clazz))); - } - - public void addPoints(int points, PointCategory category) { - this.points += points; - if (pointStats.containsKey(category)) { - pointStats.put(category, pointStats.get(category) + points); - } else { - pointStats.put(category, points); - } - } - - public int getPoints() { - return points; - } - - public String getNick() { - return nick; - } - - @Override - public String toString() { - return nick + " " + points; - } - - public int getIndex() { - return index; - } - - public Long getOwnerId() { - return slot.getOwner(); - } - - public PlayerSlot getSlot() { - return slot; - } - public void setSlot(PlayerSlot slot) { - this.slot = slot; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o instanceof Player) { - if (((Player) o).index == index && index != -1) - return true; - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(index, nick); - } - - public void setPoints(int points) { - this.points = points; - } - - - public int getPointsInCategory(PointCategory cat) { - Integer points = pointStats.get(cat); - return points == null ? 0 : points; - } - -} +package com.jcloisterzone; + +import java.io.Serializable; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.Special; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.PlayerSlot; + + +/** + * Represents one player in game. Contains information about figures, points and + * control informations.
+ * + * @author Roman Krejcik + */ +public class Player implements Serializable { + + private static final long serialVersionUID = -7276471952562769832L; + + private int points; + private final Map pointStats = new HashMap<>(); + + private final List followers = new ArrayList(SmallFollower.QUANTITY + 3); + private final List specialMeeples = new ArrayList(3); + private final Iterable meeples = Iterables.concat(followers, specialMeeples); + + + final private String nick; + final private int index; + private PlayerSlot slot; + + public Player(String nick, int index, PlayerSlot slot) { + this.nick = nick; + this.index = index; + this.slot = slot; + } + + public void addMeeple(Meeple meeple) { + if (meeple instanceof Follower) { + followers.add((Follower) meeple); + } else { + specialMeeples.add((Special) meeple); + } + } + + public List getFollowers() { + return followers; + } + + public List getSpecialMeeples() { + return specialMeeples; + } + + public Iterable getMeeples() { + return meeples; + } + + public boolean hasSpecialMeeple(Class clazz) { + assert !Modifier.isAbstract(clazz.getModifiers()); + return Iterables.any(specialMeeples, Predicates.and(MeeplePredicates.inSupply(), MeeplePredicates.type(clazz))); + } + + public boolean hasFollower() { + return Iterables.any(followers, MeeplePredicates.inSupply()); + } + + public boolean hasFollower(Class clazz) { + assert !Modifier.isAbstract(clazz.getModifiers()); + //chcek equality not instanceOf - phantom is subclass of small follower + return Iterables.any(followers, Predicates.and(MeeplePredicates.inSupply(), MeeplePredicates.type(clazz))); + } + + + public Meeple getMeepleFromSupply(Class clazz) { + assert !Modifier.isAbstract(clazz.getModifiers()); + Iterable collection = (Follower.class.isAssignableFrom(clazz) ? followers : specialMeeples); + return Iterables.find(collection, Predicates.and(MeeplePredicates.inSupply(), MeeplePredicates.type(clazz))); + } + + public void addPoints(int points, PointCategory category) { + this.points += points; + if (pointStats.containsKey(category)) { + pointStats.put(category, pointStats.get(category) + points); + } else { + pointStats.put(category, points); + } + } + + public int getPoints() { + return points; + } + + public String getNick() { + return nick; + } + + @Override + public String toString() { + return nick + " " + points; + } + + public int getIndex() { + return index; + } + + public Long getOwnerId() { + return slot.getOwner(); + } + + public PlayerSlot getSlot() { + return slot; + } + public void setSlot(PlayerSlot slot) { + this.slot = slot; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o instanceof Player) { + if (((Player) o).index == index && index != -1) + return true; + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(index, nick); + } + + public void setPoints(int points) { + this.points = points; + } + + + public int getPointsInCategory(PointCategory cat) { + Integer points = pointStats.get(cat); + return points == null ? 0 : points; + } + +} diff --git a/src/main/java/com/jcloisterzone/PlayerRestriction.java b/src/main/java/com/jcloisterzone/PlayerRestriction.java index c2a27f1b9..32cda8648 100644 --- a/src/main/java/com/jcloisterzone/PlayerRestriction.java +++ b/src/main/java/com/jcloisterzone/PlayerRestriction.java @@ -1,32 +1,32 @@ -package com.jcloisterzone; - -/** represents set of players with rights to something */ -public class PlayerRestriction { - - final Player include; - final Player exclude; - - private PlayerRestriction(Player include, Player exclude) { - this.include = include; - this.exclude = exclude; - } - - public static PlayerRestriction any() { - return new PlayerRestriction(null, null); - } - - public static PlayerRestriction only(Player p) { - return new PlayerRestriction(p, null); - } - - public static PlayerRestriction except(Player p) { - return new PlayerRestriction(null, p); - } - - public boolean isAllowed(Player p) { - if (exclude != null && p.equals(exclude)) return false; - if (include != null && !p.equals(include)) return false; - return true; - } - -} +package com.jcloisterzone; + +/** represents set of players with rights to something */ +public class PlayerRestriction { + + final Player include; + final Player exclude; + + private PlayerRestriction(Player include, Player exclude) { + this.include = include; + this.exclude = exclude; + } + + public static PlayerRestriction any() { + return new PlayerRestriction(null, null); + } + + public static PlayerRestriction only(Player p) { + return new PlayerRestriction(p, null); + } + + public static PlayerRestriction except(Player p) { + return new PlayerRestriction(null, p); + } + + public boolean isAllowed(Player p) { + if (exclude != null && p.equals(exclude)) return false; + if (include != null && !p.equals(include)) return false; + return true; + } + +} diff --git a/src/main/java/com/jcloisterzone/PointCategory.java b/src/main/java/com/jcloisterzone/PointCategory.java index 43a70aa84..e52abc2eb 100644 --- a/src/main/java/com/jcloisterzone/PointCategory.java +++ b/src/main/java/com/jcloisterzone/PointCategory.java @@ -1,19 +1,19 @@ -package com.jcloisterzone; - -public enum PointCategory { - - ROAD, - CITY, - FARM, - CLOISTER, - CASTLE, - - TRADE_GOODS, - FAIRY, - TOWER_RANSOM, - BIGGEST_CITY, - LONGEST_ROAD, - BAZAAR_AUCTION, - WIND_ROSE - -} +package com.jcloisterzone; + +public enum PointCategory { + + ROAD, + CITY, + FARM, + CLOISTER, + CASTLE, + + TRADE_GOODS, + FAIRY, + TOWER_RANSOM, + BIGGEST_CITY, + LONGEST_ROAD, + BAZAAR_AUCTION, + WIND_ROSE + +} diff --git a/src/main/java/com/jcloisterzone/TradeResource.java b/src/main/java/com/jcloisterzone/TradeResource.java index 92940ac15..1112829e5 100644 --- a/src/main/java/com/jcloisterzone/TradeResource.java +++ b/src/main/java/com/jcloisterzone/TradeResource.java @@ -1,9 +1,9 @@ -package com.jcloisterzone; - -public enum TradeResource { - - WINE, - CLOTH, - GRAIN - -} +package com.jcloisterzone; + +public enum TradeResource { + + WINE, + CLOTH, + GRAIN + +} diff --git a/src/main/java/com/jcloisterzone/UserInterface.java b/src/main/java/com/jcloisterzone/UserInterface.java index fafe9fa35..b98197adc 100644 --- a/src/main/java/com/jcloisterzone/UserInterface.java +++ b/src/main/java/com/jcloisterzone/UserInterface.java @@ -1,26 +1,26 @@ -package com.jcloisterzone; - -import java.util.EventListener; -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Position; - - -public interface UserInterface extends EventListener { - - void selectAction(List actions, boolean canPass); - void selectBazaarTile(); - void makeBazaarBid(int supplyIndex); - void selectBuyOrSellBazaarOffer(int supplyIndex); - void selectCornCircleOption(); - - void showWarning(String title, String message); - - //TODO deprecated - use unified interface - void selectDragonMove(Set positions, int movesLeft); - - - -} +package com.jcloisterzone; + +import java.util.EventListener; +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Position; + + +public interface UserInterface extends EventListener { + + void selectAction(List actions, boolean canPass); + void selectBazaarTile(); + void makeBazaarBid(int supplyIndex); + void selectBuyOrSellBazaarOffer(int supplyIndex); + void selectCornCircleOption(); + + void showWarning(String title, String message); + + //TODO deprecated - use unified interface + void selectDragonMove(Set positions, int movesLeft); + + + +} diff --git a/src/main/java/com/jcloisterzone/VersionComparator.java b/src/main/java/com/jcloisterzone/VersionComparator.java index 9a0536262..3ad78e8cc 100644 --- a/src/main/java/com/jcloisterzone/VersionComparator.java +++ b/src/main/java/com/jcloisterzone/VersionComparator.java @@ -1,129 +1,129 @@ -package com.jcloisterzone; - -import java.util.Comparator; - -public class VersionComparator implements Comparator { - - public int compare(String version1, String version2) { - VersionTokenizer tokenizer1 = new VersionTokenizer(version1); - VersionTokenizer tokenizer2 = new VersionTokenizer(version2); - - int number1 = 0, number2 = 0; - String suffix1 = "", suffix2 = ""; - - while (tokenizer1.MoveNext()) { - if (!tokenizer2.MoveNext()) { - do { - number1 = tokenizer1.getNumber(); - suffix1 = tokenizer1.getSuffix(); - if (number1 != 0 || suffix1.length() != 0) { - // Version one is longer than number two, and non-zero - return 1; - } - } - while (tokenizer1.MoveNext()); - - // Version one is longer than version two, but zero - return 0; - } - - number1 = tokenizer1.getNumber(); - suffix1 = tokenizer1.getSuffix(); - number2 = tokenizer2.getNumber(); - suffix2 = tokenizer2.getSuffix(); - - if (number1 < number2) { - // Number one is less than number two - return -1; - } - if (number1 > number2) { - // Number one is greater than number two - return 1; - } - - boolean empty1 = suffix1.length() == 0; - boolean empty2 = suffix2.length() == 0; - - if (empty1 && empty2) continue; // No suffixes - if (empty1) return 1; // First suffix is empty (1.2 > 1.2b) - if (empty2) return -1; // Second suffix is empty (1.2a < 1.2) - - // Lexical comparison of suffixes - int result = suffix1.compareTo(suffix2); - if (result != 0) return result; - - } - if (tokenizer2.MoveNext()) { - do { - number2 = tokenizer2.getNumber(); - suffix2 = tokenizer2.getSuffix(); - if (number2 != 0 || suffix2.length() != 0) { - // Version one is longer than version two, and non-zero - return -1; - } - } - while (tokenizer2.MoveNext()); - - // Version two is longer than version one, but zero - return 0; - } - return 0; - } - - private static class VersionTokenizer { - private final String _versionString; - private final int _length; - - private int _position; - private int _number; - private String _suffix; - - public int getNumber() { - return _number; - } - - public String getSuffix() { - return _suffix; - } - - public VersionTokenizer(String versionString) { - if (versionString == null) - throw new IllegalArgumentException("versionString is null"); - - _versionString = versionString; - _length = versionString.length(); - } - - public boolean MoveNext() { - _number = 0; - _suffix = ""; - - // No more characters - if (_position >= _length) - return false; - - - - while (_position < _length) { - char c = _versionString.charAt(_position); - if (c < '0' || c > '9') break; - _number = _number * 10 + (c - '0'); - _position++; - } - - int suffixStart = _position; - - while (_position < _length) { - char c = _versionString.charAt(_position); - if (c == '.') break; - _position++; - } - - _suffix = _versionString.substring(suffixStart, _position); - - if (_position < _length) _position++; - - return true; - } - } +package com.jcloisterzone; + +import java.util.Comparator; + +public class VersionComparator implements Comparator { + + public int compare(String version1, String version2) { + VersionTokenizer tokenizer1 = new VersionTokenizer(version1); + VersionTokenizer tokenizer2 = new VersionTokenizer(version2); + + int number1 = 0, number2 = 0; + String suffix1 = "", suffix2 = ""; + + while (tokenizer1.MoveNext()) { + if (!tokenizer2.MoveNext()) { + do { + number1 = tokenizer1.getNumber(); + suffix1 = tokenizer1.getSuffix(); + if (number1 != 0 || suffix1.length() != 0) { + // Version one is longer than number two, and non-zero + return 1; + } + } + while (tokenizer1.MoveNext()); + + // Version one is longer than version two, but zero + return 0; + } + + number1 = tokenizer1.getNumber(); + suffix1 = tokenizer1.getSuffix(); + number2 = tokenizer2.getNumber(); + suffix2 = tokenizer2.getSuffix(); + + if (number1 < number2) { + // Number one is less than number two + return -1; + } + if (number1 > number2) { + // Number one is greater than number two + return 1; + } + + boolean empty1 = suffix1.length() == 0; + boolean empty2 = suffix2.length() == 0; + + if (empty1 && empty2) continue; // No suffixes + if (empty1) return 1; // First suffix is empty (1.2 > 1.2b) + if (empty2) return -1; // Second suffix is empty (1.2a < 1.2) + + // Lexical comparison of suffixes + int result = suffix1.compareTo(suffix2); + if (result != 0) return result; + + } + if (tokenizer2.MoveNext()) { + do { + number2 = tokenizer2.getNumber(); + suffix2 = tokenizer2.getSuffix(); + if (number2 != 0 || suffix2.length() != 0) { + // Version one is longer than version two, and non-zero + return -1; + } + } + while (tokenizer2.MoveNext()); + + // Version two is longer than version one, but zero + return 0; + } + return 0; + } + + private static class VersionTokenizer { + private final String _versionString; + private final int _length; + + private int _position; + private int _number; + private String _suffix; + + public int getNumber() { + return _number; + } + + public String getSuffix() { + return _suffix; + } + + public VersionTokenizer(String versionString) { + if (versionString == null) + throw new IllegalArgumentException("versionString is null"); + + _versionString = versionString; + _length = versionString.length(); + } + + public boolean MoveNext() { + _number = 0; + _suffix = ""; + + // No more characters + if (_position >= _length) + return false; + + + + while (_position < _length) { + char c = _versionString.charAt(_position); + if (c < '0' || c > '9') break; + _number = _number * 10 + (c - '0'); + _position++; + } + + int suffixStart = _position; + + while (_position < _length) { + char c = _versionString.charAt(_position); + if (c == '.') break; + _position++; + } + + _suffix = _versionString.substring(suffixStart, _position); + + if (_position < _length) _position++; + + return true; + } + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/XmlUtils.java b/src/main/java/com/jcloisterzone/XmlUtils.java index 20504eeb4..a2ae4bb30 100644 --- a/src/main/java/com/jcloisterzone/XmlUtils.java +++ b/src/main/java/com/jcloisterzone/XmlUtils.java @@ -1,151 +1,151 @@ -package com.jcloisterzone; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.net.URL; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.game.SnapshotCorruptedException; - - -public class XmlUtils { - -// public static Document parseDocument(String fileName) { -// URL url = XmlUtils.class.getClassLoader().getResource(fileName); -// return XmlUtils.parseDocument(url); -// } - - public static Document parseDocument(URL url) { - try (InputStream is = url.openStream()){ - return XmlUtils.parseDocument(is); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static Document parseDocument(InputStream is) { - try { - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - docBuilderFactory.setNamespaceAware(true); - DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); - return docBuilder.parse(is); - } catch (ParserConfigurationException | SAXException | IOException e) { - throw new RuntimeException(e); - } - } - - public static Document newDocument() { - try { - DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); - docBuilderFactory.setNamespaceAware(true); - DocumentBuilder builder = docBuilderFactory.newDocumentBuilder(); - return builder.newDocument(); - } catch (ParserConfigurationException e) { - throw new RuntimeException(e); - } - } - - public static String childValue(Element parent, String childName) { - NodeList nl = parent.getElementsByTagName(childName); - if (nl.getLength() == 0) return null; - return nl.item(0).getTextContent(); - } - - public static String nodeToString(Node node) { - StringWriter sw = new StringWriter(); - try { - Transformer t = TransformerFactory.newInstance().newTransformer(); - t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - t.setOutputProperty(OutputKeys.INDENT, "yes"); - t.transform(new DOMSource(node), new StreamResult(sw)); - } catch (TransformerException te) { - throw new RuntimeException(te); - } - return sw.toString(); - } - - public static String[] asLocation(Element e) { - return e.getFirstChild().getNodeValue().trim().split("\\s+"); - } - - public static String[] asLocations(Element e, String attr) { - return e.getAttribute(attr).trim().split("\\s+"); - } - - public static String getTileId(Expansion expansion, Element xml) { - return expansion.getCode() + "." + xml.getAttribute("id"); - } - - public static Location union(String[] locations) { - Location u = null; - for (String locStr : locations) { - Location loc = Location.valueOf(locStr); - u = loc.union(u); - } - return u; - } - - public static boolean attributeBoolValue(Element e, String attr) { - return e.getAttribute(attr).equals("yes") || e.getAttribute(attr).equals("true") || e.getAttribute(attr).equals("1"); - } - - public static int attributeIntValue(Element e, String attr) { - return attributeIntValue(e, attr, null); - } - - public static int attributeIntValue(Element e, String attr, Integer defaultValue) { - if (!e.hasAttribute(attr)) { - return defaultValue; - } - if (e.getAttribute(attr).equals("yes") || e.getAttribute(attr).equals("true")) { - return 1; - } - return Integer.parseInt(e.getAttribute(attr)); - } - - public static String attributeStringValue(Element e, String attr, String defaultValue) { - if (!e.hasAttribute(attr)) { - return defaultValue; - } - return e.getAttribute(attr); - } - - // Snapshot xml utils - - public static Class classForName(String className) throws SnapshotCorruptedException { - try { - return Class.forName(className); - } catch (ClassNotFoundException e) { - throw new SnapshotCorruptedException(e); - } - } - - public static void injectPosition(Element el, Position p) { - el.setAttribute("x", "" + p.x); - el.setAttribute("y", "" + p.y); - } - - public static Position extractPosition(Element el) { - int x = Integer.parseInt(el.getAttribute("x")); - int y = Integer.parseInt(el.getAttribute("y")); - return new Position(x, y); - } -} +package com.jcloisterzone; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.URL; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.game.SnapshotCorruptedException; + + +public class XmlUtils { + +// public static Document parseDocument(String fileName) { +// URL url = XmlUtils.class.getClassLoader().getResource(fileName); +// return XmlUtils.parseDocument(url); +// } + + public static Document parseDocument(URL url) { + try (InputStream is = url.openStream()){ + return XmlUtils.parseDocument(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Document parseDocument(InputStream is) { + try { + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + docBuilderFactory.setNamespaceAware(true); + DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); + return docBuilder.parse(is); + } catch (ParserConfigurationException | SAXException | IOException e) { + throw new RuntimeException(e); + } + } + + public static Document newDocument() { + try { + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + docBuilderFactory.setNamespaceAware(true); + DocumentBuilder builder = docBuilderFactory.newDocumentBuilder(); + return builder.newDocument(); + } catch (ParserConfigurationException e) { + throw new RuntimeException(e); + } + } + + public static String childValue(Element parent, String childName) { + NodeList nl = parent.getElementsByTagName(childName); + if (nl.getLength() == 0) return null; + return nl.item(0).getTextContent(); + } + + public static String nodeToString(Node node) { + StringWriter sw = new StringWriter(); + try { + Transformer t = TransformerFactory.newInstance().newTransformer(); + t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + t.transform(new DOMSource(node), new StreamResult(sw)); + } catch (TransformerException te) { + throw new RuntimeException(te); + } + return sw.toString(); + } + + public static String[] asLocation(Element e) { + return e.getFirstChild().getNodeValue().trim().split("\\s+"); + } + + public static String[] asLocations(Element e, String attr) { + return e.getAttribute(attr).trim().split("\\s+"); + } + + public static String getTileId(Expansion expansion, Element xml) { + return expansion.getCode() + "." + xml.getAttribute("id"); + } + + public static Location union(String[] locations) { + Location u = null; + for (String locStr : locations) { + Location loc = Location.valueOf(locStr); + u = loc.union(u); + } + return u; + } + + public static boolean attributeBoolValue(Element e, String attr) { + return e.getAttribute(attr).equals("yes") || e.getAttribute(attr).equals("true") || e.getAttribute(attr).equals("1"); + } + + public static int attributeIntValue(Element e, String attr) { + return attributeIntValue(e, attr, null); + } + + public static int attributeIntValue(Element e, String attr, Integer defaultValue) { + if (!e.hasAttribute(attr)) { + return defaultValue; + } + if (e.getAttribute(attr).equals("yes") || e.getAttribute(attr).equals("true")) { + return 1; + } + return Integer.parseInt(e.getAttribute(attr)); + } + + public static String attributeStringValue(Element e, String attr, String defaultValue) { + if (!e.hasAttribute(attr)) { + return defaultValue; + } + return e.getAttribute(attr); + } + + // Snapshot xml utils + + public static Class classForName(String className) throws SnapshotCorruptedException { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw new SnapshotCorruptedException(e); + } + } + + public static void injectPosition(Element el, Position p) { + el.setAttribute("x", "" + p.x); + el.setAttribute("y", "" + p.y); + } + + public static Position extractPosition(Element el) { + int x = Integer.parseInt(el.getAttribute("x")); + int y = Integer.parseInt(el.getAttribute("y")); + return new Position(x, y); + } +} diff --git a/src/main/java/com/jcloisterzone/action/AbbeyPlacementAction.java b/src/main/java/com/jcloisterzone/action/AbbeyPlacementAction.java index d038502ed..121bc4d64 100644 --- a/src/main/java/com/jcloisterzone/action/AbbeyPlacementAction.java +++ b/src/main/java/com/jcloisterzone/action/AbbeyPlacementAction.java @@ -1,34 +1,34 @@ -package com.jcloisterzone.action; - -import java.awt.Image; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.rmi.Client2ClientIF; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.layer.AbbeyPlacementLayer; - -public class AbbeyPlacementAction extends SelectTileAction { - - public AbbeyPlacementAction(Set sites) { - super("abbeyplacement", sites); - } - - @Override - public Image getImage(Player player, boolean active) { - return client.getResourceManager().getAbbeyImage(); - } - - @Override - public void perform(Client2ClientIF server, Position p) { - server.placeTile(Rotation.R0, p); - } - - @Override - protected GridLayer createGridLayer() { - return new AbbeyPlacementLayer(client.getGridPanel(), this); - } - -} +package com.jcloisterzone.action; + +import java.awt.Image; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.rmi.Client2ClientIF; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.layer.AbbeyPlacementLayer; + +public class AbbeyPlacementAction extends SelectTileAction { + + public AbbeyPlacementAction(Set sites) { + super("abbeyplacement", sites); + } + + @Override + public Image getImage(Player player, boolean active) { + return client.getResourceManager().getAbbeyImage(); + } + + @Override + public void perform(Client2ClientIF server, Position p) { + server.placeTile(Rotation.R0, p); + } + + @Override + protected GridLayer createGridLayer() { + return new AbbeyPlacementLayer(client.getGridPanel(), this); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/BarnAction.java b/src/main/java/com/jcloisterzone/action/BarnAction.java index d015d7f91..99e6dd134 100644 --- a/src/main/java/com/jcloisterzone/action/BarnAction.java +++ b/src/main/java/com/jcloisterzone/action/BarnAction.java @@ -1,30 +1,30 @@ -package com.jcloisterzone.action; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.rmi.Client2ClientIF; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.layer.BarnAreaLayer; - - -public class BarnAction extends SelectFeatureAction { - - public BarnAction() { - super("barn"); - } - - public void perform(Client2ClientIF server, Position p, Location d) { - server.deployMeeple(p, d, Barn.class); - } - - @Override - protected GridLayer createGridLayer() { - return new BarnAreaLayer(client.getGridPanel(), this); - } - - @Override - protected int getSortOrder() { - return 9; - } -} +package com.jcloisterzone.action; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.rmi.Client2ClientIF; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.layer.BarnAreaLayer; + + +public class BarnAction extends SelectFeatureAction { + + public BarnAction() { + super("barn"); + } + + public void perform(Client2ClientIF server, Position p, Location d) { + server.deployMeeple(p, d, Barn.class); + } + + @Override + protected GridLayer createGridLayer() { + return new BarnAreaLayer(client.getGridPanel(), this); + } + + @Override + protected int getSortOrder() { + return 9; + } +} diff --git a/src/main/java/com/jcloisterzone/action/BridgeAction.java b/src/main/java/com/jcloisterzone/action/BridgeAction.java index 4f5d479bf..a2b77cc53 100644 --- a/src/main/java/com/jcloisterzone/action/BridgeAction.java +++ b/src/main/java/com/jcloisterzone/action/BridgeAction.java @@ -1,18 +1,18 @@ -package com.jcloisterzone.action; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.rmi.Client2ClientIF; - -public class BridgeAction extends SelectFeatureAction { - - public BridgeAction() { - super("bridge"); - } - - @Override - public void perform(Client2ClientIF server, Position p, Location loc) { - server.deployBridge(p, loc); - } - -} +package com.jcloisterzone.action; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.rmi.Client2ClientIF; + +public class BridgeAction extends SelectFeatureAction { + + public BridgeAction() { + super("bridge"); + } + + @Override + public void perform(Client2ClientIF server, Position p, Location loc) { + server.deployBridge(p, loc); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/CastleAction.java b/src/main/java/com/jcloisterzone/action/CastleAction.java index 45a8343d1..1871d26a7 100644 --- a/src/main/java/com/jcloisterzone/action/CastleAction.java +++ b/src/main/java/com/jcloisterzone/action/CastleAction.java @@ -1,19 +1,19 @@ -package com.jcloisterzone.action; - -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.rmi.Client2ClientIF; - -public class CastleAction extends SelectFeatureAction { - - public CastleAction( Position position, Set sites) { - super("castle", position, sites); - } - - public void perform(Client2ClientIF server, Position pos, Location loc) { - server.deployCastle(pos, loc); - } - -} +package com.jcloisterzone.action; + +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.rmi.Client2ClientIF; + +public class CastleAction extends SelectFeatureAction { + + public CastleAction( Position position, Set sites) { + super("castle", position, sites); + } + + public void perform(Client2ClientIF server, Position pos, Location loc) { + server.deployCastle(pos, loc); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/FairyAction.java b/src/main/java/com/jcloisterzone/action/FairyAction.java index 78783bb5c..5fbf0e5f3 100644 --- a/src/main/java/com/jcloisterzone/action/FairyAction.java +++ b/src/main/java/com/jcloisterzone/action/FairyAction.java @@ -1,32 +1,32 @@ -package com.jcloisterzone.action; - -import java.awt.Image; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.rmi.Client2ClientIF; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.layer.TileActionLayer; - -public class FairyAction extends SelectTileAction { - - public FairyAction() { - super("fairy"); - } - - @Override - public void perform(Client2ClientIF server, Position p) { - server.moveFairy(p); - } - - @Override - protected int getSortOrder() { - return 30; - } - - @Override - protected GridLayer createGridLayer() { - Image gd = client.getControlsTheme().getActionDecoration("fairy"); - return new TileActionLayer(client.getGridPanel(), this, gd); - } - -} +package com.jcloisterzone.action; + +import java.awt.Image; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.rmi.Client2ClientIF; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.layer.TileActionLayer; + +public class FairyAction extends SelectTileAction { + + public FairyAction() { + super("fairy"); + } + + @Override + public void perform(Client2ClientIF server, Position p) { + server.moveFairy(p); + } + + @Override + protected int getSortOrder() { + return 30; + } + + @Override + protected GridLayer createGridLayer() { + Image gd = client.getControlsTheme().getActionDecoration("fairy"); + return new TileActionLayer(client.getGridPanel(), this, gd); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/MeepleAction.java b/src/main/java/com/jcloisterzone/action/MeepleAction.java index 69d7b8d26..ad1c7221e 100644 --- a/src/main/java/com/jcloisterzone/action/MeepleAction.java +++ b/src/main/java/com/jcloisterzone/action/MeepleAction.java @@ -1,58 +1,58 @@ -package com.jcloisterzone.action; - -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.figure.BigFollower; -import com.jcloisterzone.figure.Builder; -import com.jcloisterzone.figure.Mayor; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Phantom; -import com.jcloisterzone.figure.Pig; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.Wagon; -import com.jcloisterzone.rmi.Client2ClientIF; - -public class MeepleAction extends SelectFeatureAction { - - private final Class meepleType; - - public MeepleAction(Class meepleType) { - super(meepleType.getSimpleName().toLowerCase()); - this.meepleType = meepleType; - } - - public MeepleAction(Class meepleType, LocationsMap sites) { - super(meepleType.getSimpleName().toLowerCase(), sites); - this.meepleType = meepleType; - } - - public MeepleAction(Class meepleType, Position p, Set locations) { - super(meepleType.getSimpleName().toLowerCase(), p, locations); - this.meepleType = meepleType; - } - - public Class getMeepleType() { - return meepleType; - } - - @Override - public void perform(Client2ClientIF server, Position p, Location d) { - server.deployMeeple(p, d, meepleType); - } - - @Override - protected int getSortOrder() { - if (meepleType.equals(SmallFollower.class)) return 10; - if (meepleType.equals(BigFollower.class)) return 11; - if (meepleType.equals(Wagon.class)) return 12; - if (meepleType.equals(Mayor.class)) return 13; - if (meepleType.equals(Builder.class)) return 14; - if (meepleType.equals(Pig.class)) return 15; - if (meepleType.equals(Phantom.class)) return 16; - return 19; - } - -} +package com.jcloisterzone.action; + +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.figure.BigFollower; +import com.jcloisterzone.figure.Builder; +import com.jcloisterzone.figure.Mayor; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Phantom; +import com.jcloisterzone.figure.Pig; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.Wagon; +import com.jcloisterzone.rmi.Client2ClientIF; + +public class MeepleAction extends SelectFeatureAction { + + private final Class meepleType; + + public MeepleAction(Class meepleType) { + super(meepleType.getSimpleName().toLowerCase()); + this.meepleType = meepleType; + } + + public MeepleAction(Class meepleType, LocationsMap sites) { + super(meepleType.getSimpleName().toLowerCase(), sites); + this.meepleType = meepleType; + } + + public MeepleAction(Class meepleType, Position p, Set locations) { + super(meepleType.getSimpleName().toLowerCase(), p, locations); + this.meepleType = meepleType; + } + + public Class getMeepleType() { + return meepleType; + } + + @Override + public void perform(Client2ClientIF server, Position p, Location d) { + server.deployMeeple(p, d, meepleType); + } + + @Override + protected int getSortOrder() { + if (meepleType.equals(SmallFollower.class)) return 10; + if (meepleType.equals(BigFollower.class)) return 11; + if (meepleType.equals(Wagon.class)) return 12; + if (meepleType.equals(Mayor.class)) return 13; + if (meepleType.equals(Builder.class)) return 14; + if (meepleType.equals(Pig.class)) return 15; + if (meepleType.equals(Phantom.class)) return 16; + return 19; + } + +} diff --git a/src/main/java/com/jcloisterzone/action/PlayerAction.java b/src/main/java/com/jcloisterzone/action/PlayerAction.java index 64e87235b..6ccaf9014 100644 --- a/src/main/java/com/jcloisterzone/action/PlayerAction.java +++ b/src/main/java/com/jcloisterzone/action/PlayerAction.java @@ -1,77 +1,77 @@ -package com.jcloisterzone.action; - -import java.awt.Color; -import java.awt.Image; - -import com.jcloisterzone.Player; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.grid.ForwardBackwardListener; -import com.jcloisterzone.ui.grid.GridLayer; - -public abstract class PlayerAction implements Comparable, ForwardBackwardListener { - - private final String name; - - protected Client client; - private GridLayer gridLayer; - - public PlayerAction(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public Image getImage(Player player, boolean active) { - return getImage(active ? client.getPlayerColor(player) : Color.GRAY); - } - - protected GridLayer createGridLayer() { - return null; - } - - /** Called when user select action in action panel */ - public void select() { - gridLayer = createGridLayer(); - if (gridLayer != null) { - client.getGridPanel().addLayer(gridLayer); - } - } - - /** Called when user deselect action in action panel */ - public void deselect() { - if (gridLayer != null) { - client.getGridPanel().clearActionDecorations(); - gridLayer = null; - } - } - - /** Called after right mouse click */ - public void forward() { - client.getControlPanel().getActionPanel().rollAction(1); - } - - public void backward() { - client.getControlPanel().getActionPanel().rollAction(-1); - } - - protected Image getImage(Color color) { - return client.getFigureTheme().getActionImage(this, color); - } - - - protected int getSortOrder() { - return 1024; - } - - @Override - public int compareTo(PlayerAction o) { - return getSortOrder() - o.getSortOrder(); - } - - public void setClient(Client client) { - this.client = client; - } - -} +package com.jcloisterzone.action; + +import java.awt.Color; +import java.awt.Image; + +import com.jcloisterzone.Player; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.grid.ForwardBackwardListener; +import com.jcloisterzone.ui.grid.GridLayer; + +public abstract class PlayerAction implements Comparable, ForwardBackwardListener { + + private final String name; + + protected Client client; + private GridLayer gridLayer; + + public PlayerAction(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public Image getImage(Player player, boolean active) { + return getImage(active ? client.getPlayerColor(player) : Color.GRAY); + } + + protected GridLayer createGridLayer() { + return null; + } + + /** Called when user select action in action panel */ + public void select() { + gridLayer = createGridLayer(); + if (gridLayer != null) { + client.getGridPanel().addLayer(gridLayer); + } + } + + /** Called when user deselect action in action panel */ + public void deselect() { + if (gridLayer != null) { + client.getGridPanel().clearActionDecorations(); + gridLayer = null; + } + } + + /** Called after right mouse click */ + public void forward() { + client.getControlPanel().getActionPanel().rollAction(1); + } + + public void backward() { + client.getControlPanel().getActionPanel().rollAction(-1); + } + + protected Image getImage(Color color) { + return client.getFigureTheme().getActionImage(this, color); + } + + + protected int getSortOrder() { + return 1024; + } + + @Override + public int compareTo(PlayerAction o) { + return getSortOrder() - o.getSortOrder(); + } + + public void setClient(Client client) { + this.client = client; + } + +} diff --git a/src/main/java/com/jcloisterzone/action/PrincessAction.java b/src/main/java/com/jcloisterzone/action/PrincessAction.java index a358c052f..ac7abfea7 100644 --- a/src/main/java/com/jcloisterzone/action/PrincessAction.java +++ b/src/main/java/com/jcloisterzone/action/PrincessAction.java @@ -1,16 +1,16 @@ -package com.jcloisterzone.action; - -import com.jcloisterzone.PlayerRestriction; - - -public class PrincessAction extends UndeployAction { - - public PrincessAction() { - super("princess", PlayerRestriction.any()); - } - - @Override - protected int getSortOrder() { - return 1; - } -} +package com.jcloisterzone.action; + +import com.jcloisterzone.PlayerRestriction; + + +public class PrincessAction extends UndeployAction { + + public PrincessAction() { + super("princess", PlayerRestriction.any()); + } + + @Override + protected int getSortOrder() { + return 1; + } +} diff --git a/src/main/java/com/jcloisterzone/action/SelectFeatureAction.java b/src/main/java/com/jcloisterzone/action/SelectFeatureAction.java index 8feddcbe3..e4c4aea77 100644 --- a/src/main/java/com/jcloisterzone/action/SelectFeatureAction.java +++ b/src/main/java/com/jcloisterzone/action/SelectFeatureAction.java @@ -1,56 +1,56 @@ -package com.jcloisterzone.action; - -import java.util.Collections; -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.rmi.Client2ClientIF; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.layer.FeatureAreaLayer; - -public abstract class SelectFeatureAction extends PlayerAction { - - private final LocationsMap locMap; - - public SelectFeatureAction(String name) { - this(name, new LocationsMap()); - } - - public SelectFeatureAction(String name, Position p, Set locations) { - this(name); - locMap.put(p, locations); - } - - public SelectFeatureAction(String name, LocationsMap sites) { - super(name); - this.locMap = sites; - } - - public LocationsMap getLocationsMap() { - return locMap; - } - - public Set get(Position p) { - Set locs = locMap.get(p); - return locs != null ? locs : Collections.emptySet(); - } - - public Set getOrCreate(Position p) { - return locMap.getOrCreate(p); - } - - @Override - protected GridLayer createGridLayer() { - return new FeatureAreaLayer(client.getGridPanel(), this); - } - - public abstract void perform(Client2ClientIF server, Position p, Location loc); - - @Override - public String toString() { - return getClass().getSimpleName() + '=' + locMap.toString(); - } - -} +package com.jcloisterzone.action; + +import java.util.Collections; +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.rmi.Client2ClientIF; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.layer.FeatureAreaLayer; + +public abstract class SelectFeatureAction extends PlayerAction { + + private final LocationsMap locMap; + + public SelectFeatureAction(String name) { + this(name, new LocationsMap()); + } + + public SelectFeatureAction(String name, Position p, Set locations) { + this(name); + locMap.put(p, locations); + } + + public SelectFeatureAction(String name, LocationsMap sites) { + super(name); + this.locMap = sites; + } + + public LocationsMap getLocationsMap() { + return locMap; + } + + public Set get(Position p) { + Set locs = locMap.get(p); + return locs != null ? locs : Collections.emptySet(); + } + + public Set getOrCreate(Position p) { + return locMap.getOrCreate(p); + } + + @Override + protected GridLayer createGridLayer() { + return new FeatureAreaLayer(client.getGridPanel(), this); + } + + public abstract void perform(Client2ClientIF server, Position p, Location loc); + + @Override + public String toString() { + return getClass().getSimpleName() + '=' + locMap.toString(); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/SelectFollowerAction.java b/src/main/java/com/jcloisterzone/action/SelectFollowerAction.java index 605558ee4..ea53748a9 100644 --- a/src/main/java/com/jcloisterzone/action/SelectFollowerAction.java +++ b/src/main/java/com/jcloisterzone/action/SelectFollowerAction.java @@ -1,40 +1,40 @@ -package com.jcloisterzone.action; - -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.rmi.Client2ClientIF; - -public abstract class SelectFollowerAction extends SelectFeatureAction { - - /** set null if anybody is allowed */ - private final PlayerRestriction players; - - public SelectFollowerAction(String name, PlayerRestriction players) { - super(name); - this.players = players; - } - - public PlayerRestriction getPlayers() { - return players; - } - - @Override - public final void perform(Client2ClientIF server, Position pos, Location loc) { - List meeples = client.getGame().getBoard().get(pos).getFeature(loc).getMeeples(); - for (Meeple m : meeples) { - if (players.isAllowed(m.getPlayer())) { - perform(server, pos, loc, m.getClass(), m.getPlayer()); - return; - } - } - throw new IllegalStateException("No legal meeple is placed on feature."); - } - - public abstract void perform(Client2ClientIF server, Position pos, Location loc, Class meepleType, Player owner); - -} +package com.jcloisterzone.action; + +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.rmi.Client2ClientIF; + +public abstract class SelectFollowerAction extends SelectFeatureAction { + + /** set null if anybody is allowed */ + private final PlayerRestriction players; + + public SelectFollowerAction(String name, PlayerRestriction players) { + super(name); + this.players = players; + } + + public PlayerRestriction getPlayers() { + return players; + } + + @Override + public final void perform(Client2ClientIF server, Position pos, Location loc) { + List meeples = client.getGame().getBoard().get(pos).getFeature(loc).getMeeples(); + for (Meeple m : meeples) { + if (players.isAllowed(m.getPlayer())) { + perform(server, pos, loc, m.getClass(), m.getPlayer()); + return; + } + } + throw new IllegalStateException("No legal meeple is placed on feature."); + } + + public abstract void perform(Client2ClientIF server, Position pos, Location loc, Class meepleType, Player owner); + +} diff --git a/src/main/java/com/jcloisterzone/action/SelectTileAction.java b/src/main/java/com/jcloisterzone/action/SelectTileAction.java index b4f0da694..7834333de 100644 --- a/src/main/java/com/jcloisterzone/action/SelectTileAction.java +++ b/src/main/java/com/jcloisterzone/action/SelectTileAction.java @@ -1,28 +1,28 @@ -package com.jcloisterzone.action; - -import java.util.HashSet; -import java.util.Set; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.rmi.Client2ClientIF; - -public abstract class SelectTileAction extends PlayerAction { - - private final Set sites; - - public SelectTileAction(String name) { - super(name); - this.sites = new HashSet<>(); - } - - public SelectTileAction(String name, Set sites) { - super(name); - this.sites = sites; - } - - public Set getSites() { - return sites; - } - - public abstract void perform(Client2ClientIF server, Position p); -} +package com.jcloisterzone.action; + +import java.util.HashSet; +import java.util.Set; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.rmi.Client2ClientIF; + +public abstract class SelectTileAction extends PlayerAction { + + private final Set sites; + + public SelectTileAction(String name) { + super(name); + this.sites = new HashSet<>(); + } + + public SelectTileAction(String name, Set sites) { + super(name); + this.sites = sites; + } + + public Set getSites() { + return sites; + } + + public abstract void perform(Client2ClientIF server, Position p); +} diff --git a/src/main/java/com/jcloisterzone/action/TakePrisonerAction.java b/src/main/java/com/jcloisterzone/action/TakePrisonerAction.java index b7c19eef8..64e66954f 100644 --- a/src/main/java/com/jcloisterzone/action/TakePrisonerAction.java +++ b/src/main/java/com/jcloisterzone/action/TakePrisonerAction.java @@ -1,21 +1,21 @@ -package com.jcloisterzone.action; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.rmi.Client2ClientIF; - -public class TakePrisonerAction extends SelectFollowerAction { - - public TakePrisonerAction(PlayerRestriction players) { - super("takeprisoner", players); - } - - @Override - public void perform(Client2ClientIF server, Position pos, Location loc, Class meepleType, Player owner) { - server.takePrisoner(pos, loc, meepleType, owner.getIndex()); - } - -} +package com.jcloisterzone.action; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.rmi.Client2ClientIF; + +public class TakePrisonerAction extends SelectFollowerAction { + + public TakePrisonerAction(PlayerRestriction players) { + super("takeprisoner", players); + } + + @Override + public void perform(Client2ClientIF server, Position pos, Location loc, Class meepleType, Player owner) { + server.takePrisoner(pos, loc, meepleType, owner.getIndex()); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/TilePlacementAction.java b/src/main/java/com/jcloisterzone/action/TilePlacementAction.java index dd809f79d..e77471365 100644 --- a/src/main/java/com/jcloisterzone/action/TilePlacementAction.java +++ b/src/main/java/com/jcloisterzone/action/TilePlacementAction.java @@ -1,82 +1,82 @@ -package com.jcloisterzone.action; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.rmi.Client2ClientIF; -import com.jcloisterzone.ui.UiUtils; -import com.jcloisterzone.ui.controls.ActionPanel; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.layer.TilePlacementLayer; - -public class TilePlacementAction extends PlayerAction { - - private final Tile tile; - private final Map> placements; - - private Rotation tileRotation = Rotation.R0; - - public TilePlacementAction(Tile tile, Map> placements) { - super("tileplacement"); - this.tile = tile; - this.placements = placements; - } - - public Tile getTile() { - return tile; - } - - public Rotation getTileRotation() { - return tileRotation; - } - - public Map> getAvailablePlacements() { - return placements; - } - - @Override - public Image getImage(Player player, boolean active) { - Image img = client.getResourceManager().getTileImage(tile); - int w = img.getWidth(null), h = img.getHeight(null); - BufferedImage bi = UiUtils.newTransparentImage(w, h); - AffineTransform at = tileRotation.getAffineTransform(w); - Graphics2D ig = bi.createGraphics(); - ig.drawImage(img, at, null); - ig.setColor(Color.BLACK); - ig.drawRect(0, 0, w-1, h-1); - return bi; - } - - public void perform(Client2ClientIF server, Rotation rotation, Position p) { - server.placeTile(rotation, p); - } - - @Override - protected GridLayer createGridLayer() { - return new TilePlacementLayer(client.getGridPanel(), this); - } - - @Override - public void forward() { - tileRotation = tileRotation.next(); - ActionPanel panel = client.getControlPanel().getActionPanel(); - panel.refreshImageCache(); - } - - @Override - public void backward() { - tileRotation = tileRotation.prev(); - ActionPanel panel = client.getControlPanel().getActionPanel(); - panel.refreshImageCache(); - } - -} +package com.jcloisterzone.action; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.rmi.Client2ClientIF; +import com.jcloisterzone.ui.UiUtils; +import com.jcloisterzone.ui.controls.ActionPanel; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.layer.TilePlacementLayer; + +public class TilePlacementAction extends PlayerAction { + + private final Tile tile; + private final Map> placements; + + private Rotation tileRotation = Rotation.R0; + + public TilePlacementAction(Tile tile, Map> placements) { + super("tileplacement"); + this.tile = tile; + this.placements = placements; + } + + public Tile getTile() { + return tile; + } + + public Rotation getTileRotation() { + return tileRotation; + } + + public Map> getAvailablePlacements() { + return placements; + } + + @Override + public Image getImage(Player player, boolean active) { + Image img = client.getResourceManager().getTileImage(tile); + int w = img.getWidth(null), h = img.getHeight(null); + BufferedImage bi = UiUtils.newTransparentImage(w, h); + AffineTransform at = tileRotation.getAffineTransform(w); + Graphics2D ig = bi.createGraphics(); + ig.drawImage(img, at, null); + ig.setColor(Color.BLACK); + ig.drawRect(0, 0, w-1, h-1); + return bi; + } + + public void perform(Client2ClientIF server, Rotation rotation, Position p) { + server.placeTile(rotation, p); + } + + @Override + protected GridLayer createGridLayer() { + return new TilePlacementLayer(client.getGridPanel(), this); + } + + @Override + public void forward() { + tileRotation = tileRotation.next(); + ActionPanel panel = client.getControlPanel().getActionPanel(); + panel.refreshImageCache(); + } + + @Override + public void backward() { + tileRotation = tileRotation.prev(); + ActionPanel panel = client.getControlPanel().getActionPanel(); + panel.refreshImageCache(); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/TowerPieceAction.java b/src/main/java/com/jcloisterzone/action/TowerPieceAction.java index 15f7ea49b..9aa4816ce 100644 --- a/src/main/java/com/jcloisterzone/action/TowerPieceAction.java +++ b/src/main/java/com/jcloisterzone/action/TowerPieceAction.java @@ -1,39 +1,39 @@ -package com.jcloisterzone.action; - -import java.awt.Image; -import java.util.Set; - -import com.google.common.collect.Sets; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.rmi.Client2ClientIF; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.layer.TileActionLayer; - - -public class TowerPieceAction extends SelectTileAction { - - public TowerPieceAction() { - this(Sets.newHashSet()); - } - - public TowerPieceAction(Set sites) { - super("towerpiece", sites); - } - - @Override - public void perform(Client2ClientIF server, Position p) { - server.placeTowerPiece(p); - } - - @Override - protected int getSortOrder() { - return 20; - } - - @Override - protected GridLayer createGridLayer() { - Image gd = client.getControlsTheme().getActionDecoration("tower"); - return new TileActionLayer(client.getGridPanel(), this, gd); - } - -} +package com.jcloisterzone.action; + +import java.awt.Image; +import java.util.Set; + +import com.google.common.collect.Sets; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.rmi.Client2ClientIF; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.layer.TileActionLayer; + + +public class TowerPieceAction extends SelectTileAction { + + public TowerPieceAction() { + this(Sets.newHashSet()); + } + + public TowerPieceAction(Set sites) { + super("towerpiece", sites); + } + + @Override + public void perform(Client2ClientIF server, Position p) { + server.placeTowerPiece(p); + } + + @Override + protected int getSortOrder() { + return 20; + } + + @Override + protected GridLayer createGridLayer() { + Image gd = client.getControlsTheme().getActionDecoration("tower"); + return new TileActionLayer(client.getGridPanel(), this, gd); + } + +} diff --git a/src/main/java/com/jcloisterzone/action/TunnelAction.java b/src/main/java/com/jcloisterzone/action/TunnelAction.java index 182306bcc..3e0aa2e1a 100644 --- a/src/main/java/com/jcloisterzone/action/TunnelAction.java +++ b/src/main/java/com/jcloisterzone/action/TunnelAction.java @@ -1,44 +1,44 @@ -package com.jcloisterzone.action; - -import java.awt.Image; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.rmi.Client2ClientIF; - -public class TunnelAction extends SelectFeatureAction { - - private final boolean secondTunnelPiece; - - public TunnelAction(boolean secondTunnelPiece, LocationsMap sites) { - super("tunnel", sites); - this.secondTunnelPiece = secondTunnelPiece; - } - - @Override - public Image getImage(Player player, boolean active) { - if (active && isSecondTunnelPiece()) { - return getImage(client.getPlayerSecondTunelColor(player)); - } else { - return super.getImage(player, active); - } - } - - public boolean isSecondTunnelPiece() { - return secondTunnelPiece; - } - - @Override - public void perform(Client2ClientIF server, Position p, Location d) { - server.placeTunnelPiece(p, d, secondTunnelPiece); - - } - - @Override - protected int getSortOrder() { - return secondTunnelPiece ? 41 : 40; - } - -} +package com.jcloisterzone.action; + +import java.awt.Image; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.rmi.Client2ClientIF; + +public class TunnelAction extends SelectFeatureAction { + + private final boolean secondTunnelPiece; + + public TunnelAction(boolean secondTunnelPiece, LocationsMap sites) { + super("tunnel", sites); + this.secondTunnelPiece = secondTunnelPiece; + } + + @Override + public Image getImage(Player player, boolean active) { + if (active && isSecondTunnelPiece()) { + return getImage(client.getPlayerSecondTunelColor(player)); + } else { + return super.getImage(player, active); + } + } + + public boolean isSecondTunnelPiece() { + return secondTunnelPiece; + } + + @Override + public void perform(Client2ClientIF server, Position p, Location d) { + server.placeTunnelPiece(p, d, secondTunnelPiece); + + } + + @Override + protected int getSortOrder() { + return secondTunnelPiece ? 41 : 40; + } + +} diff --git a/src/main/java/com/jcloisterzone/action/UndeployAction.java b/src/main/java/com/jcloisterzone/action/UndeployAction.java index fa86dfb51..198c8ff1a 100644 --- a/src/main/java/com/jcloisterzone/action/UndeployAction.java +++ b/src/main/java/com/jcloisterzone/action/UndeployAction.java @@ -1,21 +1,21 @@ -package com.jcloisterzone.action; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.rmi.Client2ClientIF; - -public class UndeployAction extends SelectFollowerAction { - - public UndeployAction(String name, PlayerRestriction players) { - super(name, players); - } - - @Override - public void perform(Client2ClientIF server, Position pos, Location loc, Class meepleType, Player owner) { - server.undeployMeeple(pos, loc, meepleType, owner.getIndex()); - } - -} +package com.jcloisterzone.action; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.rmi.Client2ClientIF; + +public class UndeployAction extends SelectFollowerAction { + + public UndeployAction(String name, PlayerRestriction players) { + super(name, players); + } + + @Override + public void perform(Client2ClientIF server, Position pos, Location loc, Class meepleType, Player owner) { + server.undeployMeeple(pos, loc, meepleType, owner.getIndex()); + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/AiPlayer.java b/src/main/java/com/jcloisterzone/ai/AiPlayer.java index d98cca442..a7257eeeb 100644 --- a/src/main/java/com/jcloisterzone/ai/AiPlayer.java +++ b/src/main/java/com/jcloisterzone/ai/AiPlayer.java @@ -1,164 +1,164 @@ -package com.jcloisterzone.ai; - -import java.lang.reflect.Proxy; -import java.util.List; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Player; -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.AbbeyPlacementAction; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.TakePrisonerAction; -import com.jcloisterzone.action.TilePlacementAction; -import com.jcloisterzone.board.Board; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.rmi.ServerIF; -import com.jcloisterzone.rmi.mina.ClientStub; - -public abstract class AiPlayer implements UserInterface { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - protected Game game; - - private ServerIF server; - private ClientStub clientStub; - private Player player; - - public void setGame(Game game) { - this.game = game; - } - - public Game getGame() { - return game; - } - - public ServerIF getServer() { - return server; - } - - public void setServer(ServerIF server) { - Integer placeTileDelay = game.getConfig().get("players", "ai_place_tile_delay", Integer.class); - this.server = new DelayedServer(server, placeTileDelay == null ? 0 : placeTileDelay); - this.clientStub = (ClientStub) Proxy.getInvocationHandler(server); - } - - public Player getPlayer() { - return player; - } - - public void setPlayer(Player player) { - this.player = player; - } - - protected Board getBoard() { - return game.getBoard(); - } - - protected TilePack getTilePack() { - return game.getTilePack(); - } - - protected ClientStub getClientStub() { - return clientStub; - } - - protected boolean isMe(Player p) { - return player.equals(p); - } - - public boolean isAiPlayerActive() { - if (server == null) return false; - return player.equals(game.getActivePlayer()); - } - - @Override - public void showWarning(String title, String message) { - //do nothing - } - - protected void handleRuntimeError(Exception e) { - logger.error("AI player exception", e); - } - - // dummy implementations - - protected final void selectDummyAction(List actions, boolean canPass) { - for (PlayerAction action : actions) { - if (action instanceof TilePlacementAction) { - if (selectDummyTilePlacement((TilePlacementAction) action)) return; - } - if (action instanceof AbbeyPlacementAction) { - if (selectDummyAbbeyPlacement((AbbeyPlacementAction) action)) return; - } - if (action instanceof MeepleAction) { - if (selectDummyMeepleAction((MeepleAction) action)) return; - } - if (action instanceof TakePrisonerAction) { - if (selectDummyTowerCapture((TakePrisonerAction) action)) return; - } - } - getServer().pass(); - } - - protected boolean selectDummyAbbeyPlacement(AbbeyPlacementAction action) { - getServer().pass(); - return true; - } - - protected boolean selectDummyTilePlacement(TilePlacementAction action) { - Position nearest = null, p0 = new Position(0, 0); - int min = Integer.MAX_VALUE; - for (Position pos : action.getAvailablePlacements().keySet()) { - int dist = pos.squareDistance(p0); - if (dist < min) { - min = dist; - nearest = pos; - } - } - getServer().placeTile(action.getAvailablePlacements().get(nearest).iterator().next(), nearest); - return true; - } - - protected boolean selectDummyMeepleAction(MeepleAction ma) { - Position p = ma.getLocationsMap().keySet().iterator().next(); - for (Location loc : ma.getLocationsMap().get(p)) { - Feature f = getBoard().get(p).getFeature(loc); - if (f instanceof City || f instanceof Road || f instanceof Cloister) { - getServer().deployMeeple(p, loc, ma.getMeepleType()); - return true; - } - } - return false; - } - - protected boolean selectDummyTowerCapture(TakePrisonerAction action) { - Position p = action.getLocationsMap().keySet().iterator().next(); - Location loc = action.getLocationsMap().get(p).iterator().next(); - Meeple m = getBoard().get(p).getFeature(loc).getMeeples().get(0); - getServer().takePrisoner(p, loc, m.getClass(), m.getPlayer().getIndex()); - return true; - } - - protected final void selectDummyDragonMove(Set positions, int movesLeft) { - getServer().moveDragon(positions.iterator().next()); - } - - @Override - public String toString() { - return String.valueOf(player); - } - -} +package com.jcloisterzone.ai; + +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Player; +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.AbbeyPlacementAction; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.TakePrisonerAction; +import com.jcloisterzone.action.TilePlacementAction; +import com.jcloisterzone.board.Board; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.rmi.ServerIF; +import com.jcloisterzone.rmi.mina.ClientStub; + +public abstract class AiPlayer implements UserInterface { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + protected Game game; + + private ServerIF server; + private ClientStub clientStub; + private Player player; + + public void setGame(Game game) { + this.game = game; + } + + public Game getGame() { + return game; + } + + public ServerIF getServer() { + return server; + } + + public void setServer(ServerIF server) { + Integer placeTileDelay = game.getConfig().get("players", "ai_place_tile_delay", Integer.class); + this.server = new DelayedServer(server, placeTileDelay == null ? 0 : placeTileDelay); + this.clientStub = (ClientStub) Proxy.getInvocationHandler(server); + } + + public Player getPlayer() { + return player; + } + + public void setPlayer(Player player) { + this.player = player; + } + + protected Board getBoard() { + return game.getBoard(); + } + + protected TilePack getTilePack() { + return game.getTilePack(); + } + + protected ClientStub getClientStub() { + return clientStub; + } + + protected boolean isMe(Player p) { + return player.equals(p); + } + + public boolean isAiPlayerActive() { + if (server == null) return false; + return player.equals(game.getActivePlayer()); + } + + @Override + public void showWarning(String title, String message) { + //do nothing + } + + protected void handleRuntimeError(Exception e) { + logger.error("AI player exception", e); + } + + // dummy implementations + + protected final void selectDummyAction(List actions, boolean canPass) { + for (PlayerAction action : actions) { + if (action instanceof TilePlacementAction) { + if (selectDummyTilePlacement((TilePlacementAction) action)) return; + } + if (action instanceof AbbeyPlacementAction) { + if (selectDummyAbbeyPlacement((AbbeyPlacementAction) action)) return; + } + if (action instanceof MeepleAction) { + if (selectDummyMeepleAction((MeepleAction) action)) return; + } + if (action instanceof TakePrisonerAction) { + if (selectDummyTowerCapture((TakePrisonerAction) action)) return; + } + } + getServer().pass(); + } + + protected boolean selectDummyAbbeyPlacement(AbbeyPlacementAction action) { + getServer().pass(); + return true; + } + + protected boolean selectDummyTilePlacement(TilePlacementAction action) { + Position nearest = null, p0 = new Position(0, 0); + int min = Integer.MAX_VALUE; + for (Position pos : action.getAvailablePlacements().keySet()) { + int dist = pos.squareDistance(p0); + if (dist < min) { + min = dist; + nearest = pos; + } + } + getServer().placeTile(action.getAvailablePlacements().get(nearest).iterator().next(), nearest); + return true; + } + + protected boolean selectDummyMeepleAction(MeepleAction ma) { + Position p = ma.getLocationsMap().keySet().iterator().next(); + for (Location loc : ma.getLocationsMap().get(p)) { + Feature f = getBoard().get(p).getFeature(loc); + if (f instanceof City || f instanceof Road || f instanceof Cloister) { + getServer().deployMeeple(p, loc, ma.getMeepleType()); + return true; + } + } + return false; + } + + protected boolean selectDummyTowerCapture(TakePrisonerAction action) { + Position p = action.getLocationsMap().keySet().iterator().next(); + Location loc = action.getLocationsMap().get(p).iterator().next(); + Meeple m = getBoard().get(p).getFeature(loc).getMeeples().get(0); + getServer().takePrisoner(p, loc, m.getClass(), m.getPlayer().getIndex()); + return true; + } + + protected final void selectDummyDragonMove(Set positions, int movesLeft) { + getServer().moveDragon(positions.iterator().next()); + } + + @Override + public String toString() { + return String.valueOf(player); + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/AiScoreContext.java b/src/main/java/com/jcloisterzone/ai/AiScoreContext.java index 46e7b1433..68b155d49 100644 --- a/src/main/java/com/jcloisterzone/ai/AiScoreContext.java +++ b/src/main/java/com/jcloisterzone/ai/AiScoreContext.java @@ -1,10 +1,10 @@ -package com.jcloisterzone.ai; - -import com.jcloisterzone.feature.visitor.score.ScoreContext; - -public interface AiScoreContext extends ScoreContext { - - boolean isValid(); - void setValid(boolean valid); - -} +package com.jcloisterzone.ai; + +import com.jcloisterzone.feature.visitor.score.ScoreContext; + +public interface AiScoreContext extends ScoreContext { + + boolean isValid(); + void setValid(boolean valid); + +} diff --git a/src/main/java/com/jcloisterzone/ai/AiUserInterfaceAdapter.java b/src/main/java/com/jcloisterzone/ai/AiUserInterfaceAdapter.java index 18346c5b4..8eceb8e97 100644 --- a/src/main/java/com/jcloisterzone/ai/AiUserInterfaceAdapter.java +++ b/src/main/java/com/jcloisterzone/ai/AiUserInterfaceAdapter.java @@ -1,79 +1,79 @@ -package com.jcloisterzone.ai; - -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Position; - -/** - * Dummy fallback prevent application freezing for some AiPlayers implementation errors - */ -public class AiUserInterfaceAdapter implements UserInterface { - - private AiPlayer aiPlayer; - - public AiUserInterfaceAdapter(AiPlayer aiPlayer) { - this.aiPlayer = aiPlayer; - } - - public AiPlayer getAiPlayer() { - return aiPlayer; - } - - public void setAiPlayer(AiPlayer aiPlayer) { - this.aiPlayer = aiPlayer; - } - - @Override - public void selectAction(List actions, boolean canPass) { - if (aiPlayer.isAiPlayerActive()) { - try { - aiPlayer.selectAction(actions, canPass); - } catch (Exception e) { - aiPlayer.handleRuntimeError(e); - aiPlayer.selectDummyAction(actions, canPass); - } - } - } - - @Override - public void selectBazaarTile() { - throw new UnsupportedOperationException(); - } - - @Override - public void makeBazaarBid(int supplyIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectBuyOrSellBazaarOffer(int supplyIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectCornCircleOption() { - throw new UnsupportedOperationException(); - } - - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - if (aiPlayer.isAiPlayerActive()) { - try { - aiPlayer.selectDragonMove(positions, movesLeft); - } catch (Exception e) { - aiPlayer.handleRuntimeError(e); - aiPlayer.selectDummyDragonMove(positions, movesLeft); - } - } - } - - @Override - public void showWarning(String title, String message) { - aiPlayer.showWarning(title, message); - } - -} +package com.jcloisterzone.ai; + +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Position; + +/** + * Dummy fallback prevent application freezing for some AiPlayers implementation errors + */ +public class AiUserInterfaceAdapter implements UserInterface { + + private AiPlayer aiPlayer; + + public AiUserInterfaceAdapter(AiPlayer aiPlayer) { + this.aiPlayer = aiPlayer; + } + + public AiPlayer getAiPlayer() { + return aiPlayer; + } + + public void setAiPlayer(AiPlayer aiPlayer) { + this.aiPlayer = aiPlayer; + } + + @Override + public void selectAction(List actions, boolean canPass) { + if (aiPlayer.isAiPlayerActive()) { + try { + aiPlayer.selectAction(actions, canPass); + } catch (Exception e) { + aiPlayer.handleRuntimeError(e); + aiPlayer.selectDummyAction(actions, canPass); + } + } + } + + @Override + public void selectBazaarTile() { + throw new UnsupportedOperationException(); + } + + @Override + public void makeBazaarBid(int supplyIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectBuyOrSellBazaarOffer(int supplyIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectCornCircleOption() { + throw new UnsupportedOperationException(); + } + + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + if (aiPlayer.isAiPlayerActive()) { + try { + aiPlayer.selectDragonMove(positions, movesLeft); + } catch (Exception e) { + aiPlayer.handleRuntimeError(e); + aiPlayer.selectDummyDragonMove(positions, movesLeft); + } + } + } + + @Override + public void showWarning(String title, String message) { + aiPlayer.showWarning(title, message); + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/DelayedServer.java b/src/main/java/com/jcloisterzone/ai/DelayedServer.java index c15c5ad6c..7d395ae2b 100644 --- a/src/main/java/com/jcloisterzone/ai/DelayedServer.java +++ b/src/main/java/com/jcloisterzone/ai/DelayedServer.java @@ -1,140 +1,140 @@ -package com.jcloisterzone.ai; - -import java.util.EnumSet; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.rmi.ServerIF; - -public class DelayedServer implements ServerIF { - - private final ServerIF server; - private final int placeTileDelay; - - public DelayedServer(ServerIF server, int placeTileDelay) { - this.server = server; - this.placeTileDelay = placeTileDelay; - } - - @Override - public void updateSlot(PlayerSlot slot, - EnumSet supportedExpansions) { - server.updateSlot(slot, supportedExpansions); - } - - @Override - public void selectTiles(int tilesCount, int drawCount) { - server.selectTiles(tilesCount, drawCount); - } - - @Override - public void rollFlierDice() { - server.rollFlierDice(); - } - - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - server.updateExpansion(expansion, enabled); - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - server.updateCustomRule(rule, enabled); - } - - @Override - public void startGame() { - server.startGame(); - } - - @Override - public void pass() { - server.pass(); - } - - @Override - public void placeTile(Rotation rotation, Position position) { - try { - Thread.sleep(placeTileDelay); - } catch (InterruptedException e) {} - server.placeTile(rotation, position); - } - - @Override - public void deployMeeple(Position pos, Location loc, - Class meepleType) { - server.deployMeeple(pos, loc, meepleType); - } - - @Override - public void undeployMeeple(Position pos, Location loc, Class meepleType, Integer meepleOwner) { - server.undeployMeeple(pos, loc, meepleType, meepleOwner); - } - - @Override - public void placeTowerPiece(Position pos) { - server.placeTowerPiece(pos); - } - - @Override - public void takePrisoner(Position pos, Location loc, Class meepleType, Integer meepleOwner) { - server.takePrisoner(pos, loc, meepleType, meepleOwner); - } - - @Override - public void placeTunnelPiece(Position pos, Location loc, - boolean isSecondPiece) { - server.placeTunnelPiece(pos, loc, isSecondPiece); - } - - @Override - public void moveFairy(Position pos) { - server.moveFairy(pos); - } - - @Override - public void moveDragon(Position pos) { - try { - Thread.sleep(placeTileDelay / 2); - } catch (InterruptedException e) {} - server.moveDragon(pos); - } - - @Override - public void payRansom(Integer playerIndexToPay, - Class meepleType) { - server.payRansom(playerIndexToPay, meepleType); - } - - @Override - public void deployBridge(Position pos, Location loc) { - server.deployBridge(pos, loc); - } - - @Override - public void deployCastle(Position pos, Location loc) { - server.deployCastle(pos, loc); - } - - @Override - public void bazaarBid(Integer supplyIndex, Integer price) { - server.bazaarBid(supplyIndex, price); - } - - @Override - public void bazaarBuyOrSell(boolean buy) { - server.bazaarBuyOrSell(buy); - } - - @Override - public void cornCiclesRemoveOrDeploy(boolean remove) { - server.cornCiclesRemoveOrDeploy(remove); - } - +package com.jcloisterzone.ai; + +import java.util.EnumSet; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.rmi.ServerIF; + +public class DelayedServer implements ServerIF { + + private final ServerIF server; + private final int placeTileDelay; + + public DelayedServer(ServerIF server, int placeTileDelay) { + this.server = server; + this.placeTileDelay = placeTileDelay; + } + + @Override + public void updateSlot(PlayerSlot slot, + EnumSet supportedExpansions) { + server.updateSlot(slot, supportedExpansions); + } + + @Override + public void selectTiles(int tilesCount, int drawCount) { + server.selectTiles(tilesCount, drawCount); + } + + @Override + public void rollFlierDice() { + server.rollFlierDice(); + } + + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + server.updateExpansion(expansion, enabled); + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + server.updateCustomRule(rule, enabled); + } + + @Override + public void startGame() { + server.startGame(); + } + + @Override + public void pass() { + server.pass(); + } + + @Override + public void placeTile(Rotation rotation, Position position) { + try { + Thread.sleep(placeTileDelay); + } catch (InterruptedException e) {} + server.placeTile(rotation, position); + } + + @Override + public void deployMeeple(Position pos, Location loc, + Class meepleType) { + server.deployMeeple(pos, loc, meepleType); + } + + @Override + public void undeployMeeple(Position pos, Location loc, Class meepleType, Integer meepleOwner) { + server.undeployMeeple(pos, loc, meepleType, meepleOwner); + } + + @Override + public void placeTowerPiece(Position pos) { + server.placeTowerPiece(pos); + } + + @Override + public void takePrisoner(Position pos, Location loc, Class meepleType, Integer meepleOwner) { + server.takePrisoner(pos, loc, meepleType, meepleOwner); + } + + @Override + public void placeTunnelPiece(Position pos, Location loc, + boolean isSecondPiece) { + server.placeTunnelPiece(pos, loc, isSecondPiece); + } + + @Override + public void moveFairy(Position pos) { + server.moveFairy(pos); + } + + @Override + public void moveDragon(Position pos) { + try { + Thread.sleep(placeTileDelay / 2); + } catch (InterruptedException e) {} + server.moveDragon(pos); + } + + @Override + public void payRansom(Integer playerIndexToPay, + Class meepleType) { + server.payRansom(playerIndexToPay, meepleType); + } + + @Override + public void deployBridge(Position pos, Location loc) { + server.deployBridge(pos, loc); + } + + @Override + public void deployCastle(Position pos, Location loc) { + server.deployCastle(pos, loc); + } + + @Override + public void bazaarBid(Integer supplyIndex, Integer price) { + server.bazaarBid(supplyIndex, price); + } + + @Override + public void bazaarBuyOrSell(boolean buy) { + server.bazaarBuyOrSell(buy); + } + + @Override + public void cornCiclesRemoveOrDeploy(boolean remove) { + server.cornCiclesRemoveOrDeploy(remove); + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ai/DummyAiPlayer.java b/src/main/java/com/jcloisterzone/ai/DummyAiPlayer.java index 00617a63f..7567bba45 100644 --- a/src/main/java/com/jcloisterzone/ai/DummyAiPlayer.java +++ b/src/main/java/com/jcloisterzone/ai/DummyAiPlayer.java @@ -1,41 +1,41 @@ -package com.jcloisterzone.ai; - -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Position; - -public class DummyAiPlayer extends AiPlayer { - - @Override - public void selectAction(List actions, boolean canPass) { - selectDummyAction(actions, canPass); - } - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - selectDummyDragonMove(positions, movesLeft); - } - - @Override - public void selectBazaarTile() { - throw new UnsupportedOperationException(); - } - - @Override - public void makeBazaarBid(int supplyIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectBuyOrSellBazaarOffer(int supplyIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectCornCircleOption() { - throw new UnsupportedOperationException(); - } - -} +package com.jcloisterzone.ai; + +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Position; + +public class DummyAiPlayer extends AiPlayer { + + @Override + public void selectAction(List actions, boolean canPass) { + selectDummyAction(actions, canPass); + } + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + selectDummyDragonMove(positions, movesLeft); + } + + @Override + public void selectBazaarTile() { + throw new UnsupportedOperationException(); + } + + @Override + public void makeBazaarBid(int supplyIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectBuyOrSellBazaarOffer(int supplyIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectCornCircleOption() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/NotSupportedInteraction.java b/src/main/java/com/jcloisterzone/ai/NotSupportedInteraction.java index cfb59f4f3..b73b6a470 100644 --- a/src/main/java/com/jcloisterzone/ai/NotSupportedInteraction.java +++ b/src/main/java/com/jcloisterzone/ai/NotSupportedInteraction.java @@ -1,47 +1,47 @@ -package com.jcloisterzone.ai; - -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Position; - -public class NotSupportedInteraction implements UserInterface { - - @Override - public void selectAction(List actions, boolean canPass) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectBazaarTile() { - throw new UnsupportedOperationException(); - } - - @Override - public void makeBazaarBid(int supplyIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectBuyOrSellBazaarOffer(int supplyIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectCornCircleOption() { - throw new UnsupportedOperationException(); - } - - @Override - public void showWarning(String title, String message) { - throw new UnsupportedOperationException(); - } - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - throw new UnsupportedOperationException(); - } - +package com.jcloisterzone.ai; + +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Position; + +public class NotSupportedInteraction implements UserInterface { + + @Override + public void selectAction(List actions, boolean canPass) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectBazaarTile() { + throw new UnsupportedOperationException(); + } + + @Override + public void makeBazaarBid(int supplyIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectBuyOrSellBazaarOffer(int supplyIndex) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectCornCircleOption() { + throw new UnsupportedOperationException(); + } + + @Override + public void showWarning(String title, String message) { + throw new UnsupportedOperationException(); + } + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + throw new UnsupportedOperationException(); + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ai/PositionRanking.java b/src/main/java/com/jcloisterzone/ai/PositionRanking.java index 14e3b0d83..2abb86bff 100644 --- a/src/main/java/com/jcloisterzone/ai/PositionRanking.java +++ b/src/main/java/com/jcloisterzone/ai/PositionRanking.java @@ -1,110 +1,110 @@ -package com.jcloisterzone.ai; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.figure.Meeple; - -public class PositionRanking { - - public static class SelectedAction { - - public SelectedAction(PlayerAction action) { - this(action, null, null, null, null); - } - - public SelectedAction(PlayerAction action, Position position, Location location) { - this(action, position, location, null, null); - } - - public SelectedAction(PlayerAction action, Position actionPosition, Location actionLocation, Class meepleType, Player meepleOwner) { - this.action = action; - this.position = actionPosition; - this.location = actionLocation; - this.meepleType = meepleType; - this.meepleOwner = meepleOwner; - } - - public PlayerAction action; - public Position position; - public Location location; - public Class meepleType; - public Player meepleOwner; - } - - private double rank; - - private Position position; - private Rotation rotation; - - private Deque selectedActions = new LinkedList<>(); - - - public PositionRanking(double rank) { - this.rank = rank; - } - - public PositionRanking(double rank, Position position, Rotation rotation) { - this.rank = rank; - this.position = position; - this.rotation = rotation; - } - - public double getRank() { - return rank; - } - - public void setRank(double rank) { - this.rank = rank; - } - - public Position getPosition() { - return position; - } - - public void setPosition(Position position) { - this.position = position; - } - - public Rotation getRotation() { - return rotation; - } - - public void setRotation(Rotation rotation) { - this.rotation = rotation; - } - - public Deque getSelectedActions() { - return selectedActions; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(rank); - sb.append(" Pos: ").append(position); - sb.append(" Rot: ").append(rotation); - for (SelectedAction sa : selectedActions) { - if (sa.action instanceof MeepleAction) { - sb.append(" Meeple: ").append(((MeepleAction)sa.action).getMeepleType().getSimpleName()); - sb.append(" APos: ").append(sa.position); - sb.append(" ALoc: ").append(sa.location); - } else { - sb.append(" Action: ").append(sa.action.getName()); - } - } - return sb.toString(); - } - - - -} - +package com.jcloisterzone.ai; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.figure.Meeple; + +public class PositionRanking { + + public static class SelectedAction { + + public SelectedAction(PlayerAction action) { + this(action, null, null, null, null); + } + + public SelectedAction(PlayerAction action, Position position, Location location) { + this(action, position, location, null, null); + } + + public SelectedAction(PlayerAction action, Position actionPosition, Location actionLocation, Class meepleType, Player meepleOwner) { + this.action = action; + this.position = actionPosition; + this.location = actionLocation; + this.meepleType = meepleType; + this.meepleOwner = meepleOwner; + } + + public PlayerAction action; + public Position position; + public Location location; + public Class meepleType; + public Player meepleOwner; + } + + private double rank; + + private Position position; + private Rotation rotation; + + private Deque selectedActions = new LinkedList<>(); + + + public PositionRanking(double rank) { + this.rank = rank; + } + + public PositionRanking(double rank, Position position, Rotation rotation) { + this.rank = rank; + this.position = position; + this.rotation = rotation; + } + + public double getRank() { + return rank; + } + + public void setRank(double rank) { + this.rank = rank; + } + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + + public Rotation getRotation() { + return rotation; + } + + public void setRotation(Rotation rotation) { + this.rotation = rotation; + } + + public Deque getSelectedActions() { + return selectedActions; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(rank); + sb.append(" Pos: ").append(position); + sb.append(" Rot: ").append(rotation); + for (SelectedAction sa : selectedActions) { + if (sa.action instanceof MeepleAction) { + sb.append(" Meeple: ").append(((MeepleAction)sa.action).getMeepleType().getSimpleName()); + sb.append(" APos: ").append(sa.position); + sb.append(" ALoc: ").append(sa.location); + } else { + sb.append(" Action: ").append(sa.action.getName()); + } + } + return sb.toString(); + } + + + +} + diff --git a/src/main/java/com/jcloisterzone/ai/RankingAiPlayer.java b/src/main/java/com/jcloisterzone/ai/RankingAiPlayer.java index b35dc7f18..0b1f616ad 100644 --- a/src/main/java/com/jcloisterzone/ai/RankingAiPlayer.java +++ b/src/main/java/com/jcloisterzone/ai/RankingAiPlayer.java @@ -1,419 +1,419 @@ -package com.jcloisterzone.ai; - -import java.io.File; -import java.util.Collections; -import java.util.Deque; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Map.Entry; -import java.util.Set; - -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.AbbeyPlacementAction; -import com.jcloisterzone.action.BarnAction; -import com.jcloisterzone.action.FairyAction; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.SelectFollowerAction; -import com.jcloisterzone.action.SelectTileAction; -import com.jcloisterzone.action.TakePrisonerAction; -import com.jcloisterzone.action.TilePlacementAction; -import com.jcloisterzone.action.TowerPieceAction; -import com.jcloisterzone.action.UndeployAction; -import com.jcloisterzone.ai.PositionRanking.SelectedAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.phase.ActionPhase; -import com.jcloisterzone.game.phase.EscapePhase; -import com.jcloisterzone.game.phase.LoadGamePhase; -import com.jcloisterzone.game.phase.Phase; -import com.jcloisterzone.game.phase.TowerCapturePhase; - -public abstract class RankingAiPlayer extends AiPlayer { - - class PositionLocation { - Position position; - Location location; - } - - private Game original; - private SavePointManager spm; - - private UserInterface defaultInteractionHandler; - private UserInterface interactionHandler; - - //private Map scoreCache = new HashMap<>(); - private PositionRanking bestSoFar; - //private List hopefulGatePlacements = new ArrayList(); - -// public Map getScoreCache() { -// return scoreCache; -// } - - public RankingAiPlayer() { - defaultInteractionHandler = createDefaultInteractionHandler(); - interactionHandler = defaultInteractionHandler; - } - - protected UserInterface createDefaultInteractionHandler() { - return new DefaultInteraction(); - } - - /* TODP COPIED FROM CLIENT STUB */ - private void phaseLoop() { - Phase phase = getGame().getPhase(); - List> allowed = Lists.newArrayList(ActionPhase.class, EscapePhase.class, TowerCapturePhase.class); - while (!phase.isEntered()) { - if (!Iterables.contains(allowed, phase.getClass())) { - break; - } - //logger.info(" * not entered {} -> {}", phase, phase.getDefaultNext()); - phase.setEntered(true); - phase.enter(); - phase = getGame().getPhase(); - } - } - - //TODO is there faster game copying without snapshot? or without re-creating board and tile instances - private Game deepGameCopy(Game game) { - Snapshot snapshot = new Snapshot(game, 0); - Game copy = snapshot.asGame(); - copy.setConfig(game.getConfig()); - copy.addUserInterface(this); - - LoadGamePhase phase = new LoadGamePhase(copy, snapshot, null); - phase.setSlots(new PlayerSlot[0]); - copy.getPhases().put(phase.getClass(), phase); - copy.setPhase(phase); - phase.startGame(); - return copy; - } - - - protected void backupGame() { - assert original == null; - original = getGame(); - Game copy = deepGameCopy(original); - setGame(copy); - interactionHandler = new RankingInteractionHanlder(); - - spm = new SavePointManager(copy); - bestSoFar = new PositionRanking(Double.NEGATIVE_INFINITY); - spm.startRecording(); - } - - protected void restoreGame() { - assert original != null; - spm.stopRecording(); - spm = null; - setGame(original); - original = null; - interactionHandler = defaultInteractionHandler; - } - -// private boolean isRankingInProcess() { -// return original != null; -// } - -// public PositionRanking getBestSoFar() { -// return bestSoFar; -// } - - - protected void selectAbbeyPlacement(AbbeyPlacementAction action) { - Map> placements = new HashMap<>(); - for (Position pos : action.getSites()) { - placements.put(pos, Collections.singleton(Rotation.R0)); - } - rankTilePlacement(placements); - if (bestSoFar.getRank() > 2.0) { - getServer().placeTile(bestSoFar.getRotation(), bestSoFar.getPosition()); - } else { - getServer().pass(); - } - } - - protected void selectTilePlacement(TilePlacementAction action) { - String autosave = game.getConfig().get("debug", "save_before_ranking"); - if (autosave != null && autosave.length() > 0) { - Snapshot snapshot = new Snapshot(game, 0); - if ("plain".equals(game.getConfig().get("debug", "save_format"))) { - snapshot.setGzipOutput(false); - } - try { - snapshot.save(new File(autosave)); - } catch (Exception e) { - logger.error("Auto save before ranking failed.", e); - } - } - - Map> placements = action.getAvailablePlacements(); - rankTilePlacement(placements); - getServer().placeTile(bestSoFar.getRotation(), bestSoFar.getPosition()); - } - - protected void rankTilePlacement(Map> placements) { - //logger.info("---------- Ranking start ---------------"); - //logger.info("Positions: {} ", placements.keySet()); - - backupGame(); - SavePoint sp = spm.save(); - for (Entry> entry : placements.entrySet()) { - Position pos = entry.getKey(); - for (Rotation rot : entry.getValue()) { - //logger.info(" * phase {} -> {}", getGame().getPhase(), getGame().getPhase().getDefaultNext()); - //logger.info(" * placing {} {}", pos, rot); - getGame().getPhase().placeTile(rot, pos); - //logger.info(" * phase {} -> {}", getGame().getPhase(), getGame().getPhase().getDefaultNext()); - phaseLoop(); - double currRank = rank(); - if (currRank > bestSoFar.getRank()) { - bestSoFar = new PositionRanking(currRank, pos, rot); - } - spm.restore(sp); - //TODO fix hopefulGatePlacement - //now rank meeple placements - must restore because rank change game - //getGame().getPhase().placeTile(rot, pos); - //hopefulGatePlacements.clear(); - //spm.restore(sp); - //TODO add best placements for MAGIC GATE - //getGame().getPhase().enter(); - } - } - restoreGame(); - logger.info("Rank {} > {}", getGame().getCurrentTile() == null ? "Abbey" : getGame().getCurrentTile().getId(), bestSoFar); - } - - protected void rankAction(List actions) { - Tile currTile = getGame().getCurrentTile(); - Position pos = currTile.getPosition(); - for (PlayerAction action : actions) { - if (action instanceof MeepleAction) { - MeepleAction ma = (MeepleAction) action; - rankMeeplePlacement(currTile, ma, ma.getMeepleType(), pos, ma.getLocationsMap().get(pos)); -// for (PositionLocation posloc : hopefulGatePlacements) { -// rankMeepleAction(currTile, ma, posloc.position, Collections.singleton(posloc.location)); -// } - } - if (action instanceof BarnAction) { - BarnAction ba = (BarnAction) action; - rankMeeplePlacement(currTile, ba, Barn.class, pos, ba.get(pos)); - } - if (action instanceof FairyAction) { - rankFairyPlacement(currTile, (FairyAction) action); - } - if (action instanceof TowerPieceAction) { - rankTowerPiecePlacement(currTile, (TowerPieceAction) action); - } - } - } - - protected void rankFairyPlacement(Tile currTile, FairyAction action) { - SavePoint sp = spm.save(); - for (Position pos: action.getSites()) { - getGame().getPhase().moveFairy(pos); - double currRank = rank(); - if (currRank > bestSoFar.getRank()) { - bestSoFar = new PositionRanking(currRank, currTile.getPosition(), currTile.getRotation()); - bestSoFar.getSelectedActions().add(new SelectedAction(action, pos, null)); - } - spm.restore(sp); - } - } - - protected void rankTowerPiecePlacementOnTile(final Tile currTile, final TowerPieceAction towerPieceAction, final Position towerPiecePos) { - this.interactionHandler = new NotSupportedInteraction() { - public void selectAction(List actions, boolean canPass) { - phaseLoop(); - SavePoint sp = spm.save(); - TakePrisonerAction prisonerAction = (TakePrisonerAction) actions.get(0); - for (Entry> entry : prisonerAction.getLocationsMap().entrySet()) { - Position pos = entry.getKey(); - for (Location loc : entry.getValue()) { - for (Meeple m : getBoard().get(pos).getFeature(loc).getMeeples()) { - getGame().getPhase().takePrisoner(pos, loc, m.getClass(), m.getPlayer().getIndex()); - double currRank = rank(); - if (currRank > bestSoFar.getRank()) { - bestSoFar = new PositionRanking(currRank, currTile.getPosition(), currTile.getRotation()); - Deque sa = bestSoFar.getSelectedActions(); - sa.add(new SelectedAction(towerPieceAction, towerPiecePos, null)); - sa.add(new SelectedAction(prisonerAction, pos, loc, m.getClass(), m.getPlayer())); - } - spm.restore(sp); - } - } - } - }; - }; - getGame().getPhase().placeTowerPiece(towerPiecePos); - } - - protected void rankTowerPiecePlacement(Tile currTile,TowerPieceAction action) { - UserInterface interactionHandlerBackup = this.interactionHandler; - SavePoint sp = spm.save(); - for (Position pos: action.getSites()) { - rankTowerPiecePlacementOnTile(currTile, action, pos); - spm.restore(sp); - } - - this.interactionHandler = interactionHandlerBackup; - } - - protected void rankMeeplePlacement(Tile currTile, PlayerAction action, Class meepleType, Position pos, Set locations) { - if (locations == null) { - return; - } - SavePoint sp = spm.save(); - for (Location loc : locations) { - //logger.info(" . deploying {}", meepleType); - getGame().getPhase().deployMeeple(pos, loc, meepleType); - double currRank = rank(); - if (currRank > bestSoFar.getRank()) { - bestSoFar = new PositionRanking(currRank, currTile.getPosition(), currTile.getRotation()); - bestSoFar.getSelectedActions().add(new SelectedAction(action, pos, loc)); - } - spm.restore(sp); - } - } - - public void rankPass() { - SavePoint sp = spm.save(); - getGame().getPhase().pass(); - double currRank = rank(); - if (currRank > bestSoFar.getRank()) { - bestSoFar = new PositionRanking(currRank); - } - spm.restore(sp); - } - - public void cleanRanking() { - bestSoFar = null; - //scoreCache.clear(); - } - - @Override - public void selectAction(List actions, boolean canPass) { - interactionHandler.selectAction(actions, canPass); - } - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - interactionHandler.selectDragonMove(positions, movesLeft); - } - - @Override - public void selectBazaarTile() { - interactionHandler.selectBazaarTile(); - } - - @Override - public void makeBazaarBid(int supplyIndex) { - interactionHandler.makeBazaarBid(supplyIndex); - } - - @Override - public void selectBuyOrSellBazaarOffer(int supplyIndex) { - interactionHandler.selectBuyOrSellBazaarOffer(supplyIndex); - } - - @Override - public void selectCornCircleOption() { - interactionHandler.selectCornCircleOption(); - } - - abstract protected double rank(); - - @Override - protected void handleRuntimeError(Exception e) { - super.handleRuntimeError(e); - cleanRanking(); - if (original != null) { - restoreGame(); - } - } - - class RankingInteractionHanlder extends NotSupportedInteraction { - @Override - public void selectAction(List actions, boolean canPass) { - rankAction(actions); - } - } - - class DefaultInteraction extends NotSupportedInteraction { - - @Override - public void selectAction(List actions, boolean canPass) { - if (actions.size() > 0) { - PlayerAction firstAction = actions.get(0); - - if (firstAction instanceof TilePlacementAction) { - selectTilePlacement((TilePlacementAction) firstAction); - return; - } - if (firstAction instanceof AbbeyPlacementAction) { - selectAbbeyPlacement((AbbeyPlacementAction) firstAction); - return; - } - if (firstAction instanceof UndeployAction ) { - //hack, ai never use escape, TODO - if (firstAction.getName().equals("escape")) { - getServer().pass(); - } - } - } - - if (bestSoFar == null) { //loaded game or wagon phase - backupGame(); - if (canPass) rankPass(); - rankAction(actions); - restoreGame(); - } - - Deque selected = bestSoFar.getSelectedActions(); - SelectedAction sa = selected.pollFirst(); - if (sa != null) { - //logger.info("Polling " + sa.action); - if (sa.action instanceof MeepleAction) { - MeepleAction action = (MeepleAction) sa.action; - //debug, should never happen, but it happens sometimes when Tower game is enabled - try { - getPlayer().getMeepleFromSupply(action.getMeepleType()); - } catch (NoSuchElementException e) { - logger.error(e.getMessage(), e); - throw e; - } - action.perform(getServer(), sa.position, sa.location); - } else if (sa.action instanceof BarnAction) { - BarnAction action = (BarnAction) sa.action; - action.perform(getServer(), sa.position, sa.location); - } else if (sa.action instanceof SelectTileAction) { - SelectTileAction action = (SelectTileAction) sa.action; - action.perform(getServer(), sa.position); - } else if (sa.action instanceof SelectFollowerAction) { - SelectFollowerAction action = (SelectFollowerAction) sa.action; - action.perform(getServer(), sa.position, sa.location, sa.meepleType, sa.meepleOwner); - } else { - throw new UnsupportedOperationException("Unhandled action type " + sa.action.getName()); //should never happen - } - } else { - getServer().pass(); - } - - if (selected.isEmpty()) { - cleanRanking(); - } - } - } - -} +package com.jcloisterzone.ai; + +import java.io.File; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Map.Entry; +import java.util.Set; + +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.AbbeyPlacementAction; +import com.jcloisterzone.action.BarnAction; +import com.jcloisterzone.action.FairyAction; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.SelectFollowerAction; +import com.jcloisterzone.action.SelectTileAction; +import com.jcloisterzone.action.TakePrisonerAction; +import com.jcloisterzone.action.TilePlacementAction; +import com.jcloisterzone.action.TowerPieceAction; +import com.jcloisterzone.action.UndeployAction; +import com.jcloisterzone.ai.PositionRanking.SelectedAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.phase.ActionPhase; +import com.jcloisterzone.game.phase.EscapePhase; +import com.jcloisterzone.game.phase.LoadGamePhase; +import com.jcloisterzone.game.phase.Phase; +import com.jcloisterzone.game.phase.TowerCapturePhase; + +public abstract class RankingAiPlayer extends AiPlayer { + + class PositionLocation { + Position position; + Location location; + } + + private Game original; + private SavePointManager spm; + + private UserInterface defaultInteractionHandler; + private UserInterface interactionHandler; + + //private Map scoreCache = new HashMap<>(); + private PositionRanking bestSoFar; + //private List hopefulGatePlacements = new ArrayList(); + +// public Map getScoreCache() { +// return scoreCache; +// } + + public RankingAiPlayer() { + defaultInteractionHandler = createDefaultInteractionHandler(); + interactionHandler = defaultInteractionHandler; + } + + protected UserInterface createDefaultInteractionHandler() { + return new DefaultInteraction(); + } + + /* TODP COPIED FROM CLIENT STUB */ + private void phaseLoop() { + Phase phase = getGame().getPhase(); + List> allowed = Lists.newArrayList(ActionPhase.class, EscapePhase.class, TowerCapturePhase.class); + while (!phase.isEntered()) { + if (!Iterables.contains(allowed, phase.getClass())) { + break; + } + //logger.info(" * not entered {} -> {}", phase, phase.getDefaultNext()); + phase.setEntered(true); + phase.enter(); + phase = getGame().getPhase(); + } + } + + //TODO is there faster game copying without snapshot? or without re-creating board and tile instances + private Game deepGameCopy(Game game) { + Snapshot snapshot = new Snapshot(game, 0); + Game copy = snapshot.asGame(); + copy.setConfig(game.getConfig()); + copy.addUserInterface(this); + + LoadGamePhase phase = new LoadGamePhase(copy, snapshot, null); + phase.setSlots(new PlayerSlot[0]); + copy.getPhases().put(phase.getClass(), phase); + copy.setPhase(phase); + phase.startGame(); + return copy; + } + + + protected void backupGame() { + assert original == null; + original = getGame(); + Game copy = deepGameCopy(original); + setGame(copy); + interactionHandler = new RankingInteractionHanlder(); + + spm = new SavePointManager(copy); + bestSoFar = new PositionRanking(Double.NEGATIVE_INFINITY); + spm.startRecording(); + } + + protected void restoreGame() { + assert original != null; + spm.stopRecording(); + spm = null; + setGame(original); + original = null; + interactionHandler = defaultInteractionHandler; + } + +// private boolean isRankingInProcess() { +// return original != null; +// } + +// public PositionRanking getBestSoFar() { +// return bestSoFar; +// } + + + protected void selectAbbeyPlacement(AbbeyPlacementAction action) { + Map> placements = new HashMap<>(); + for (Position pos : action.getSites()) { + placements.put(pos, Collections.singleton(Rotation.R0)); + } + rankTilePlacement(placements); + if (bestSoFar.getRank() > 2.0) { + getServer().placeTile(bestSoFar.getRotation(), bestSoFar.getPosition()); + } else { + getServer().pass(); + } + } + + protected void selectTilePlacement(TilePlacementAction action) { + String autosave = game.getConfig().get("debug", "save_before_ranking"); + if (autosave != null && autosave.length() > 0) { + Snapshot snapshot = new Snapshot(game, 0); + if ("plain".equals(game.getConfig().get("debug", "save_format"))) { + snapshot.setGzipOutput(false); + } + try { + snapshot.save(new File(autosave)); + } catch (Exception e) { + logger.error("Auto save before ranking failed.", e); + } + } + + Map> placements = action.getAvailablePlacements(); + rankTilePlacement(placements); + getServer().placeTile(bestSoFar.getRotation(), bestSoFar.getPosition()); + } + + protected void rankTilePlacement(Map> placements) { + //logger.info("---------- Ranking start ---------------"); + //logger.info("Positions: {} ", placements.keySet()); + + backupGame(); + SavePoint sp = spm.save(); + for (Entry> entry : placements.entrySet()) { + Position pos = entry.getKey(); + for (Rotation rot : entry.getValue()) { + //logger.info(" * phase {} -> {}", getGame().getPhase(), getGame().getPhase().getDefaultNext()); + //logger.info(" * placing {} {}", pos, rot); + getGame().getPhase().placeTile(rot, pos); + //logger.info(" * phase {} -> {}", getGame().getPhase(), getGame().getPhase().getDefaultNext()); + phaseLoop(); + double currRank = rank(); + if (currRank > bestSoFar.getRank()) { + bestSoFar = new PositionRanking(currRank, pos, rot); + } + spm.restore(sp); + //TODO fix hopefulGatePlacement + //now rank meeple placements - must restore because rank change game + //getGame().getPhase().placeTile(rot, pos); + //hopefulGatePlacements.clear(); + //spm.restore(sp); + //TODO add best placements for MAGIC GATE + //getGame().getPhase().enter(); + } + } + restoreGame(); + logger.info("Rank {} > {}", getGame().getCurrentTile() == null ? "Abbey" : getGame().getCurrentTile().getId(), bestSoFar); + } + + protected void rankAction(List actions) { + Tile currTile = getGame().getCurrentTile(); + Position pos = currTile.getPosition(); + for (PlayerAction action : actions) { + if (action instanceof MeepleAction) { + MeepleAction ma = (MeepleAction) action; + rankMeeplePlacement(currTile, ma, ma.getMeepleType(), pos, ma.getLocationsMap().get(pos)); +// for (PositionLocation posloc : hopefulGatePlacements) { +// rankMeepleAction(currTile, ma, posloc.position, Collections.singleton(posloc.location)); +// } + } + if (action instanceof BarnAction) { + BarnAction ba = (BarnAction) action; + rankMeeplePlacement(currTile, ba, Barn.class, pos, ba.get(pos)); + } + if (action instanceof FairyAction) { + rankFairyPlacement(currTile, (FairyAction) action); + } + if (action instanceof TowerPieceAction) { + rankTowerPiecePlacement(currTile, (TowerPieceAction) action); + } + } + } + + protected void rankFairyPlacement(Tile currTile, FairyAction action) { + SavePoint sp = spm.save(); + for (Position pos: action.getSites()) { + getGame().getPhase().moveFairy(pos); + double currRank = rank(); + if (currRank > bestSoFar.getRank()) { + bestSoFar = new PositionRanking(currRank, currTile.getPosition(), currTile.getRotation()); + bestSoFar.getSelectedActions().add(new SelectedAction(action, pos, null)); + } + spm.restore(sp); + } + } + + protected void rankTowerPiecePlacementOnTile(final Tile currTile, final TowerPieceAction towerPieceAction, final Position towerPiecePos) { + this.interactionHandler = new NotSupportedInteraction() { + public void selectAction(List actions, boolean canPass) { + phaseLoop(); + SavePoint sp = spm.save(); + TakePrisonerAction prisonerAction = (TakePrisonerAction) actions.get(0); + for (Entry> entry : prisonerAction.getLocationsMap().entrySet()) { + Position pos = entry.getKey(); + for (Location loc : entry.getValue()) { + for (Meeple m : getBoard().get(pos).getFeature(loc).getMeeples()) { + getGame().getPhase().takePrisoner(pos, loc, m.getClass(), m.getPlayer().getIndex()); + double currRank = rank(); + if (currRank > bestSoFar.getRank()) { + bestSoFar = new PositionRanking(currRank, currTile.getPosition(), currTile.getRotation()); + Deque sa = bestSoFar.getSelectedActions(); + sa.add(new SelectedAction(towerPieceAction, towerPiecePos, null)); + sa.add(new SelectedAction(prisonerAction, pos, loc, m.getClass(), m.getPlayer())); + } + spm.restore(sp); + } + } + } + }; + }; + getGame().getPhase().placeTowerPiece(towerPiecePos); + } + + protected void rankTowerPiecePlacement(Tile currTile,TowerPieceAction action) { + UserInterface interactionHandlerBackup = this.interactionHandler; + SavePoint sp = spm.save(); + for (Position pos: action.getSites()) { + rankTowerPiecePlacementOnTile(currTile, action, pos); + spm.restore(sp); + } + + this.interactionHandler = interactionHandlerBackup; + } + + protected void rankMeeplePlacement(Tile currTile, PlayerAction action, Class meepleType, Position pos, Set locations) { + if (locations == null) { + return; + } + SavePoint sp = spm.save(); + for (Location loc : locations) { + //logger.info(" . deploying {}", meepleType); + getGame().getPhase().deployMeeple(pos, loc, meepleType); + double currRank = rank(); + if (currRank > bestSoFar.getRank()) { + bestSoFar = new PositionRanking(currRank, currTile.getPosition(), currTile.getRotation()); + bestSoFar.getSelectedActions().add(new SelectedAction(action, pos, loc)); + } + spm.restore(sp); + } + } + + public void rankPass() { + SavePoint sp = spm.save(); + getGame().getPhase().pass(); + double currRank = rank(); + if (currRank > bestSoFar.getRank()) { + bestSoFar = new PositionRanking(currRank); + } + spm.restore(sp); + } + + public void cleanRanking() { + bestSoFar = null; + //scoreCache.clear(); + } + + @Override + public void selectAction(List actions, boolean canPass) { + interactionHandler.selectAction(actions, canPass); + } + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + interactionHandler.selectDragonMove(positions, movesLeft); + } + + @Override + public void selectBazaarTile() { + interactionHandler.selectBazaarTile(); + } + + @Override + public void makeBazaarBid(int supplyIndex) { + interactionHandler.makeBazaarBid(supplyIndex); + } + + @Override + public void selectBuyOrSellBazaarOffer(int supplyIndex) { + interactionHandler.selectBuyOrSellBazaarOffer(supplyIndex); + } + + @Override + public void selectCornCircleOption() { + interactionHandler.selectCornCircleOption(); + } + + abstract protected double rank(); + + @Override + protected void handleRuntimeError(Exception e) { + super.handleRuntimeError(e); + cleanRanking(); + if (original != null) { + restoreGame(); + } + } + + class RankingInteractionHanlder extends NotSupportedInteraction { + @Override + public void selectAction(List actions, boolean canPass) { + rankAction(actions); + } + } + + class DefaultInteraction extends NotSupportedInteraction { + + @Override + public void selectAction(List actions, boolean canPass) { + if (actions.size() > 0) { + PlayerAction firstAction = actions.get(0); + + if (firstAction instanceof TilePlacementAction) { + selectTilePlacement((TilePlacementAction) firstAction); + return; + } + if (firstAction instanceof AbbeyPlacementAction) { + selectAbbeyPlacement((AbbeyPlacementAction) firstAction); + return; + } + if (firstAction instanceof UndeployAction ) { + //hack, ai never use escape, TODO + if (firstAction.getName().equals("escape")) { + getServer().pass(); + } + } + } + + if (bestSoFar == null) { //loaded game or wagon phase + backupGame(); + if (canPass) rankPass(); + rankAction(actions); + restoreGame(); + } + + Deque selected = bestSoFar.getSelectedActions(); + SelectedAction sa = selected.pollFirst(); + if (sa != null) { + //logger.info("Polling " + sa.action); + if (sa.action instanceof MeepleAction) { + MeepleAction action = (MeepleAction) sa.action; + //debug, should never happen, but it happens sometimes when Tower game is enabled + try { + getPlayer().getMeepleFromSupply(action.getMeepleType()); + } catch (NoSuchElementException e) { + logger.error(e.getMessage(), e); + throw e; + } + action.perform(getServer(), sa.position, sa.location); + } else if (sa.action instanceof BarnAction) { + BarnAction action = (BarnAction) sa.action; + action.perform(getServer(), sa.position, sa.location); + } else if (sa.action instanceof SelectTileAction) { + SelectTileAction action = (SelectTileAction) sa.action; + action.perform(getServer(), sa.position); + } else if (sa.action instanceof SelectFollowerAction) { + SelectFollowerAction action = (SelectFollowerAction) sa.action; + action.perform(getServer(), sa.position, sa.location, sa.meepleType, sa.meepleOwner); + } else { + throw new UnsupportedOperationException("Unhandled action type " + sa.action.getName()); //should never happen + } + } else { + getServer().pass(); + } + + if (selected.isEmpty()) { + cleanRanking(); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/SavePoint.java b/src/main/java/com/jcloisterzone/ai/SavePoint.java index 7bbe58ae9..45e2915b8 100644 --- a/src/main/java/com/jcloisterzone/ai/SavePoint.java +++ b/src/main/java/com/jcloisterzone/ai/SavePoint.java @@ -1,28 +1,28 @@ -package com.jcloisterzone.ai; - -import com.jcloisterzone.ai.operation.Operation; -import com.jcloisterzone.game.phase.Phase; - -public class SavePoint { - private final Operation operation; - private final Phase phase; - private final Object[] capabilitiesBackups; - - public SavePoint(Operation operation, Phase phase, Object[] capabilitiesBackups) { - this.operation = operation; - this.phase = phase; - this.capabilitiesBackups = capabilitiesBackups; - } - - public Operation getOperation() { - return operation; - } - - public Phase getPhase() { - return phase; - } - - public Object[] getCapabilitiesBackups() { - return capabilitiesBackups; - } +package com.jcloisterzone.ai; + +import com.jcloisterzone.ai.operation.Operation; +import com.jcloisterzone.game.phase.Phase; + +public class SavePoint { + private final Operation operation; + private final Phase phase; + private final Object[] capabilitiesBackups; + + public SavePoint(Operation operation, Phase phase, Object[] capabilitiesBackups) { + this.operation = operation; + this.phase = phase; + this.capabilitiesBackups = capabilitiesBackups; + } + + public Operation getOperation() { + return operation; + } + + public Phase getPhase() { + return phase; + } + + public Object[] getCapabilitiesBackups() { + return capabilitiesBackups; + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ai/SavePointManager.java b/src/main/java/com/jcloisterzone/ai/SavePointManager.java index a983ff543..82ab61f9c 100644 --- a/src/main/java/com/jcloisterzone/ai/SavePointManager.java +++ b/src/main/java/com/jcloisterzone/ai/SavePointManager.java @@ -1,106 +1,106 @@ -package com.jcloisterzone.ai; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Player; -import com.jcloisterzone.ai.operation.MeepleDeployedOperation; -import com.jcloisterzone.ai.operation.MeepleUndeployedOperation; -import com.jcloisterzone.ai.operation.Operation; -import com.jcloisterzone.ai.operation.ScoreOperation; -import com.jcloisterzone.ai.operation.TilePlacedOperation; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.event.GameEventAdapter; -import com.jcloisterzone.event.GameEventListener; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.phase.Phase; - -public class SavePointManager { - - private final Game game; - protected Deque operations = new ArrayDeque(); - private GameEventListener operationRecorder = new OperationRecorder(); - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - public SavePointManager(Game game) { - this.game = game; - } - - public Game getGame() { - return game; - } - - public void startRecording() { - game.addGameListener(operationRecorder); - } - - public void stopRecording() { - game.removeGameListener(operationRecorder); - operations.clear(); - } - - public SavePoint save() { - Object[] backups = new Object[game.getCapabilities().size()]; - int i = 0; - for (Capability cap : game.getCapabilities()) { - backups[i++] = cap.backup(); - } - return new SavePoint(operations.peekLast(), game.getPhase(), backups); - - } - - public void restore(SavePoint sp) { - game.removeGameListener(operationRecorder); - Operation target = sp.getOperation(); - while (operations.peekLast() != target) { - //logger.info(" < undo {}", item); - operations.pollLast().undo(game); - } - int i = 0; - for (Capability cap : game.getCapabilities()) { - cap.restore(sp.getCapabilitiesBackups()[i++]); - } - - Phase phase = sp.getPhase(); - game.setPhase(phase); - phase.setEntered(true); - game.addGameListener(operationRecorder); - } - - class OperationRecorder extends GameEventAdapter { - @Override - public void tilePlaced(Tile tile) { - operations.addLast(new TilePlacedOperation(tile)); - } - @Override - public void deployed(Meeple meeple) { - operations.addLast(new MeepleDeployedOperation(meeple)); - } - @Override - public void undeployed(Meeple meeple) { - operations.addLast(new MeepleUndeployedOperation(meeple)); - } -// @Override -// public void playerActivated(Player turnPlayer, Player activePlayer) { -// // TODO Auto-generated method stub -// super.playerActivated(turnPlayer, activePlayer); -// } - @Override - public void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal) { - operations.addLast(new ScoreOperation(meeple.getPlayer(), points)); - } - @Override - public void scored(Position position, Player player, int points, String label, boolean isFinal) { - operations.addLast(new ScoreOperation(player, points)); - } - } +package com.jcloisterzone.ai; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Player; +import com.jcloisterzone.ai.operation.MeepleDeployedOperation; +import com.jcloisterzone.ai.operation.MeepleUndeployedOperation; +import com.jcloisterzone.ai.operation.Operation; +import com.jcloisterzone.ai.operation.ScoreOperation; +import com.jcloisterzone.ai.operation.TilePlacedOperation; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.event.GameEventAdapter; +import com.jcloisterzone.event.GameEventListener; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.phase.Phase; + +public class SavePointManager { + + private final Game game; + protected Deque operations = new ArrayDeque(); + private GameEventListener operationRecorder = new OperationRecorder(); + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + public SavePointManager(Game game) { + this.game = game; + } + + public Game getGame() { + return game; + } + + public void startRecording() { + game.addGameListener(operationRecorder); + } + + public void stopRecording() { + game.removeGameListener(operationRecorder); + operations.clear(); + } + + public SavePoint save() { + Object[] backups = new Object[game.getCapabilities().size()]; + int i = 0; + for (Capability cap : game.getCapabilities()) { + backups[i++] = cap.backup(); + } + return new SavePoint(operations.peekLast(), game.getPhase(), backups); + + } + + public void restore(SavePoint sp) { + game.removeGameListener(operationRecorder); + Operation target = sp.getOperation(); + while (operations.peekLast() != target) { + //logger.info(" < undo {}", item); + operations.pollLast().undo(game); + } + int i = 0; + for (Capability cap : game.getCapabilities()) { + cap.restore(sp.getCapabilitiesBackups()[i++]); + } + + Phase phase = sp.getPhase(); + game.setPhase(phase); + phase.setEntered(true); + game.addGameListener(operationRecorder); + } + + class OperationRecorder extends GameEventAdapter { + @Override + public void tilePlaced(Tile tile) { + operations.addLast(new TilePlacedOperation(tile)); + } + @Override + public void deployed(Meeple meeple) { + operations.addLast(new MeepleDeployedOperation(meeple)); + } + @Override + public void undeployed(Meeple meeple) { + operations.addLast(new MeepleUndeployedOperation(meeple)); + } +// @Override +// public void playerActivated(Player turnPlayer, Player activePlayer) { +// // TODO Auto-generated method stub +// super.playerActivated(turnPlayer, activePlayer); +// } + @Override + public void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal) { + operations.addLast(new ScoreOperation(meeple.getPlayer(), points)); + } + @Override + public void scored(Position position, Player player, int points, String label, boolean isFinal) { + operations.addLast(new ScoreOperation(player, points)); + } + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiFarmScoreContext.java b/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiFarmScoreContext.java index 2048e2867..2c9b65d88 100644 --- a/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiFarmScoreContext.java +++ b/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiFarmScoreContext.java @@ -1,34 +1,34 @@ -package com.jcloisterzone.ai.legacyplayer; - -import com.jcloisterzone.ai.AiScoreContext; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.game.Game; - -public class LegacyAiFarmScoreContext extends FarmScoreContext implements AiScoreContext { - - //private final Map scoreCache; - private boolean valid; - - public LegacyAiFarmScoreContext(Game game/*, Map scoreCache*/) { - super(game); - //this.scoreCache = scoreCache; - } - - @Override - public boolean isValid() { - return valid; - } - - @Override - public void setValid(boolean valid) { - this.valid = valid; - } - - @Override - public boolean visit(Feature feature) { - //scoreCache.put(feature, this); - return super.visit(feature); - } - -} +package com.jcloisterzone.ai.legacyplayer; + +import com.jcloisterzone.ai.AiScoreContext; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.game.Game; + +public class LegacyAiFarmScoreContext extends FarmScoreContext implements AiScoreContext { + + //private final Map scoreCache; + private boolean valid; + + public LegacyAiFarmScoreContext(Game game/*, Map scoreCache*/) { + super(game); + //this.scoreCache = scoreCache; + } + + @Override + public boolean isValid() { + return valid; + } + + @Override + public void setValid(boolean valid) { + this.valid = valid; + } + + @Override + public boolean visit(Feature feature) { + //scoreCache.put(feature, this); + return super.visit(feature); + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiPlayer.java b/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiPlayer.java index 8a289ceac..7ede7b2f9 100644 --- a/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiPlayer.java +++ b/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiPlayer.java @@ -1,691 +1,691 @@ -package com.jcloisterzone.ai.legacyplayer; - -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.ai.RankingAiPlayer; -import com.jcloisterzone.board.EdgePattern; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.score.ScoreAllCallback; -import com.jcloisterzone.feature.score.ScoreAllFeatureFinder; -import com.jcloisterzone.feature.visitor.score.AbstractScoreContext; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.feature.visitor.score.RoadScoreContext; -import com.jcloisterzone.feature.visitor.score.ScoreContext; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.BigFollower; -import com.jcloisterzone.figure.Builder; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.capability.BuilderCapability; -import com.jcloisterzone.game.capability.BuilderCapability.BuilderState; -import com.jcloisterzone.game.capability.DragonCapability; -import com.jcloisterzone.game.capability.FairyCapability; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.game.phase.ScorePhase; - -public class LegacyAiPlayer extends RankingAiPlayer { - - private static final double TRAPPED_MY_FIGURE_POINTS = -12.0; - private static final double TRAPPED_ENEMY_FIGURE_POINTS = 3.0; - private static final double SELF_MERGE_PENALTY = 6.0; - - private static final double MIN_CHANCE = 0.4; - - protected int packSize, myTurnsLeft; - protected int enemyPlayers; - - private static final int OPEN_COUNT_ROAD = 0; - private static final int OPEN_COUNT_CITY = 1; - private static final int OPEN_COUNT_FARM = 2; - private static final int OPEN_COUNT_CLOITSTER = 3; - - - private int[] openCount = new int[4]; //number of my open objects - - public static EnumSet supportedExpansions() { - return EnumSet.of( - Expansion.BASIC, - Expansion.WINTER, - Expansion.ABBEY_AND_MAYOR, - Expansion.INNS_AND_CATHEDRALS, - Expansion.TRADERS_AND_BUILDERS, - Expansion.PRINCESS_AND_DRAGON, - //Expansion.TOWER, //causing error sometimes - Expansion.KING_AND_SCOUT, - Expansion.RIVER, - Expansion.RIVER_II, - Expansion.GQ11, - Expansion.CATAPULT, - Expansion.WIND_ROSE, - Expansion.CATHARS, - //Expansion.PHANTOM, - //only cards - Expansion.COUNT, - Expansion.PLAGUE - ); - } - - - - protected void initVars() { - packSize = getTilePack().totalSize(); - enemyPlayers = game.getAllPlayers().length - 1; - myTurnsLeft = ((packSize-1) / (enemyPlayers+1)) + 1; - } - - @Override - protected double rank() { - double ranking = 0; - initVars(); - - //trigger score - game.getPhase().next(ScorePhase.class); - game.getPhase().enter(); - - Arrays.fill(openCount, 0); - - ranking += meepleRating(); - ranking += pointRating(); - ranking += openObjectRating(); - - ranking += rankPossibleFeatureConnections(); - ranking += rankConvexity(); - ranking += rankFairy(); - -// // --- dbg print -- -// Tile tile = getGame().getCurrentTile(); -// Feature meeplePlacement = Iterables.find(tile.getFeatures(), new Predicate() { -// @Override -// public boolean apply(Feature f) { -// return !f.getMeeples().isEmpty(); -// } -// }, null); -// Arrays.fill(openCount, 0); -// System.err.println( -// String.format("%8s (%4s) %10s %4s/%5s %8.3f = Mepl %.3f Poit %.3f Open %.3f Conn %.3f Covx %.3f Fair %.3f", -// tile.getId(), tile.getRotation(), tile.getPosition(), -// meeplePlacement == null ? "" : meeplePlacement.getClass().getSimpleName(), -// meeplePlacement == null ? "" : meeplePlacement.getLocation(), -// ranking, meepleRating(), pointRating(), openObjectRating(), -// rankPossibleFeatureConnections(), rankConvexity(), rankFairy())); -// // --- end of debug print - - //objectRatings.clear(); - - return ranking; - } - - protected double reducePoints(double points, Player p) { - if (isMe(p)) return points; - return -points/enemyPlayers; - } - - protected double chanceToPlaceTile(Position pos) { - EdgePattern pattern = game.getBoard().getAvailMoveEdgePattern(pos); - if (pattern != null && pattern.wildcardSize() < 2) { - int remains = game.getTilePack().getSizeForEdgePattern(pattern); - if (remains == 0) return 0.0; - if (remains < game.getAllPlayers().length) { - if (remains == 0) return 0.0; - return 1.0 - Math.pow(1.0 - 1.0 / (game.getAllPlayers().length), remains); - } - } - return 1.0; - } - - protected double meepleRating() { - double rating = 0; - - for (Player p : game.getAllPlayers()) { - double meeplePoints = 0; - int limit = 0; - for (Follower f : Iterables.filter(p.getFollowers(), MeeplePredicates.deployed())) { - if (f instanceof SmallFollower) { - meeplePoints += 0.15; - } else if (f instanceof BigFollower) { - meeplePoints += 0.25; - } - if (++limit == myTurnsLeft) break; - } - rating += reducePoints(meeplePoints, p); - } - return rating; - } - - class LegacyAiScoreAllCallback implements ScoreAllCallback { - - private double rank = 0; - - private Set towerDanger = new HashSet<>(); - - public LegacyAiScoreAllCallback() { - TowerCapability towerCap = game.getCapability(TowerCapability.class); - if (towerCap != null) { - for (Position towerPos : towerCap.getTowers()) { - int dangerDistance = 1 + game.getBoard().get(towerPos).getTower().getHeight(); - towerDanger.add(towerPos); - for (int i = 1; i < dangerDistance; i++) { - towerDanger.add(towerPos.add(new Position(i, 0))); - towerDanger.add(towerPos.add(new Position(-i, 0))); - towerDanger.add(towerPos.add(new Position(0, i))); - towerDanger.add(towerPos.add(new Position(0, -i))); - } - } - } - } - - private boolean isInTowerDanger(ScoreContext ctx) { - //not exact but it is easy heuristic at now - if (!towerDanger.isEmpty()) { - for (Follower f : ctx.getFollowers()) { - if (towerDanger.contains(f.getPosition())) { - return true; - } - } - } - return false; - } - - @Override - public void scoreCastle(Meeple meeple, Castle castle) { - throw new UnsupportedOperationException(); - } - - @Override - public LegacyAiScoreContext getCompletableScoreContext(Completable completable) { - //TODO uncomment after invalidate implemeted -// AiScoreContext ctx = getScoreCache().get(completable); -// if (ctx != null && ctx.isValid()) { -// return (CompletableScoreContext) ctx; -// } - return new LegacyAiScoreContext(LegacyAiPlayer.this, completable.getScoreContext()/*, getScoreCache()*/); - } - - @Override - public LegacyAiFarmScoreContext getFarmScoreContext(Farm farm) { - //TODO uncomment after invalidate implemeted -// AiScoreContext ctx = getScoreCache().get(farm); -// if (ctx != null && ctx.isValid()) { -// return (FarmScoreContext) ctx; -// } - return new LegacyAiFarmScoreContext(game/*, getScoreCache()*/); - } - - @Override - public void scoreFarm(FarmScoreContext ctx, Player player) { - if (isInTowerDanger(ctx)) return; - double points = getFarmPoints((Farm) ctx.getMasterFeature(), player, ctx); - rank += reducePoints(points, player); - } - - @Override - public void scoreBarn(FarmScoreContext ctx, Barn meeple) { - //prefer barn placement - magic constant - rank += reducePoints(1.2 * ctx.getBarnPoints(), meeple.getPlayer()); - } - - @Override - public void scoreCompletableFeature(CompletableScoreContext ctx) { - if (isInTowerDanger(ctx)) return; - rank += rankUnfishedCompletable(ctx.getMasterFeature(), (LegacyAiScoreContext) ctx); - rank += rankTrappedMeeples((LegacyAiScoreContext) ctx); - rank += rankSpecialFigures((LegacyAiScoreContext) ctx); - } - - public double getRanking() { - return rank; - } - - } - - protected double pointRating() { - double rating = 0; - - for (Player p : game.getAllPlayers()) { - rating += reducePoints(p.getPoints(), p); - } - - ScoreAllFeatureFinder scoreAll = new ScoreAllFeatureFinder(); - LegacyAiScoreAllCallback callback = new LegacyAiScoreAllCallback(); - scoreAll.scoreAll(game, callback); - rating += callback.getRanking(); - - return rating; - } - - - public static final double[][] OPEN_PENALTY = { - { 0.0, 1.0, 2.5, 4.5, 7.5, 10.5, 14.5, 19.0, 29.0 }, //road - { 0.0, 0.5, 1.5, 3.0, 5.0, 8.0, 12.0, 17.0, 27.0 }, //city - { 0.0, 5.0, 10.0, 19.0, 28.0, 37.0, 47.0, 57.0, 67.0 }, //farm - { 0.0, 0.0, 0.4, 0.8, 1.2, 2.0, 4.0, 7.0, 11.0 } //cloister - }; - - protected double openObjectRating() { - double rating = 0; - - for (int i = 0; i < OPEN_PENALTY.length; i++ ){ - double penalty; - //fast fix for strange bug causes ArrayIndexOutOfBoundsException: 9 - if (openCount[i] >= OPEN_PENALTY[i].length) { - penalty = OPEN_PENALTY[i][OPEN_PENALTY[i].length - 1]; - } else { - penalty = OPEN_PENALTY[i][openCount[i]]; - } - if (i == 2) { - //Farm - double modifier = (packSize - ((1+enemyPlayers) * 3)) / 20.0; - if (modifier < 1.0) modifier = 1.0; - rating -= modifier * penalty; - } else { - rating -= penalty; - } - } - return rating; - } - - private ScoreContext futureConnectionCreateScoreContext(Feature feature) { - LegacyAiScoreAllCallback ctxHelper = new LegacyAiScoreAllCallback(); - ScoreContext ctx; - if (feature instanceof Completable) { - ctx = ctxHelper.getCompletableScoreContext((Completable) feature); - } else { - ctx = ctxHelper.getFarmScoreContext((Farm) feature); - ((LegacyAiFarmScoreContext) ctx).setCityCache(new HashMap()); - } - feature.walk(ctx); - return ctx; - } - - private double futureConnectionGetFeaturePoints(Feature feature, ScoreContext featureCtx) { - if (featureCtx instanceof CompletableScoreContext) { - return getUnfinishedCompletablePoints((Completable) feature, (LegacyAiScoreContext) featureCtx); - } else { - return ((FarmScoreContext) featureCtx).getPoints(getPlayer()); - } - } - - private double futureConnectionRateConnection(Location toEmpty, Location toFeature, Position f2Pos, double chance) { - Tile tile1 = getGame().getCurrentTile(); - Tile tile2 = getBoard().get(f2Pos); - - double rating = 0; - - Completable f1 = (Completable) tile1.getFeaturePartOf(toEmpty); - Completable f2 = (Completable) tile2.getFeaturePartOf(toFeature.rev()); - - if (f1 != null && f2 != null) { - if (f1.getClass().equals(f2.getClass())) { - // System.err.println(" " + tile1.getPosition() + " <-->" + f2Pos + " / " + f1 + " " + f2); - rating += futureConnectionRateFeatures(toEmpty, toFeature, chance, f1, f2); - } else { - rating += futureConnectionRateCrossing(toEmpty, toFeature, chance, f1, f2); - } - } - - if (toEmpty != toFeature) { - boolean left = toEmpty.rotateCCW(Rotation.R90) == toFeature; - Farm farm1 = (Farm) tile2.getFeaturePartOf(left ? toEmpty.getLeftFarm() : toEmpty.getRightFarm()); - Farm farm2 = (Farm) tile2.getFeaturePartOf(left ? toFeature.rev().getRightFarm() : toFeature.rev().getLeftFarm()); - - if (farm1 != null && farm2 != null) { -// System.err.println(" " + tile1.getPosition() + " <-->" + f2Pos + " / " + farm1 + " " + farm2); - rating += futureConnectionRateFeatures(toEmpty, toFeature, chance, farm1, farm2); - } - } - return rating; - } - - private double futureConnectionRateCrossing(Location toEmpty, Location toFeature, double chance, Feature f1, Feature f2) { - ScoreContext f1Ctx = futureConnectionCreateScoreContext(f1); - ScoreContext f2Ctx = futureConnectionCreateScoreContext(f2); - Map f1Powers = f1Ctx.getPowers(); - Map f2Powers = f2Ctx.getPowers(); - - int[] powers = funtureConnectionSumPower(f2Powers, null); - int myPower = powers[0]; - int bestEnemy = powers[1]; - - if (f1Powers.size() == 0) { - if (bestEnemy > myPower) { - return 0.2; - } else if (myPower > 0) { - return -2.5; - } - } else { - if (bestEnemy > myPower) { - return -0.1; - } else if (myPower > 0) { - return -0.5; - } else { - return -0.5; - } - } - return 0; - } - - - private double futureConnectionRateFeatures(Location toEmpty, Location toFeature, double chance, Feature f1, Feature f2) { - ScoreContext f1Ctx = futureConnectionCreateScoreContext(f1); - ScoreContext f2Ctx = futureConnectionCreateScoreContext(f2); - Map f1Powers = f1Ctx.getPowers(); - Map f2Powers = f2Ctx.getPowers(); - - if (f1Powers.size() == 0) { - return 0; - } - - if (f1Powers.size() == 1 && f2Powers.size() == 1 && f1Powers.containsKey(getPlayer()) && f2Powers.containsKey(getPlayer())) { -// System.err.println(" !self merge"); -// System.err.println(f1Powers + " // " + f2Powers); - return -SELF_MERGE_PENALTY; - } - - double myPoints = futureConnectionGetFeaturePoints(f1, f1Ctx); - double enemyPoints = futureConnectionGetFeaturePoints(f2, f2Ctx); - - if (enemyPoints < (toEmpty == toFeature ? 7.0 : 5.0)) { -// System.err.println("too small penalty: " + enemyPoints); - return -0.05; //small penalty - } - - int[] powers = funtureConnectionSumPower(f1Powers, f2Powers); - int myPower = powers[0]; - int bestEnemy = powers[1]; - - double coef = toEmpty != toFeature ? 0.7 : 0.4; //corner / straight connection - -// System.err.println("@@@ @@@ " + myPower + "/" + myPoints + " vs " + bestEnemy + "/" + enemyPoints); - - if (myPower == bestEnemy) { - return coef * (enemyPoints - myPoints) * chance; - } - if (myPower > bestEnemy) { - return coef * enemyPoints * chance; - - } - return -myPoints * chance; //no coef here - - } - - private int[] funtureConnectionSumPower(Map f1Powers, Map f2Powers) { - Map sum = new HashMap(f1Powers); - if (f2Powers != null) { - for (Entry epower : f2Powers.entrySet()) { - Integer val = sum.get(epower.getKey()); - sum.put(epower.getKey(), val == null ? epower.getValue() : val + epower.getValue()); - } - } - int myPower = 0; - int bestEnemy = 0; - for (Entry esum : sum.entrySet()) { - int value = esum.getValue(); - if (esum.getKey().equals(getPlayer())) { - myPower = value; - } else { - if (value > bestEnemy) bestEnemy = value; - } - } - return new int[] { myPower, bestEnemy }; - } - - private double rankPossibleFeatureConnections() { - double rank = 0; - - Tile tile = getGame().getCurrentTile(); - Position placement = tile.getPosition(); - assert placement != null; - - for (Entry eplace : Position.ADJACENT.entrySet()) { - Position pos = placement.add(eplace.getValue()); - if (getBoard().get(pos) != null) continue; - - double chance = chanceToPlaceTile(pos); - if (chance < MIN_CHANCE) continue; - - for (Entry econn : Position.ADJACENT.entrySet()) { - Position conn = pos.add(econn.getValue()); - if (conn.equals(placement)) continue; - Tile connTile = getBoard().get(conn); - if (connTile == null) continue; - - rank += futureConnectionRateConnection(eplace.getKey(), econn.getKey(), conn, chance); - } - } - return rank; - } - - protected double rankFairy() { - if (!game.hasCapability(FairyCapability.class)) return 0; - FairyCapability fc = game.getCapability(FairyCapability.class); - Position fairyPos = fc.getFairyPosition(); - if (fairyPos == null) return 0; - - double rating = 0; - -// TODO more sophisticated rating - for (Meeple meeple : game.getDeployedMeeples()) { - if (!meeple.at(fairyPos)) continue; - if (!(meeple instanceof Follower)) continue; - if (meeple.getFeature() instanceof Castle) continue; - - rating += reducePoints(1.0, meeple.getPlayer()); - } - - return rating; - -// //OLD legacy impl -// Set onTile = gc.getPlacedFiguresForTile(board.get(fairyPos.x,fairyPos.y)); -// Set onePointPlayers = new HashSet<>(); -// for (PlacedFigure pfi : onTile) { -// if (pfi != null && gi.get().equals(pfi.player)) { -// onePointPlayers.add(pfi.player); -// } -// if (pfi.et == FeatureType.TOWER) continue; -// LastPlaceInfo last = gc.getBoard().getLastPlacementInfo(); -// if (gc.getBoard().get(last.pos).getTrigger() == TileTrigger.DRAGON) { -// int dist = last.pos.squareDistance(pfi.position); -// if (dist == 1) { -// //figurka hned vedle, heuristika -// /*Tile lastTile = gc.getBoard().get(pfi.position); -// if (pfi.et == ElementType.CLOISTER) { -// //lastTile.getCloister().get ... -// }*/ -// rating += reducePoints(4, pfi.player); //zatim proste odhadnem cenu figurky na 4 body -// } -// } -// } -// //kvuli brane a vice figurkam na jednom poli, aby kazdy hrac max +1 za kolo -// -// for (Player player : onePointPlayers) { -// rating += reducePoints(0.8, player); -// } - } - - protected double rankConvexity() { - Position pos = game.getCurrentTile().getPosition(); - return 0.001 * getBoard().getAdjacentAndDiagonalTiles(pos).size(); - } - - protected double rankUnfishedCompletable(Completable completable, LegacyAiScoreContext ctx) { - double rating = 0.0; - double points = getUnfinishedCompletablePoints(completable, ctx); - for (Player p : ctx.getMajorOwners()) { - rating += reducePoints(points, p); - } - return rating; - } - - protected double getUnfinishedCompletablePoints(Completable complatable, LegacyAiScoreContext ctx) { - if (complatable instanceof City) { - return getUnfinishedCityPoints((City) complatable, ctx); - } - if (complatable instanceof Road) { - return getUnfinishedRoadPoints((Road) complatable, ctx); - } - if (complatable instanceof Cloister) { - return getUnfinishedCloisterPoints((Cloister) complatable, ctx); - } - throw new IllegalArgumentException(); - } - - protected double getUnfinishedCityPoints(City city, LegacyAiScoreContext ctx) { - double chanceToClose = ctx.getChanceToClose(); - - if (chanceToClose > MIN_CHANCE && ctx.getMajorOwners().contains(getPlayer())) { - openCount[OPEN_COUNT_CITY]++; - } - - //legacy heuristic - CityScoreContext cityCtx = (CityScoreContext) ctx.getCompletableScoreContext(); - if (chanceToClose < MIN_CHANCE) { - return cityCtx.getPoints(false) + 3.0*chanceToClose; - } else { - return cityCtx.getPoints(true) - 3.0*(1.0-chanceToClose); - } - } - - protected double getUnfinishedRoadPoints(Road road, LegacyAiScoreContext ctx) { - double chanceToClose = ctx.getChanceToClose();; - - if (chanceToClose > MIN_CHANCE && ctx.getMajorOwners().contains(getPlayer())) { - openCount[OPEN_COUNT_ROAD]++; - } - - //legacy heuristic - RoadScoreContext roadCtx = (RoadScoreContext) ctx.getCompletableScoreContext(); - if (chanceToClose < MIN_CHANCE) { - return roadCtx.getPoints(false) + 3.0*chanceToClose; - } else { - return roadCtx.getPoints(true) - 3.0*(1.0-chanceToClose); - } - - } - - protected double getUnfinishedCloisterPoints(Cloister cloister, LegacyAiScoreContext ctx) { - List followers = cloister.getMeeples(); - if (!followers.isEmpty() && isMe(followers.get(0).getPlayer())) { - openCount[OPEN_COUNT_CLOITSTER]++; - } - double chanceToClose = ctx.getChanceToClose(); - int points = ctx.getPoints(); - return points + (9-points)*chanceToClose; - } - - protected double getFarmPoints(Farm farm, Player p, FarmScoreContext ctx) { - if (isMe(p)) { - openCount[OPEN_COUNT_FARM]++; - } - return ctx.getPoints(p); - } - - protected double rankSpecialFigures(LegacyAiScoreContext ctx) { - double rating = 0.0; - for (Meeple m : ctx.getSpecialMeeples()) { - if (m instanceof Builder && isMe(m.getPlayer())) { - rating += rankBuilder((Builder) m, ctx); - } - } - return rating; - } - - protected double rankBuilder(Builder builder, LegacyAiScoreContext ctx) { - if (!ctx.getMajorOwners().contains(getPlayer())) { - return -3.0; //builder in enemy object penalty - } - if (ctx.getChanceToClose() < 0.55) return 0.0; - double rating = 0.0; - //builder placed in object - if (builder.getFeature() instanceof City) { - rating += 1.5; - } else { - rating += 0.5; - } - - BuilderCapability bc = game.getCapability(BuilderCapability.class); - //builder used on object - if (bc.getBuilderState() == BuilderState.ACTIVATED) { - rating += 3.5; - } - return rating; - } - - private double rankTrappedMeeples(LegacyAiScoreContext ctx) { - //musi tu byt dolni mez - btw nestaci toto misto hodnoceni figurek, spis asi :) - - //TODO lepe - if (myTurnsLeft < 8) return 0.0; - - if (ctx.getChanceToClose() > 0.4) return 0.0; - - double rating = 0.0; - for (Meeple m : ctx.getMeeples()) { - if (isMe(m.getPlayer())) { - rating += TRAPPED_MY_FIGURE_POINTS; - } else { - rating += TRAPPED_ENEMY_FIGURE_POINTS; - } - } - return (1.0 - ctx.getChanceToClose()) * rating; //no reduce - } - - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - initVars(); - Position dragonPosition = game.getCapability(DragonCapability.class).getDragonPosition(); - double tensionX = 0, tensionY = 0; - - for (Meeple m : game.getDeployedMeeples()) { - int distance = dragonPosition.squareDistance(m.getPosition()); - if (distance == 0 || distance > movesLeft) continue; - if (m.getFeature() instanceof Castle) continue; - - double weight = 1.0 / (distance * distance); - if (isMe(m.getPlayer())) { - weight *= -0.8; //co takhle 0.8 - } - tensionX += weight * (m.getPosition().x - dragonPosition.x); - tensionY += weight * (m.getPosition().y - dragonPosition.y); - } - - double minDiff = Double.MAX_VALUE; - Position result = null; - for (Position p : positions) { - double diff = - Math.abs(p.x - dragonPosition.x - tensionX) + Math.abs(p.y - dragonPosition.y - tensionY); - if (diff < minDiff) { - minDiff = diff; - result = p; - } - } - logger.info("Selected dragon move: {}", result); - getServer().moveDragon(result); - } - -} +package com.jcloisterzone.ai.legacyplayer; + +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.ai.RankingAiPlayer; +import com.jcloisterzone.board.EdgePattern; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.score.ScoreAllCallback; +import com.jcloisterzone.feature.score.ScoreAllFeatureFinder; +import com.jcloisterzone.feature.visitor.score.AbstractScoreContext; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.feature.visitor.score.RoadScoreContext; +import com.jcloisterzone.feature.visitor.score.ScoreContext; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.BigFollower; +import com.jcloisterzone.figure.Builder; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.capability.BuilderCapability; +import com.jcloisterzone.game.capability.BuilderCapability.BuilderState; +import com.jcloisterzone.game.capability.DragonCapability; +import com.jcloisterzone.game.capability.FairyCapability; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.game.phase.ScorePhase; + +public class LegacyAiPlayer extends RankingAiPlayer { + + private static final double TRAPPED_MY_FIGURE_POINTS = -12.0; + private static final double TRAPPED_ENEMY_FIGURE_POINTS = 3.0; + private static final double SELF_MERGE_PENALTY = 6.0; + + private static final double MIN_CHANCE = 0.4; + + protected int packSize, myTurnsLeft; + protected int enemyPlayers; + + private static final int OPEN_COUNT_ROAD = 0; + private static final int OPEN_COUNT_CITY = 1; + private static final int OPEN_COUNT_FARM = 2; + private static final int OPEN_COUNT_CLOITSTER = 3; + + + private int[] openCount = new int[4]; //number of my open objects + + public static EnumSet supportedExpansions() { + return EnumSet.of( + Expansion.BASIC, + Expansion.WINTER, + Expansion.ABBEY_AND_MAYOR, + Expansion.INNS_AND_CATHEDRALS, + Expansion.TRADERS_AND_BUILDERS, + Expansion.PRINCESS_AND_DRAGON, + //Expansion.TOWER, //causing error sometimes + Expansion.KING_AND_SCOUT, + Expansion.RIVER, + Expansion.RIVER_II, + Expansion.GQ11, + Expansion.CATAPULT, + Expansion.WIND_ROSE, + Expansion.CATHARS, + //Expansion.PHANTOM, + //only cards + Expansion.COUNT, + Expansion.PLAGUE + ); + } + + + + protected void initVars() { + packSize = getTilePack().totalSize(); + enemyPlayers = game.getAllPlayers().length - 1; + myTurnsLeft = ((packSize-1) / (enemyPlayers+1)) + 1; + } + + @Override + protected double rank() { + double ranking = 0; + initVars(); + + //trigger score + game.getPhase().next(ScorePhase.class); + game.getPhase().enter(); + + Arrays.fill(openCount, 0); + + ranking += meepleRating(); + ranking += pointRating(); + ranking += openObjectRating(); + + ranking += rankPossibleFeatureConnections(); + ranking += rankConvexity(); + ranking += rankFairy(); + +// // --- dbg print -- +// Tile tile = getGame().getCurrentTile(); +// Feature meeplePlacement = Iterables.find(tile.getFeatures(), new Predicate() { +// @Override +// public boolean apply(Feature f) { +// return !f.getMeeples().isEmpty(); +// } +// }, null); +// Arrays.fill(openCount, 0); +// System.err.println( +// String.format("%8s (%4s) %10s %4s/%5s %8.3f = Mepl %.3f Poit %.3f Open %.3f Conn %.3f Covx %.3f Fair %.3f", +// tile.getId(), tile.getRotation(), tile.getPosition(), +// meeplePlacement == null ? "" : meeplePlacement.getClass().getSimpleName(), +// meeplePlacement == null ? "" : meeplePlacement.getLocation(), +// ranking, meepleRating(), pointRating(), openObjectRating(), +// rankPossibleFeatureConnections(), rankConvexity(), rankFairy())); +// // --- end of debug print + + //objectRatings.clear(); + + return ranking; + } + + protected double reducePoints(double points, Player p) { + if (isMe(p)) return points; + return -points/enemyPlayers; + } + + protected double chanceToPlaceTile(Position pos) { + EdgePattern pattern = game.getBoard().getAvailMoveEdgePattern(pos); + if (pattern != null && pattern.wildcardSize() < 2) { + int remains = game.getTilePack().getSizeForEdgePattern(pattern); + if (remains == 0) return 0.0; + if (remains < game.getAllPlayers().length) { + if (remains == 0) return 0.0; + return 1.0 - Math.pow(1.0 - 1.0 / (game.getAllPlayers().length), remains); + } + } + return 1.0; + } + + protected double meepleRating() { + double rating = 0; + + for (Player p : game.getAllPlayers()) { + double meeplePoints = 0; + int limit = 0; + for (Follower f : Iterables.filter(p.getFollowers(), MeeplePredicates.deployed())) { + if (f instanceof SmallFollower) { + meeplePoints += 0.15; + } else if (f instanceof BigFollower) { + meeplePoints += 0.25; + } + if (++limit == myTurnsLeft) break; + } + rating += reducePoints(meeplePoints, p); + } + return rating; + } + + class LegacyAiScoreAllCallback implements ScoreAllCallback { + + private double rank = 0; + + private Set towerDanger = new HashSet<>(); + + public LegacyAiScoreAllCallback() { + TowerCapability towerCap = game.getCapability(TowerCapability.class); + if (towerCap != null) { + for (Position towerPos : towerCap.getTowers()) { + int dangerDistance = 1 + game.getBoard().get(towerPos).getTower().getHeight(); + towerDanger.add(towerPos); + for (int i = 1; i < dangerDistance; i++) { + towerDanger.add(towerPos.add(new Position(i, 0))); + towerDanger.add(towerPos.add(new Position(-i, 0))); + towerDanger.add(towerPos.add(new Position(0, i))); + towerDanger.add(towerPos.add(new Position(0, -i))); + } + } + } + } + + private boolean isInTowerDanger(ScoreContext ctx) { + //not exact but it is easy heuristic at now + if (!towerDanger.isEmpty()) { + for (Follower f : ctx.getFollowers()) { + if (towerDanger.contains(f.getPosition())) { + return true; + } + } + } + return false; + } + + @Override + public void scoreCastle(Meeple meeple, Castle castle) { + throw new UnsupportedOperationException(); + } + + @Override + public LegacyAiScoreContext getCompletableScoreContext(Completable completable) { + //TODO uncomment after invalidate implemeted +// AiScoreContext ctx = getScoreCache().get(completable); +// if (ctx != null && ctx.isValid()) { +// return (CompletableScoreContext) ctx; +// } + return new LegacyAiScoreContext(LegacyAiPlayer.this, completable.getScoreContext()/*, getScoreCache()*/); + } + + @Override + public LegacyAiFarmScoreContext getFarmScoreContext(Farm farm) { + //TODO uncomment after invalidate implemeted +// AiScoreContext ctx = getScoreCache().get(farm); +// if (ctx != null && ctx.isValid()) { +// return (FarmScoreContext) ctx; +// } + return new LegacyAiFarmScoreContext(game/*, getScoreCache()*/); + } + + @Override + public void scoreFarm(FarmScoreContext ctx, Player player) { + if (isInTowerDanger(ctx)) return; + double points = getFarmPoints((Farm) ctx.getMasterFeature(), player, ctx); + rank += reducePoints(points, player); + } + + @Override + public void scoreBarn(FarmScoreContext ctx, Barn meeple) { + //prefer barn placement - magic constant + rank += reducePoints(1.2 * ctx.getBarnPoints(), meeple.getPlayer()); + } + + @Override + public void scoreCompletableFeature(CompletableScoreContext ctx) { + if (isInTowerDanger(ctx)) return; + rank += rankUnfishedCompletable(ctx.getMasterFeature(), (LegacyAiScoreContext) ctx); + rank += rankTrappedMeeples((LegacyAiScoreContext) ctx); + rank += rankSpecialFigures((LegacyAiScoreContext) ctx); + } + + public double getRanking() { + return rank; + } + + } + + protected double pointRating() { + double rating = 0; + + for (Player p : game.getAllPlayers()) { + rating += reducePoints(p.getPoints(), p); + } + + ScoreAllFeatureFinder scoreAll = new ScoreAllFeatureFinder(); + LegacyAiScoreAllCallback callback = new LegacyAiScoreAllCallback(); + scoreAll.scoreAll(game, callback); + rating += callback.getRanking(); + + return rating; + } + + + public static final double[][] OPEN_PENALTY = { + { 0.0, 1.0, 2.5, 4.5, 7.5, 10.5, 14.5, 19.0, 29.0 }, //road + { 0.0, 0.5, 1.5, 3.0, 5.0, 8.0, 12.0, 17.0, 27.0 }, //city + { 0.0, 5.0, 10.0, 19.0, 28.0, 37.0, 47.0, 57.0, 67.0 }, //farm + { 0.0, 0.0, 0.4, 0.8, 1.2, 2.0, 4.0, 7.0, 11.0 } //cloister + }; + + protected double openObjectRating() { + double rating = 0; + + for (int i = 0; i < OPEN_PENALTY.length; i++ ){ + double penalty; + //fast fix for strange bug causes ArrayIndexOutOfBoundsException: 9 + if (openCount[i] >= OPEN_PENALTY[i].length) { + penalty = OPEN_PENALTY[i][OPEN_PENALTY[i].length - 1]; + } else { + penalty = OPEN_PENALTY[i][openCount[i]]; + } + if (i == 2) { + //Farm + double modifier = (packSize - ((1+enemyPlayers) * 3)) / 20.0; + if (modifier < 1.0) modifier = 1.0; + rating -= modifier * penalty; + } else { + rating -= penalty; + } + } + return rating; + } + + private ScoreContext futureConnectionCreateScoreContext(Feature feature) { + LegacyAiScoreAllCallback ctxHelper = new LegacyAiScoreAllCallback(); + ScoreContext ctx; + if (feature instanceof Completable) { + ctx = ctxHelper.getCompletableScoreContext((Completable) feature); + } else { + ctx = ctxHelper.getFarmScoreContext((Farm) feature); + ((LegacyAiFarmScoreContext) ctx).setCityCache(new HashMap()); + } + feature.walk(ctx); + return ctx; + } + + private double futureConnectionGetFeaturePoints(Feature feature, ScoreContext featureCtx) { + if (featureCtx instanceof CompletableScoreContext) { + return getUnfinishedCompletablePoints((Completable) feature, (LegacyAiScoreContext) featureCtx); + } else { + return ((FarmScoreContext) featureCtx).getPoints(getPlayer()); + } + } + + private double futureConnectionRateConnection(Location toEmpty, Location toFeature, Position f2Pos, double chance) { + Tile tile1 = getGame().getCurrentTile(); + Tile tile2 = getBoard().get(f2Pos); + + double rating = 0; + + Completable f1 = (Completable) tile1.getFeaturePartOf(toEmpty); + Completable f2 = (Completable) tile2.getFeaturePartOf(toFeature.rev()); + + if (f1 != null && f2 != null) { + if (f1.getClass().equals(f2.getClass())) { + // System.err.println(" " + tile1.getPosition() + " <-->" + f2Pos + " / " + f1 + " " + f2); + rating += futureConnectionRateFeatures(toEmpty, toFeature, chance, f1, f2); + } else { + rating += futureConnectionRateCrossing(toEmpty, toFeature, chance, f1, f2); + } + } + + if (toEmpty != toFeature) { + boolean left = toEmpty.rotateCCW(Rotation.R90) == toFeature; + Farm farm1 = (Farm) tile2.getFeaturePartOf(left ? toEmpty.getLeftFarm() : toEmpty.getRightFarm()); + Farm farm2 = (Farm) tile2.getFeaturePartOf(left ? toFeature.rev().getRightFarm() : toFeature.rev().getLeftFarm()); + + if (farm1 != null && farm2 != null) { +// System.err.println(" " + tile1.getPosition() + " <-->" + f2Pos + " / " + farm1 + " " + farm2); + rating += futureConnectionRateFeatures(toEmpty, toFeature, chance, farm1, farm2); + } + } + return rating; + } + + private double futureConnectionRateCrossing(Location toEmpty, Location toFeature, double chance, Feature f1, Feature f2) { + ScoreContext f1Ctx = futureConnectionCreateScoreContext(f1); + ScoreContext f2Ctx = futureConnectionCreateScoreContext(f2); + Map f1Powers = f1Ctx.getPowers(); + Map f2Powers = f2Ctx.getPowers(); + + int[] powers = funtureConnectionSumPower(f2Powers, null); + int myPower = powers[0]; + int bestEnemy = powers[1]; + + if (f1Powers.size() == 0) { + if (bestEnemy > myPower) { + return 0.2; + } else if (myPower > 0) { + return -2.5; + } + } else { + if (bestEnemy > myPower) { + return -0.1; + } else if (myPower > 0) { + return -0.5; + } else { + return -0.5; + } + } + return 0; + } + + + private double futureConnectionRateFeatures(Location toEmpty, Location toFeature, double chance, Feature f1, Feature f2) { + ScoreContext f1Ctx = futureConnectionCreateScoreContext(f1); + ScoreContext f2Ctx = futureConnectionCreateScoreContext(f2); + Map f1Powers = f1Ctx.getPowers(); + Map f2Powers = f2Ctx.getPowers(); + + if (f1Powers.size() == 0) { + return 0; + } + + if (f1Powers.size() == 1 && f2Powers.size() == 1 && f1Powers.containsKey(getPlayer()) && f2Powers.containsKey(getPlayer())) { +// System.err.println(" !self merge"); +// System.err.println(f1Powers + " // " + f2Powers); + return -SELF_MERGE_PENALTY; + } + + double myPoints = futureConnectionGetFeaturePoints(f1, f1Ctx); + double enemyPoints = futureConnectionGetFeaturePoints(f2, f2Ctx); + + if (enemyPoints < (toEmpty == toFeature ? 7.0 : 5.0)) { +// System.err.println("too small penalty: " + enemyPoints); + return -0.05; //small penalty + } + + int[] powers = funtureConnectionSumPower(f1Powers, f2Powers); + int myPower = powers[0]; + int bestEnemy = powers[1]; + + double coef = toEmpty != toFeature ? 0.7 : 0.4; //corner / straight connection + +// System.err.println("@@@ @@@ " + myPower + "/" + myPoints + " vs " + bestEnemy + "/" + enemyPoints); + + if (myPower == bestEnemy) { + return coef * (enemyPoints - myPoints) * chance; + } + if (myPower > bestEnemy) { + return coef * enemyPoints * chance; + + } + return -myPoints * chance; //no coef here + + } + + private int[] funtureConnectionSumPower(Map f1Powers, Map f2Powers) { + Map sum = new HashMap(f1Powers); + if (f2Powers != null) { + for (Entry epower : f2Powers.entrySet()) { + Integer val = sum.get(epower.getKey()); + sum.put(epower.getKey(), val == null ? epower.getValue() : val + epower.getValue()); + } + } + int myPower = 0; + int bestEnemy = 0; + for (Entry esum : sum.entrySet()) { + int value = esum.getValue(); + if (esum.getKey().equals(getPlayer())) { + myPower = value; + } else { + if (value > bestEnemy) bestEnemy = value; + } + } + return new int[] { myPower, bestEnemy }; + } + + private double rankPossibleFeatureConnections() { + double rank = 0; + + Tile tile = getGame().getCurrentTile(); + Position placement = tile.getPosition(); + assert placement != null; + + for (Entry eplace : Position.ADJACENT.entrySet()) { + Position pos = placement.add(eplace.getValue()); + if (getBoard().get(pos) != null) continue; + + double chance = chanceToPlaceTile(pos); + if (chance < MIN_CHANCE) continue; + + for (Entry econn : Position.ADJACENT.entrySet()) { + Position conn = pos.add(econn.getValue()); + if (conn.equals(placement)) continue; + Tile connTile = getBoard().get(conn); + if (connTile == null) continue; + + rank += futureConnectionRateConnection(eplace.getKey(), econn.getKey(), conn, chance); + } + } + return rank; + } + + protected double rankFairy() { + if (!game.hasCapability(FairyCapability.class)) return 0; + FairyCapability fc = game.getCapability(FairyCapability.class); + Position fairyPos = fc.getFairyPosition(); + if (fairyPos == null) return 0; + + double rating = 0; + +// TODO more sophisticated rating + for (Meeple meeple : game.getDeployedMeeples()) { + if (!meeple.at(fairyPos)) continue; + if (!(meeple instanceof Follower)) continue; + if (meeple.getFeature() instanceof Castle) continue; + + rating += reducePoints(1.0, meeple.getPlayer()); + } + + return rating; + +// //OLD legacy impl +// Set onTile = gc.getPlacedFiguresForTile(board.get(fairyPos.x,fairyPos.y)); +// Set onePointPlayers = new HashSet<>(); +// for (PlacedFigure pfi : onTile) { +// if (pfi != null && gi.get().equals(pfi.player)) { +// onePointPlayers.add(pfi.player); +// } +// if (pfi.et == FeatureType.TOWER) continue; +// LastPlaceInfo last = gc.getBoard().getLastPlacementInfo(); +// if (gc.getBoard().get(last.pos).getTrigger() == TileTrigger.DRAGON) { +// int dist = last.pos.squareDistance(pfi.position); +// if (dist == 1) { +// //figurka hned vedle, heuristika +// /*Tile lastTile = gc.getBoard().get(pfi.position); +// if (pfi.et == ElementType.CLOISTER) { +// //lastTile.getCloister().get ... +// }*/ +// rating += reducePoints(4, pfi.player); //zatim proste odhadnem cenu figurky na 4 body +// } +// } +// } +// //kvuli brane a vice figurkam na jednom poli, aby kazdy hrac max +1 za kolo +// +// for (Player player : onePointPlayers) { +// rating += reducePoints(0.8, player); +// } + } + + protected double rankConvexity() { + Position pos = game.getCurrentTile().getPosition(); + return 0.001 * getBoard().getAdjacentAndDiagonalTiles(pos).size(); + } + + protected double rankUnfishedCompletable(Completable completable, LegacyAiScoreContext ctx) { + double rating = 0.0; + double points = getUnfinishedCompletablePoints(completable, ctx); + for (Player p : ctx.getMajorOwners()) { + rating += reducePoints(points, p); + } + return rating; + } + + protected double getUnfinishedCompletablePoints(Completable complatable, LegacyAiScoreContext ctx) { + if (complatable instanceof City) { + return getUnfinishedCityPoints((City) complatable, ctx); + } + if (complatable instanceof Road) { + return getUnfinishedRoadPoints((Road) complatable, ctx); + } + if (complatable instanceof Cloister) { + return getUnfinishedCloisterPoints((Cloister) complatable, ctx); + } + throw new IllegalArgumentException(); + } + + protected double getUnfinishedCityPoints(City city, LegacyAiScoreContext ctx) { + double chanceToClose = ctx.getChanceToClose(); + + if (chanceToClose > MIN_CHANCE && ctx.getMajorOwners().contains(getPlayer())) { + openCount[OPEN_COUNT_CITY]++; + } + + //legacy heuristic + CityScoreContext cityCtx = (CityScoreContext) ctx.getCompletableScoreContext(); + if (chanceToClose < MIN_CHANCE) { + return cityCtx.getPoints(false) + 3.0*chanceToClose; + } else { + return cityCtx.getPoints(true) - 3.0*(1.0-chanceToClose); + } + } + + protected double getUnfinishedRoadPoints(Road road, LegacyAiScoreContext ctx) { + double chanceToClose = ctx.getChanceToClose();; + + if (chanceToClose > MIN_CHANCE && ctx.getMajorOwners().contains(getPlayer())) { + openCount[OPEN_COUNT_ROAD]++; + } + + //legacy heuristic + RoadScoreContext roadCtx = (RoadScoreContext) ctx.getCompletableScoreContext(); + if (chanceToClose < MIN_CHANCE) { + return roadCtx.getPoints(false) + 3.0*chanceToClose; + } else { + return roadCtx.getPoints(true) - 3.0*(1.0-chanceToClose); + } + + } + + protected double getUnfinishedCloisterPoints(Cloister cloister, LegacyAiScoreContext ctx) { + List followers = cloister.getMeeples(); + if (!followers.isEmpty() && isMe(followers.get(0).getPlayer())) { + openCount[OPEN_COUNT_CLOITSTER]++; + } + double chanceToClose = ctx.getChanceToClose(); + int points = ctx.getPoints(); + return points + (9-points)*chanceToClose; + } + + protected double getFarmPoints(Farm farm, Player p, FarmScoreContext ctx) { + if (isMe(p)) { + openCount[OPEN_COUNT_FARM]++; + } + return ctx.getPoints(p); + } + + protected double rankSpecialFigures(LegacyAiScoreContext ctx) { + double rating = 0.0; + for (Meeple m : ctx.getSpecialMeeples()) { + if (m instanceof Builder && isMe(m.getPlayer())) { + rating += rankBuilder((Builder) m, ctx); + } + } + return rating; + } + + protected double rankBuilder(Builder builder, LegacyAiScoreContext ctx) { + if (!ctx.getMajorOwners().contains(getPlayer())) { + return -3.0; //builder in enemy object penalty + } + if (ctx.getChanceToClose() < 0.55) return 0.0; + double rating = 0.0; + //builder placed in object + if (builder.getFeature() instanceof City) { + rating += 1.5; + } else { + rating += 0.5; + } + + BuilderCapability bc = game.getCapability(BuilderCapability.class); + //builder used on object + if (bc.getBuilderState() == BuilderState.ACTIVATED) { + rating += 3.5; + } + return rating; + } + + private double rankTrappedMeeples(LegacyAiScoreContext ctx) { + //musi tu byt dolni mez - btw nestaci toto misto hodnoceni figurek, spis asi :) + + //TODO lepe + if (myTurnsLeft < 8) return 0.0; + + if (ctx.getChanceToClose() > 0.4) return 0.0; + + double rating = 0.0; + for (Meeple m : ctx.getMeeples()) { + if (isMe(m.getPlayer())) { + rating += TRAPPED_MY_FIGURE_POINTS; + } else { + rating += TRAPPED_ENEMY_FIGURE_POINTS; + } + } + return (1.0 - ctx.getChanceToClose()) * rating; //no reduce + } + + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + initVars(); + Position dragonPosition = game.getCapability(DragonCapability.class).getDragonPosition(); + double tensionX = 0, tensionY = 0; + + for (Meeple m : game.getDeployedMeeples()) { + int distance = dragonPosition.squareDistance(m.getPosition()); + if (distance == 0 || distance > movesLeft) continue; + if (m.getFeature() instanceof Castle) continue; + + double weight = 1.0 / (distance * distance); + if (isMe(m.getPlayer())) { + weight *= -0.8; //co takhle 0.8 + } + tensionX += weight * (m.getPosition().x - dragonPosition.x); + tensionY += weight * (m.getPosition().y - dragonPosition.y); + } + + double minDiff = Double.MAX_VALUE; + Position result = null; + for (Position p : positions) { + double diff = + Math.abs(p.x - dragonPosition.x - tensionX) + Math.abs(p.y - dragonPosition.y - tensionY); + if (diff < minDiff) { + minDiff = diff; + result = p; + } + } + logger.info("Selected dragon move: {}", result); + getServer().moveDragon(result); + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiScoreContext.java b/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiScoreContext.java index f5735c1e8..78eeda28f 100644 --- a/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiScoreContext.java +++ b/src/main/java/com/jcloisterzone/ai/legacyplayer/LegacyAiScoreContext.java @@ -1,171 +1,171 @@ -package com.jcloisterzone.ai.legacyplayer; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Player; -import com.jcloisterzone.ai.AiScoreContext; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.CompletableFeature; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.SelfReturningVisitor; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Special; - -class LegacyAiScoreContext extends SelfReturningVisitor implements CompletableScoreContext, AiScoreContext { - - public static class OpenEdge { - double chanceToClose; - Feature feature; - Location location; - } - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final LegacyAiPlayer aiPlayer; - private final CompletableScoreContext ctx; - //private final Map scoreCache; - private boolean valid = true; - - private Map openEdgesChanceToClose = new HashMap<>(); - private double chanceToClose = 1.0; - - public LegacyAiScoreContext(LegacyAiPlayer aiPlayer, CompletableScoreContext ctx/*, Map scoreCache*/) { - this.aiPlayer = aiPlayer; - this.ctx = ctx; - //this.scoreCache = scoreCache; - } - - @Override - public boolean isValid() { - return valid; - }; - - public void setValid(boolean valid) { - this.valid = valid; - } - - public double getChanceToClose() { - if (chanceToClose > 0.95) { - return 0.95; - } - return chanceToClose; - } - - private double updateCompletableChanceToClose(CompletableFeature completable) { - double result = 1.0; - //TODO: this method using internal contract of MultiTileFeature - encapsulation is violated here - int i = 0; - for (Location side : Location.sides()) { - if (side.intersect(completable.getLocation()) != null) { - if (completable.getEdges()[i] == null) { - //side is open - Position p = completable.getTile().getPosition().add(side); - if (!openEdgesChanceToClose.containsKey(p)) { - OpenEdge edge = new OpenEdge(); - edge.chanceToClose = aiPlayer.chanceToPlaceTile(p); - edge.feature = completable; - edge.location = side; - openEdgesChanceToClose.put(p, edge); - result *= edge.chanceToClose; - } - } - i++; - } - } - return result; - } - - public Map getOpenEdgesChanceToClose() { - return openEdgesChanceToClose; - } - - private double updateCloisterChanceToClose(Cloister cloister) { - double result = 1.0; - Position p = cloister.getTile().getPosition(); - for (Position adjacent: p.addMulti(Position.ADJACENT_AND_DIAGONAL.values())) { - result *= aiPlayer.chanceToPlaceTile(adjacent); - } - //for "1.6-compatibility" - make it already sense ? - if (result > 0.85) return 0.85; - return result; - } - - @Override - public boolean visit(Feature feature) { - //scoreCache.put(feature, this); - - if (feature instanceof CompletableFeature) { - chanceToClose *= updateCompletableChanceToClose((CompletableFeature) feature); - } else if (feature instanceof Cloister) { - chanceToClose *= updateCloisterChanceToClose((Cloister) feature); - } - return ctx.visit(feature); - } - - public CompletableScoreContext getCompletableScoreContext() { - return ctx; - } - - @Override - public Follower getSampleFollower(Player player) { - return ctx.getSampleFollower(player); - } - - @Override - public Set getMajorOwners() { - return ctx.getMajorOwners(); - } - - @Override - public List getFollowers() { - return ctx.getFollowers(); - } - - @Override - public List getSpecialMeeples() { - return ctx.getSpecialMeeples(); - } - - @Override - public Iterable getMeeples() { - return ctx.getMeeples(); - } - - - @Override - public Completable getMasterFeature() { - return ctx.getMasterFeature(); - } - - @Override - public boolean isCompleted() { - return ctx.isCompleted(); - } - - @Override - public int getPoints() { - return ctx.getPoints(); - } - - @Override - public Set getPositions() { - return ctx.getPositions(); - } - - @Override - public Map getPowers() { - return ctx.getPowers(); - } - +package com.jcloisterzone.ai.legacyplayer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Player; +import com.jcloisterzone.ai.AiScoreContext; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.CompletableFeature; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.SelfReturningVisitor; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Special; + +class LegacyAiScoreContext extends SelfReturningVisitor implements CompletableScoreContext, AiScoreContext { + + public static class OpenEdge { + double chanceToClose; + Feature feature; + Location location; + } + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final LegacyAiPlayer aiPlayer; + private final CompletableScoreContext ctx; + //private final Map scoreCache; + private boolean valid = true; + + private Map openEdgesChanceToClose = new HashMap<>(); + private double chanceToClose = 1.0; + + public LegacyAiScoreContext(LegacyAiPlayer aiPlayer, CompletableScoreContext ctx/*, Map scoreCache*/) { + this.aiPlayer = aiPlayer; + this.ctx = ctx; + //this.scoreCache = scoreCache; + } + + @Override + public boolean isValid() { + return valid; + }; + + public void setValid(boolean valid) { + this.valid = valid; + } + + public double getChanceToClose() { + if (chanceToClose > 0.95) { + return 0.95; + } + return chanceToClose; + } + + private double updateCompletableChanceToClose(CompletableFeature completable) { + double result = 1.0; + //TODO: this method using internal contract of MultiTileFeature - encapsulation is violated here + int i = 0; + for (Location side : Location.sides()) { + if (side.intersect(completable.getLocation()) != null) { + if (completable.getEdges()[i] == null) { + //side is open + Position p = completable.getTile().getPosition().add(side); + if (!openEdgesChanceToClose.containsKey(p)) { + OpenEdge edge = new OpenEdge(); + edge.chanceToClose = aiPlayer.chanceToPlaceTile(p); + edge.feature = completable; + edge.location = side; + openEdgesChanceToClose.put(p, edge); + result *= edge.chanceToClose; + } + } + i++; + } + } + return result; + } + + public Map getOpenEdgesChanceToClose() { + return openEdgesChanceToClose; + } + + private double updateCloisterChanceToClose(Cloister cloister) { + double result = 1.0; + Position p = cloister.getTile().getPosition(); + for (Position adjacent: p.addMulti(Position.ADJACENT_AND_DIAGONAL.values())) { + result *= aiPlayer.chanceToPlaceTile(adjacent); + } + //for "1.6-compatibility" - make it already sense ? + if (result > 0.85) return 0.85; + return result; + } + + @Override + public boolean visit(Feature feature) { + //scoreCache.put(feature, this); + + if (feature instanceof CompletableFeature) { + chanceToClose *= updateCompletableChanceToClose((CompletableFeature) feature); + } else if (feature instanceof Cloister) { + chanceToClose *= updateCloisterChanceToClose((Cloister) feature); + } + return ctx.visit(feature); + } + + public CompletableScoreContext getCompletableScoreContext() { + return ctx; + } + + @Override + public Follower getSampleFollower(Player player) { + return ctx.getSampleFollower(player); + } + + @Override + public Set getMajorOwners() { + return ctx.getMajorOwners(); + } + + @Override + public List getFollowers() { + return ctx.getFollowers(); + } + + @Override + public List getSpecialMeeples() { + return ctx.getSpecialMeeples(); + } + + @Override + public Iterable getMeeples() { + return ctx.getMeeples(); + } + + + @Override + public Completable getMasterFeature() { + return ctx.getMasterFeature(); + } + + @Override + public boolean isCompleted() { + return ctx.isCompleted(); + } + + @Override + public int getPoints() { + return ctx.getPoints(); + } + + @Override + public Set getPositions() { + return ctx.getPositions(); + } + + @Override + public Map getPowers() { + return ctx.getPowers(); + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ai/operation/MeepleUndeployedOperation.java b/src/main/java/com/jcloisterzone/ai/operation/MeepleUndeployedOperation.java index 8a319a3cc..e0bb14156 100644 --- a/src/main/java/com/jcloisterzone/ai/operation/MeepleUndeployedOperation.java +++ b/src/main/java/com/jcloisterzone/ai/operation/MeepleUndeployedOperation.java @@ -1,32 +1,32 @@ -package com.jcloisterzone.ai.operation; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; - -public class MeepleUndeployedOperation implements Operation { - - private final Meeple meeple; - private Tile tile; - private Location loc; - - public MeepleUndeployedOperation(Meeple meeple) { - this.meeple = meeple; - this.tile = meeple.getFeature() == null ? null : meeple.getFeature().getTile(); //prison undeploy - this.loc = meeple.getLocation(); - } - - @Override - public void undo(Game game) { - meeple.setLocation(loc); - if (tile != null) { - Feature feature = meeple.getPieceForDeploy(tile, loc); - feature.addMeeple(meeple); - meeple.setPosition(tile.getPosition()); - meeple.setFeature(feature); - } - } - -} +package com.jcloisterzone.ai.operation; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; + +public class MeepleUndeployedOperation implements Operation { + + private final Meeple meeple; + private Tile tile; + private Location loc; + + public MeepleUndeployedOperation(Meeple meeple) { + this.meeple = meeple; + this.tile = meeple.getFeature() == null ? null : meeple.getFeature().getTile(); //prison undeploy + this.loc = meeple.getLocation(); + } + + @Override + public void undo(Game game) { + meeple.setLocation(loc); + if (tile != null) { + Feature feature = meeple.getPieceForDeploy(tile, loc); + feature.addMeeple(meeple); + meeple.setPosition(tile.getPosition()); + meeple.setFeature(feature); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ai/operation/TilePlacedOperation.java b/src/main/java/com/jcloisterzone/ai/operation/TilePlacedOperation.java index 1567b0b76..8035b2edd 100644 --- a/src/main/java/com/jcloisterzone/ai/operation/TilePlacedOperation.java +++ b/src/main/java/com/jcloisterzone/ai/operation/TilePlacedOperation.java @@ -1,24 +1,24 @@ -package com.jcloisterzone.ai.operation; - -import com.jcloisterzone.board.DefaultTilePack; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.game.Game; - -public class TilePlacedOperation implements Operation { - - private final Tile tile; - - public TilePlacedOperation(Tile tile) { - this.tile = tile; - } - - @Override - public void undo(Game game) { - game.getBoard().unmergeFeatures(tile); - game.getBoard().remove(tile); - if (tile.isAbbeyTile()) { - ((DefaultTilePack)game.getTilePack()).addTile(tile, TilePack.INACTIVE_GROUP); - } - } -} +package com.jcloisterzone.ai.operation; + +import com.jcloisterzone.board.DefaultTilePack; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.game.Game; + +public class TilePlacedOperation implements Operation { + + private final Tile tile; + + public TilePlacedOperation(Tile tile) { + this.tile = tile; + } + + @Override + public void undo(Game game) { + game.getBoard().unmergeFeatures(tile); + game.getBoard().remove(tile); + if (tile.isAbbeyTile()) { + ((DefaultTilePack)game.getTilePack()).addTile(tile, TilePack.INACTIVE_GROUP); + } + } +} diff --git a/src/main/java/com/jcloisterzone/board/Board.java b/src/main/java/com/jcloisterzone/board/Board.java index ab889bb03..40493d69e 100644 --- a/src/main/java/com/jcloisterzone/board/Board.java +++ b/src/main/java/com/jcloisterzone/board/Board.java @@ -1,276 +1,276 @@ -package com.jcloisterzone.board; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.BridgeCapability; - - -/** - * Board represent game board with any size, so Tile instances ale - * stored in Map. Board supplies proper merging of score objects - * (Road, City or Farm) - * and diagonal merge for Cloister instances. - - */ -public class Board { - protected final Map tiles = new LinkedHashMap(); - protected final Map availMoves = new HashMap<>(); - protected final Map> currentAvailMoves = new HashMap<>(); - protected final Set holes = new HashSet<>(); - - private int maxX, minX, maxY, minY; - - private final Game game; - -// protected Set tunnels = new HashSet<>(); -// protected Map openTunnels = new HashMap<>(); //tunnel with open one side - - protected List discardedTiles = new ArrayList<>(); - - - public Board(Game game) { - this.game = game; - } - - /** - * Updates current avail moves for next turn - * @param tile next tile - */ - public void refreshAvailablePlacements(Tile tile) { - Rotation tileRotation = tile.getRotation(); - currentAvailMoves.clear(); - for (Position p : availMoves.keySet()) { - EnumSet allowed = EnumSet.noneOf(Rotation.class); - for (Rotation rotation: Rotation.values()) { - tile.setRotation(rotation); - if (!isPlacementAllowed(tile, p)) { - //not allowed according standard rules, must check if deployed bridge can allow it - if (!game.hasCapability(BridgeCapability.class)) continue; - if (!game.getCapability(BridgeCapability.class).isTilePlacementWithBridgePossible(tile, p)) continue; - } - if (!game.isTilePlacementAllowed(tile, p)) continue; - allowed.add(rotation); - } - if (!allowed.isEmpty()) { - currentAvailMoves.put(p, allowed); - } - } - tile.setRotation(tileRotation); //reset rotation - } - - - protected void availMovesAdd(Position pos) { - availMoves.put(pos, EdgePattern.forEmptyTile(this, pos)); - } - - protected void availMovesRemove(Position pos) { - availMoves.remove(pos); - } - - public EdgePattern getAvailMoveEdgePattern(Position pos) { - return availMoves.get(pos); - } - - - /** - * Place tile on given position. Check for correct placement (check if neigbours - * edges match with tile edges according to Carcassonne rules - * @param tile tile to place - * @param p position to place - * @throws IllegalMoveException if placement is violate game rules - */ - public void add(Tile tile, Position p) { - add(tile, p, false); - } - - public void add(Tile tile, Position p, boolean unchecked) { - if (!unchecked) { - if (tile.isAbbeyTile()) { - if (!holes.contains(p)) { - throw new IllegalArgumentException("Abbey must be placed inside hole"); - } - } else { - if (!currentAvailMoves.containsKey(p)) { - throw new IllegalArgumentException("Invalid position " + p); - } - if (!currentAvailMoves.get(p).contains(tile.getRotation())) { - throw new IllegalArgumentException("Incorrect rotation " + tile.getRotation() + " "+ p); - } - } - } - - tiles.put(p, tile); - availMovesRemove(p); - - for (Position offset: Position.ADJACENT.values()) { - Position next = p.add(offset); - if (get(next) == null) { - availMovesAdd(next); - if (isHole(next)) { - holes.add(next); - } - } - } - holes.remove(p); - tile.setPosition(p); - if (p.x > maxX) maxX = p.x; - if (p.x < minX) minX = p.x; - if (p.y > maxY) maxY = p.y; - if (p.y < minY) minY = p.y; - } - - public void mergeFeatures(Tile tile) { - for (Entry e : getAdjacentTilesMap(tile.getPosition()).entrySet()) { - tile.merge(e.getValue(), e.getKey()); - } - } - - public void remove(Tile tile) { - Position pos = tile.getPosition(); - assert pos != null; - tiles.remove(pos); - tile.setPosition(null); - availMovesAdd(pos); - if (isHole(pos)) holes.add(pos); - for (Position offset: Position.ADJACENT.values()) { - Position next = pos.add(offset); - holes.remove(next); - if (getAdjacentCount(next) == 0) { - availMoves.remove(next); - } - } - } - - public void unmergeFeatures(Tile tile) { - assert tile.getPosition() != null; - for (Entry e : getAdjacentTilesMap(tile.getPosition()).entrySet()) { - tile.unmerge(e.getValue(), e.getKey()); - } - } - - public void discardTile(Tile tile) { - discardedTiles.add(tile); - game.fireGameEvent().tileDiscarded(tile); - } - - - public List getDiscardedTiles() { - return discardedTiles; - } - - private boolean isHole(Position p) { - for (Position offset: Position.ADJACENT.values()) { - Position next = p.add(offset); - if (get(next) == null) { - return false; - } - } - return true; - } - - private int getAdjacentCount(Position p) { - int count = 0; - for (Position offset: Position.ADJACENT.values()) { - Position next = p.add(offset); - if (get(next) != null) { - count++; - } - } - return count; - } - - public Map> getAvailablePlacements() { - return currentAvailMoves; - } - - public Set getAvailablePlacementPositions() { - return currentAvailMoves.keySet(); - } - - public Set getHoles() { - return holes; - } - - - /** - * Returns tile on position with cordinates x,y. - * @param x x-coordinate - * @param y y-coordinate - * @return demand tile - */ - public Tile get(int x, int y) { - return tiles.get(new Position(x, y)); - } - - public Tile get(Position p) { - return tiles.get(p); - } - - public Collection getAllTiles() { - return tiles.values(); - } - - /* - * Check if placement is legal against orthonogal neigbours. */ - public boolean isPlacementAllowed(Tile tile, Position p) { - for (Entry e : getAdjacentTilesMap(p).entrySet()) { - if (!tile.check(e.getValue(), e.getKey(), this)) { - return false; - } - } - return true; - } - - public int getMaxX() { - return maxX; - } - - public int getMinX() { - return minX; - } - - public int getMaxY() { - return maxY; - } - - public int getMinY() { - return minY; - } - - public List getMulti(Position[] positions) { - List tiles = new ArrayList<>(); - for (Position p : positions) { - Tile t = get(p); - if (t != null) { - tiles.add(t); - } - } - return tiles; - } - - public Map getAdjacentTilesMap(Position pos) { - Map tiles = new HashMap(4); - for (Entry e: Position.ADJACENT.entrySet()) { - Tile tile = get(e.getValue().add(pos)); - if (tile != null) { - tiles.put(e.getKey(), tile); - } - } - return tiles; - } - - public List getAdjacentAndDiagonalTiles(Position pos) { - return getMulti(pos.addMulti(Position.ADJACENT_AND_DIAGONAL.values())); - } - -} +package com.jcloisterzone.board; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.BridgeCapability; + + +/** + * Board represent game board with any size, so Tile instances ale + * stored in Map. Board supplies proper merging of score objects + * (Road, City or Farm) + * and diagonal merge for Cloister instances. + + */ +public class Board { + protected final Map tiles = new LinkedHashMap(); + protected final Map availMoves = new HashMap<>(); + protected final Map> currentAvailMoves = new HashMap<>(); + protected final Set holes = new HashSet<>(); + + private int maxX, minX, maxY, minY; + + private final Game game; + +// protected Set tunnels = new HashSet<>(); +// protected Map openTunnels = new HashMap<>(); //tunnel with open one side + + protected List discardedTiles = new ArrayList<>(); + + + public Board(Game game) { + this.game = game; + } + + /** + * Updates current avail moves for next turn + * @param tile next tile + */ + public void refreshAvailablePlacements(Tile tile) { + Rotation tileRotation = tile.getRotation(); + currentAvailMoves.clear(); + for (Position p : availMoves.keySet()) { + EnumSet allowed = EnumSet.noneOf(Rotation.class); + for (Rotation rotation: Rotation.values()) { + tile.setRotation(rotation); + if (!isPlacementAllowed(tile, p)) { + //not allowed according standard rules, must check if deployed bridge can allow it + if (!game.hasCapability(BridgeCapability.class)) continue; + if (!game.getCapability(BridgeCapability.class).isTilePlacementWithBridgePossible(tile, p)) continue; + } + if (!game.isTilePlacementAllowed(tile, p)) continue; + allowed.add(rotation); + } + if (!allowed.isEmpty()) { + currentAvailMoves.put(p, allowed); + } + } + tile.setRotation(tileRotation); //reset rotation + } + + + protected void availMovesAdd(Position pos) { + availMoves.put(pos, EdgePattern.forEmptyTile(this, pos)); + } + + protected void availMovesRemove(Position pos) { + availMoves.remove(pos); + } + + public EdgePattern getAvailMoveEdgePattern(Position pos) { + return availMoves.get(pos); + } + + + /** + * Place tile on given position. Check for correct placement (check if neigbours + * edges match with tile edges according to Carcassonne rules + * @param tile tile to place + * @param p position to place + * @throws IllegalMoveException if placement is violate game rules + */ + public void add(Tile tile, Position p) { + add(tile, p, false); + } + + public void add(Tile tile, Position p, boolean unchecked) { + if (!unchecked) { + if (tile.isAbbeyTile()) { + if (!holes.contains(p)) { + throw new IllegalArgumentException("Abbey must be placed inside hole"); + } + } else { + if (!currentAvailMoves.containsKey(p)) { + throw new IllegalArgumentException("Invalid position " + p); + } + if (!currentAvailMoves.get(p).contains(tile.getRotation())) { + throw new IllegalArgumentException("Incorrect rotation " + tile.getRotation() + " "+ p); + } + } + } + + tiles.put(p, tile); + availMovesRemove(p); + + for (Position offset: Position.ADJACENT.values()) { + Position next = p.add(offset); + if (get(next) == null) { + availMovesAdd(next); + if (isHole(next)) { + holes.add(next); + } + } + } + holes.remove(p); + tile.setPosition(p); + if (p.x > maxX) maxX = p.x; + if (p.x < minX) minX = p.x; + if (p.y > maxY) maxY = p.y; + if (p.y < minY) minY = p.y; + } + + public void mergeFeatures(Tile tile) { + for (Entry e : getAdjacentTilesMap(tile.getPosition()).entrySet()) { + tile.merge(e.getValue(), e.getKey()); + } + } + + public void remove(Tile tile) { + Position pos = tile.getPosition(); + assert pos != null; + tiles.remove(pos); + tile.setPosition(null); + availMovesAdd(pos); + if (isHole(pos)) holes.add(pos); + for (Position offset: Position.ADJACENT.values()) { + Position next = pos.add(offset); + holes.remove(next); + if (getAdjacentCount(next) == 0) { + availMoves.remove(next); + } + } + } + + public void unmergeFeatures(Tile tile) { + assert tile.getPosition() != null; + for (Entry e : getAdjacentTilesMap(tile.getPosition()).entrySet()) { + tile.unmerge(e.getValue(), e.getKey()); + } + } + + public void discardTile(Tile tile) { + discardedTiles.add(tile); + game.fireGameEvent().tileDiscarded(tile); + } + + + public List getDiscardedTiles() { + return discardedTiles; + } + + private boolean isHole(Position p) { + for (Position offset: Position.ADJACENT.values()) { + Position next = p.add(offset); + if (get(next) == null) { + return false; + } + } + return true; + } + + private int getAdjacentCount(Position p) { + int count = 0; + for (Position offset: Position.ADJACENT.values()) { + Position next = p.add(offset); + if (get(next) != null) { + count++; + } + } + return count; + } + + public Map> getAvailablePlacements() { + return currentAvailMoves; + } + + public Set getAvailablePlacementPositions() { + return currentAvailMoves.keySet(); + } + + public Set getHoles() { + return holes; + } + + + /** + * Returns tile on position with cordinates x,y. + * @param x x-coordinate + * @param y y-coordinate + * @return demand tile + */ + public Tile get(int x, int y) { + return tiles.get(new Position(x, y)); + } + + public Tile get(Position p) { + return tiles.get(p); + } + + public Collection getAllTiles() { + return tiles.values(); + } + + /* + * Check if placement is legal against orthonogal neigbours. */ + public boolean isPlacementAllowed(Tile tile, Position p) { + for (Entry e : getAdjacentTilesMap(p).entrySet()) { + if (!tile.check(e.getValue(), e.getKey(), this)) { + return false; + } + } + return true; + } + + public int getMaxX() { + return maxX; + } + + public int getMinX() { + return minX; + } + + public int getMaxY() { + return maxY; + } + + public int getMinY() { + return minY; + } + + public List getMulti(Position[] positions) { + List tiles = new ArrayList<>(); + for (Position p : positions) { + Tile t = get(p); + if (t != null) { + tiles.add(t); + } + } + return tiles; + } + + public Map getAdjacentTilesMap(Position pos) { + Map tiles = new HashMap(4); + for (Entry e: Position.ADJACENT.entrySet()) { + Tile tile = get(e.getValue().add(pos)); + if (tile != null) { + tiles.put(e.getKey(), tile); + } + } + return tiles; + } + + public List getAdjacentAndDiagonalTiles(Position pos) { + return getMulti(pos.addMulti(Position.ADJACENT_AND_DIAGONAL.values())); + } + +} diff --git a/src/main/java/com/jcloisterzone/board/DefaultTilePack.java b/src/main/java/com/jcloisterzone/board/DefaultTilePack.java index 826b7ad57..74d7a9b29 100644 --- a/src/main/java/com/jcloisterzone/board/DefaultTilePack.java +++ b/src/main/java/com/jcloisterzone/board/DefaultTilePack.java @@ -1,194 +1,194 @@ -package com.jcloisterzone.board; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DefaultTilePack implements TilePack { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private static final String INACTIVE_GROUP = "inactive"; - - private Map> groups = new HashMap<>(); - private Set activeGroups = new HashSet<>(); - - private Map edgePatterns = new HashMap<>(); - - @Override - public int totalSize() { - int n = 0; - for (Entry> entry: groups.entrySet()) { - if (!entry.getKey().equals(INACTIVE_GROUP)) { - n += entry.getValue().size(); - } - } - return n; - } - - @Override - public boolean isEmpty() { - return size() == 0; - } - - @Override - public int size() { - int n = 0; - for (String key: activeGroups) { - n += groups.get(key).size(); - } - return n; - } - - @Override - public Tile drawTile(int index) { - for (String key: activeGroups) { - ArrayList group = groups.get(key); - if (index < group.size()) { - Tile currentTile = group.remove(index); - decreaseSideMaskCounter(currentTile, key); - return currentTile; - } else { - index -= group.size(); - } - } - throw new ArrayIndexOutOfBoundsException(); - } - - private void increaseSideMaskCounter(Tile tile, String groupId) { - if (!INACTIVE_GROUP.equals(groupId) && tile.getPosition() == null) { - Integer countForSideMask = edgePatterns.get(tile.getEdgePattern()); - if (countForSideMask == null) { - edgePatterns.put(tile.getEdgePattern(), 1); - } else { - edgePatterns.put(tile.getEdgePattern(), countForSideMask + 1); - } - } - } - - private void decreaseSideMaskCounter(Tile tile, String groupId) { - if (tile == null || groupId.equals(INACTIVE_GROUP)) return; - Integer count = edgePatterns.get(tile.getEdgePattern()); - if (count == null) { - logger.error("Inconsistent edge mask statistics. Cannot decrease: " + tile.getEdgePattern().toString()); - return; - } - if (count == 1) { - edgePatterns.remove(tile.getEdgePattern()); - } else { - edgePatterns.put(tile.getEdgePattern(), count - 1); - } - } - - @Override - public Tile drawTile(String groupId, String tileId) { - ArrayList group = groups.get(groupId); - Iterator i = group.iterator(); - while(i.hasNext()) { - Tile tile = i.next(); - if (tile.getId().equals(tileId)) { - i.remove(); - decreaseSideMaskCounter(tile, groupId); - return tile; - } - } - return null; - } - - @Override - public Tile drawTile(String tileId) { - for (String groupId: groups.keySet()) { - Tile tile = drawTile(groupId, tileId); - if (tile != null) return tile; - } - logger.warn("Tile pack does not contain {}", tileId); - return null; - } - - public List drawPrePlacedActiveTiles() { - List result = new ArrayList<>(); - for (Entry> entry: groups.entrySet()) { - ArrayList group = entry.getValue(); - Iterator i = group.iterator(); - while(i.hasNext()) { - Tile tile = i.next(); - if (tile.getPosition() != null) { - if (activeGroups.contains(entry.getKey())) { - result.add(tile); - i.remove(); - } else { - tile.setPosition(null); - increaseSideMaskCounter(tile, entry.getKey()); - } - } - } - } - return result; - } - - public void addTile(Tile tile, String groupId) { - if (!groups.containsKey(groupId)) { - groups.put(groupId, new ArrayList()); - } - ArrayList group = groups.get(groupId); - group.add(tile); - increaseSideMaskCounter(tile, groupId); - } - - @Override - public void activateGroup(String group) { - //check if group exists - game load can cause activation on empty (and non existing after load) group - if (groups.containsKey(group)) { - activeGroups.add(group); - } - } - - @Override - public void deactivateGroup(String group) { - activeGroups.remove(group); - } - - public void deactivateAllGroups() { - activeGroups.clear(); - } - - @Override - public boolean isGroupActive(String group) { - return activeGroups.contains(group); - } - - @Override - public Set getGroups() { - return groups.keySet(); - } - - /* special Abbey related methods - refactor je to jen kvuli klientovi */ - @Override - public Tile getAbbeyTile() { - for (Tile tile : groups.get(INACTIVE_GROUP)) { - if (tile.getId().equals(Tile.ABBEY_TILE_ID)) { - return tile; - } - } - return null; - } - - @Override - public int getSizeForEdgePattern(EdgePattern pattern) { - int size = 0; - for (EdgePattern filled : pattern.fill()) { - Integer count = edgePatterns.get(filled); - size += count == null ? 0 : count; - } - return size; - } - -} +package com.jcloisterzone.board; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DefaultTilePack implements TilePack { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private static final String INACTIVE_GROUP = "inactive"; + + private Map> groups = new HashMap<>(); + private Set activeGroups = new HashSet<>(); + + private Map edgePatterns = new HashMap<>(); + + @Override + public int totalSize() { + int n = 0; + for (Entry> entry: groups.entrySet()) { + if (!entry.getKey().equals(INACTIVE_GROUP)) { + n += entry.getValue().size(); + } + } + return n; + } + + @Override + public boolean isEmpty() { + return size() == 0; + } + + @Override + public int size() { + int n = 0; + for (String key: activeGroups) { + n += groups.get(key).size(); + } + return n; + } + + @Override + public Tile drawTile(int index) { + for (String key: activeGroups) { + ArrayList group = groups.get(key); + if (index < group.size()) { + Tile currentTile = group.remove(index); + decreaseSideMaskCounter(currentTile, key); + return currentTile; + } else { + index -= group.size(); + } + } + throw new ArrayIndexOutOfBoundsException(); + } + + private void increaseSideMaskCounter(Tile tile, String groupId) { + if (!INACTIVE_GROUP.equals(groupId) && tile.getPosition() == null) { + Integer countForSideMask = edgePatterns.get(tile.getEdgePattern()); + if (countForSideMask == null) { + edgePatterns.put(tile.getEdgePattern(), 1); + } else { + edgePatterns.put(tile.getEdgePattern(), countForSideMask + 1); + } + } + } + + private void decreaseSideMaskCounter(Tile tile, String groupId) { + if (tile == null || groupId.equals(INACTIVE_GROUP)) return; + Integer count = edgePatterns.get(tile.getEdgePattern()); + if (count == null) { + logger.error("Inconsistent edge mask statistics. Cannot decrease: " + tile.getEdgePattern().toString()); + return; + } + if (count == 1) { + edgePatterns.remove(tile.getEdgePattern()); + } else { + edgePatterns.put(tile.getEdgePattern(), count - 1); + } + } + + @Override + public Tile drawTile(String groupId, String tileId) { + ArrayList group = groups.get(groupId); + Iterator i = group.iterator(); + while(i.hasNext()) { + Tile tile = i.next(); + if (tile.getId().equals(tileId)) { + i.remove(); + decreaseSideMaskCounter(tile, groupId); + return tile; + } + } + return null; + } + + @Override + public Tile drawTile(String tileId) { + for (String groupId: groups.keySet()) { + Tile tile = drawTile(groupId, tileId); + if (tile != null) return tile; + } + logger.warn("Tile pack does not contain {}", tileId); + return null; + } + + public List drawPrePlacedActiveTiles() { + List result = new ArrayList<>(); + for (Entry> entry: groups.entrySet()) { + ArrayList group = entry.getValue(); + Iterator i = group.iterator(); + while(i.hasNext()) { + Tile tile = i.next(); + if (tile.getPosition() != null) { + if (activeGroups.contains(entry.getKey())) { + result.add(tile); + i.remove(); + } else { + tile.setPosition(null); + increaseSideMaskCounter(tile, entry.getKey()); + } + } + } + } + return result; + } + + public void addTile(Tile tile, String groupId) { + if (!groups.containsKey(groupId)) { + groups.put(groupId, new ArrayList()); + } + ArrayList group = groups.get(groupId); + group.add(tile); + increaseSideMaskCounter(tile, groupId); + } + + @Override + public void activateGroup(String group) { + //check if group exists - game load can cause activation on empty (and non existing after load) group + if (groups.containsKey(group)) { + activeGroups.add(group); + } + } + + @Override + public void deactivateGroup(String group) { + activeGroups.remove(group); + } + + public void deactivateAllGroups() { + activeGroups.clear(); + } + + @Override + public boolean isGroupActive(String group) { + return activeGroups.contains(group); + } + + @Override + public Set getGroups() { + return groups.keySet(); + } + + /* special Abbey related methods - refactor je to jen kvuli klientovi */ + @Override + public Tile getAbbeyTile() { + for (Tile tile : groups.get(INACTIVE_GROUP)) { + if (tile.getId().equals(Tile.ABBEY_TILE_ID)) { + return tile; + } + } + return null; + } + + @Override + public int getSizeForEdgePattern(EdgePattern pattern) { + int size = 0; + for (EdgePattern filled : pattern.fill()) { + Integer count = edgePatterns.get(filled); + size += count == null ? 0 : count; + } + return size; + } + +} diff --git a/src/main/java/com/jcloisterzone/board/EdgePattern.java b/src/main/java/com/jcloisterzone/board/EdgePattern.java index 441755381..df9222d55 100644 --- a/src/main/java/com/jcloisterzone/board/EdgePattern.java +++ b/src/main/java/com/jcloisterzone/board/EdgePattern.java @@ -1,175 +1,175 @@ -package com.jcloisterzone.board; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.Queue; - -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; - -public class EdgePattern { - - private char[] code = new char[4]; - - private EdgePattern() { } - private EdgePattern(char[] code) { this.code = code; } - - private static char getTileEdgePattern(Tile tile, Location loc) { - Feature f = tile.getFeaturePartOf(loc); - if (f == null) { - return 'F'; - } - if (f instanceof Road) { - return 'R'; - } - return 'C'; - } - - public static EdgePattern forTile(Tile tile) { - EdgePattern pattern = new EdgePattern(); - for (Location loc : Location.sides()) { - pattern.code[indexfor (loc)] = getTileEdgePattern(tile, loc); - } - return pattern; - } - - private static int indexfor (Location loc) { - if (loc == Location.N) return 0; - if (loc == Location.W) return 1; - if (loc == Location.S) return 2; - if (loc == Location.E) return 3; - throw new IllegalArgumentException(); - } - - public static EdgePattern forEmptyTile(Board board, Position pos) { - EdgePattern pattern = new EdgePattern(); - for (Location loc : Location.sides()) { - Tile t = board.get(pos.add(loc)); - int idx = indexfor (loc); - if (t == null) { - pattern.code[idx] = '?'; - } else { - pattern.code[idx] = getTileEdgePattern(t, loc.rev()); - } - } - return pattern; - } - - public char at(Location loc) { - return code[indexfor (loc)]; - } - - public char at(Location loc, Rotation rotation) { - return at(loc.rotateCCW(rotation)); - } - - public int wildcardSize() { - int size = 0; - for (int i = 0; i < code.length; i++) { - if (code[i] == '?') size++; - } - return size; - } - - private EdgePattern switchEdge(int i, char ch) { - char[] switched = Arrays.copyOf(code, code.length); - switched[i] = ch; - return new EdgePattern(switched); - } - - public Collection fill() { - //TODO better impl - if (wildcardSize() == 0) return Collections.singleton(this); - Queue q = new LinkedList(); - q.add(this); - while(q.peek().wildcardSize() > 0) { - EdgePattern p = q.poll(); - int i = 0; - while(p.code[i] != '?') i++; - q.add(switchEdge(i, 'R')); - q.add(switchEdge(i, 'C')); - q.add(switchEdge(i, 'F')); - } - return q; - } - - private char[] shift(int shift) { - char[] result = new char[4]; - for (int i = 0; i < code.length; i++) { - result[i] = code[(i+shift)%code.length]; - } - return result; - } - - private char[] canonize() { - char[] result = code; - shiftLoop: - for (int shift = 1; shift < code.length; shift++) { - char[] c = shift(shift); - for (int i = 0; i < code.length; i++) { - if (c[i] < result[i]) { - result = c; - continue shiftLoop; - } - if (c[i] > result[i]) { - break; - } - } - } - return result; - } - - public boolean isBridgeAllowed(Location bridge, Rotation tileRotation) { - if (bridge == Location.NS) { - if (at(Location.N, tileRotation) != 'F') return false; - if (at(Location.S, tileRotation) != 'F') return false; - } else { - if (at(Location.W, tileRotation) != 'F') return false; - if (at(Location.E, tileRotation) != 'F') return false; - } - return true; - } - - public EdgePattern getBridgePattern(Location bridge) { - char[] bridgeCode = Arrays.copyOf(code, code.length); - if (bridge == Location.NS) { - bridgeCode[0] = 'R'; - bridgeCode[2] = 'R'; - } else { - bridgeCode[1] = 'R'; - bridgeCode[3] = 'R'; - } - return new EdgePattern(bridgeCode); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof EdgePattern)) return false; - EdgePattern that = (EdgePattern) obj; - return Arrays.equals(that.canonize(), canonize()); - } - - @Override - public int hashCode() { - char[] c = canonize(); - int hash = 0; - for (int i = 0; i < c.length; i++) { - hash = hash * 91 + c[i]; - } - return hash; - } - - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < code.length; i++) { - sb.append(code[i]); - } - return sb.toString(); - } - -} +package com.jcloisterzone.board; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.Queue; + +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; + +public class EdgePattern { + + private char[] code = new char[4]; + + private EdgePattern() { } + private EdgePattern(char[] code) { this.code = code; } + + private static char getTileEdgePattern(Tile tile, Location loc) { + Feature f = tile.getFeaturePartOf(loc); + if (f == null) { + return 'F'; + } + if (f instanceof Road) { + return 'R'; + } + return 'C'; + } + + public static EdgePattern forTile(Tile tile) { + EdgePattern pattern = new EdgePattern(); + for (Location loc : Location.sides()) { + pattern.code[indexfor (loc)] = getTileEdgePattern(tile, loc); + } + return pattern; + } + + private static int indexfor (Location loc) { + if (loc == Location.N) return 0; + if (loc == Location.W) return 1; + if (loc == Location.S) return 2; + if (loc == Location.E) return 3; + throw new IllegalArgumentException(); + } + + public static EdgePattern forEmptyTile(Board board, Position pos) { + EdgePattern pattern = new EdgePattern(); + for (Location loc : Location.sides()) { + Tile t = board.get(pos.add(loc)); + int idx = indexfor (loc); + if (t == null) { + pattern.code[idx] = '?'; + } else { + pattern.code[idx] = getTileEdgePattern(t, loc.rev()); + } + } + return pattern; + } + + public char at(Location loc) { + return code[indexfor (loc)]; + } + + public char at(Location loc, Rotation rotation) { + return at(loc.rotateCCW(rotation)); + } + + public int wildcardSize() { + int size = 0; + for (int i = 0; i < code.length; i++) { + if (code[i] == '?') size++; + } + return size; + } + + private EdgePattern switchEdge(int i, char ch) { + char[] switched = Arrays.copyOf(code, code.length); + switched[i] = ch; + return new EdgePattern(switched); + } + + public Collection fill() { + //TODO better impl + if (wildcardSize() == 0) return Collections.singleton(this); + Queue q = new LinkedList(); + q.add(this); + while(q.peek().wildcardSize() > 0) { + EdgePattern p = q.poll(); + int i = 0; + while(p.code[i] != '?') i++; + q.add(switchEdge(i, 'R')); + q.add(switchEdge(i, 'C')); + q.add(switchEdge(i, 'F')); + } + return q; + } + + private char[] shift(int shift) { + char[] result = new char[4]; + for (int i = 0; i < code.length; i++) { + result[i] = code[(i+shift)%code.length]; + } + return result; + } + + private char[] canonize() { + char[] result = code; + shiftLoop: + for (int shift = 1; shift < code.length; shift++) { + char[] c = shift(shift); + for (int i = 0; i < code.length; i++) { + if (c[i] < result[i]) { + result = c; + continue shiftLoop; + } + if (c[i] > result[i]) { + break; + } + } + } + return result; + } + + public boolean isBridgeAllowed(Location bridge, Rotation tileRotation) { + if (bridge == Location.NS) { + if (at(Location.N, tileRotation) != 'F') return false; + if (at(Location.S, tileRotation) != 'F') return false; + } else { + if (at(Location.W, tileRotation) != 'F') return false; + if (at(Location.E, tileRotation) != 'F') return false; + } + return true; + } + + public EdgePattern getBridgePattern(Location bridge) { + char[] bridgeCode = Arrays.copyOf(code, code.length); + if (bridge == Location.NS) { + bridgeCode[0] = 'R'; + bridgeCode[2] = 'R'; + } else { + bridgeCode[1] = 'R'; + bridgeCode[3] = 'R'; + } + return new EdgePattern(bridgeCode); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof EdgePattern)) return false; + EdgePattern that = (EdgePattern) obj; + return Arrays.equals(that.canonize(), canonize()); + } + + @Override + public int hashCode() { + char[] c = canonize(); + int hash = 0; + for (int i = 0; i < c.length; i++) { + hash = hash * 91 + c[i]; + } + return hash; + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < code.length; i++) { + sb.append(code[i]); + } + return sb.toString(); + } + +} diff --git a/src/main/java/com/jcloisterzone/board/LoadGameTilePackFactory.java b/src/main/java/com/jcloisterzone/board/LoadGameTilePackFactory.java index b9e44c63a..af17ce43c 100644 --- a/src/main/java/com/jcloisterzone/board/LoadGameTilePackFactory.java +++ b/src/main/java/com/jcloisterzone/board/LoadGameTilePackFactory.java @@ -1,113 +1,113 @@ -package com.jcloisterzone.board; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Snapshot; - - -public class LoadGameTilePackFactory extends TilePackFactory { - - public static final String PLACED_GROUP = "placed"; - - private Snapshot snapshot; - - private List preplacedMeeples = new ArrayList<>(); - - //TODO is required to store information from snapshot outside ? - class PreplacedTile { - String tileId; - Position pos; - Rotation rot; - Tile tile; - Element element; - } - PreplacedTile[] preplaced; - - public Snapshot getSnapshot() { - return snapshot; - } - - public void setSnapshot(Snapshot snapshot) { - this.snapshot = snapshot; - - NodeList nl = snapshot.getTileElements(); - preplaced = new PreplacedTile[nl.getLength()]; - - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - preplaced[i] = new PreplacedTile(); - preplaced[i].tileId = el.getAttribute("name"); - preplaced[i].pos = XmlUtils.extractPosition(el); - preplaced[i].rot = snapshot.extractTileRotation(el); - preplaced[i].element = el; - preplacedMeeples.addAll(snapshot.extractTileMeeples(el, game, preplaced[i].pos)); - } - } - - - @Override - public LinkedList getPreplacedPositions(String tileId, Element card) { - return null; - } - - @Override - public List createTiles(Expansion expansion, String tileId, Element card, Map discardList) { - List result = super.createTiles(expansion, tileId, card, discardList); - for (PreplacedTile pt : preplaced) { - if (pt.tile == null && pt.tileId.equals(tileId)) { - pt.tile = result.remove(result.size()-1); - game.loadTileFromSnapshot(pt.tile, pt.element); - } - if (result.isEmpty()) { - break; - } - } - return result; - } - - public List getPreplacedMeeples() { - return preplacedMeeples; - } - - @Override - protected String getTileGroup(Tile tile, Element card) { - if (tile.getPosition() != null) { - return PLACED_GROUP; //special placed group (because all placed must be in active group) - } - return super.getTileGroup(tile, card); - } - - @Override - public DefaultTilePack createTilePack() { - DefaultTilePack pack = super.createTilePack(); - for (PreplacedTile pt : preplaced) { - pt.tile.setRotation(pt.rot); - pt.tile.setPosition(pt.pos); - pack.addTile(pt.tile, PLACED_GROUP); - } - pack.activateGroup(PLACED_GROUP); - if (preplaced.length > 0) { - game.setCurrentTile(preplaced[preplaced.length-1].tile); - } - return pack; - } - - public void activateGroups(DefaultTilePack pack) { - pack.deactivateAllGroups(); - for (String group : snapshot.getActiveGroups()) { - if (pack.getGroups().contains(group)) { - pack.activateGroup(group); - } - } - } - -} +package com.jcloisterzone.board; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Snapshot; + + +public class LoadGameTilePackFactory extends TilePackFactory { + + public static final String PLACED_GROUP = "placed"; + + private Snapshot snapshot; + + private List preplacedMeeples = new ArrayList<>(); + + //TODO is required to store information from snapshot outside ? + class PreplacedTile { + String tileId; + Position pos; + Rotation rot; + Tile tile; + Element element; + } + PreplacedTile[] preplaced; + + public Snapshot getSnapshot() { + return snapshot; + } + + public void setSnapshot(Snapshot snapshot) { + this.snapshot = snapshot; + + NodeList nl = snapshot.getTileElements(); + preplaced = new PreplacedTile[nl.getLength()]; + + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + preplaced[i] = new PreplacedTile(); + preplaced[i].tileId = el.getAttribute("name"); + preplaced[i].pos = XmlUtils.extractPosition(el); + preplaced[i].rot = snapshot.extractTileRotation(el); + preplaced[i].element = el; + preplacedMeeples.addAll(snapshot.extractTileMeeples(el, game, preplaced[i].pos)); + } + } + + + @Override + public LinkedList getPreplacedPositions(String tileId, Element card) { + return null; + } + + @Override + public List createTiles(Expansion expansion, String tileId, Element card, Map discardList) { + List result = super.createTiles(expansion, tileId, card, discardList); + for (PreplacedTile pt : preplaced) { + if (pt.tile == null && pt.tileId.equals(tileId)) { + pt.tile = result.remove(result.size()-1); + game.loadTileFromSnapshot(pt.tile, pt.element); + } + if (result.isEmpty()) { + break; + } + } + return result; + } + + public List getPreplacedMeeples() { + return preplacedMeeples; + } + + @Override + protected String getTileGroup(Tile tile, Element card) { + if (tile.getPosition() != null) { + return PLACED_GROUP; //special placed group (because all placed must be in active group) + } + return super.getTileGroup(tile, card); + } + + @Override + public DefaultTilePack createTilePack() { + DefaultTilePack pack = super.createTilePack(); + for (PreplacedTile pt : preplaced) { + pt.tile.setRotation(pt.rot); + pt.tile.setPosition(pt.pos); + pack.addTile(pt.tile, PLACED_GROUP); + } + pack.activateGroup(PLACED_GROUP); + if (preplaced.length > 0) { + game.setCurrentTile(preplaced[preplaced.length-1].tile); + } + return pack; + } + + public void activateGroups(DefaultTilePack pack) { + pack.deactivateAllGroups(); + for (String group : snapshot.getActiveGroups()) { + if (pack.getGroups().contains(group)) { + pack.activateGroup(group); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/board/Location.java b/src/main/java/com/jcloisterzone/board/Location.java index e54e867fc..b16bc84ea 100644 --- a/src/main/java/com/jcloisterzone/board/Location.java +++ b/src/main/java/com/jcloisterzone/board/Location.java @@ -1,301 +1,301 @@ -package com.jcloisterzone.board; - -import java.io.ObjectStreamException; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -/** - * bite order corresponding constants - * - * 0 1 1 2 - * 7 2 128 4 - * 6 3 64 8 - * 5 4 32 16 - */ -public class Location implements Serializable { - - private static final long serialVersionUID = -8348910171518350353L; - - transient private String name; - private int mask; - - private static Map instances = new HashMap<>(); - - /** - * Obtains instance with given mask. For named location - * instance is unique. - * @param mask bite mask of demand instance - */ - public static Location create(int mask) { - Location loc = instances.get(mask); - if (loc != null) return loc; - //TODO prepare name here - return new Location(null, mask); - } - - private Object readResolve() throws ObjectStreamException { - return create(mask); - } - - private Location(String name, int mask) { - this.name = name; - this.mask = mask; - - instances.put(mask, this); - } - - /** North */ - public static final Location N = new Location("N", 3 << 8); - /** West */ - public static final Location W = new Location("W", 192 << 8); - /** South */ - public static final Location S = new Location("S", 48 << 8); - /** East */ - public static final Location E = new Location("E", 12 << 8); - - /** North-west */ - public static final Location NW = new Location("NW", 195 << 8); - /** South-west */ - public static final Location SW = new Location("SW", 240 << 8); - /** South-east */ - public static final Location SE = new Location("SE", 60 << 8); - /** North-east */ - public static final Location NE = new Location("NE", 15 << 8); - - /** Horizontal location - W + E */ - public static final Location WE = new Location("WE", 204 << 8); - /** Vertical location - N + S */ - public static final Location NS = new Location("NS", 51 << 8); - /** All edge locations */ - public static final Location NWSE = new Location("NWSE", 255 << 8); - - /** Supplement to the north */ - public static final Location _N = new Location("_N", 252 << 8); - /** Supplement to the west */ - public static final Location _W = new Location("_W", 63 << 8); - /** Supplement to the south */ - public static final Location _S = new Location("_S", 207 << 8); - /** Supplement to the east */ - public static final Location _E = new Location("_E", 243 << 8); - - /** Cloister on tile */ - public static final Location CLOISTER = new Location("CLOISTER", 1 << 16 ); - /** Tower on tile */ - public static final Location TOWER = new Location("TOWER", 1 << 17); - /** Inprisoned follwer */ - public static final Location PRISON = new Location("PRISON", 1 << 18); - - // --- farm locations --- - - /** North left farm */ - public static final Location NL = new Location("NL", 1); - /** North right farm */ - public static final Location NR = new Location("NR", 2); - /** East left farm */ - public static final Location EL = new Location("EL", 4); - /** East right farm */ - public static final Location ER = new Location("ER", 8); - /** South left farm */ - public static final Location SL = new Location("SL", 16); - /** South right farm */ - public static final Location SR = new Location("SR", 32); - /** West left farm */ - public static final Location WL = new Location("WL", 64); - /** West right farm */ - public static final Location WR = new Location("WR", 128); - /** Center farm*/ - public static final Location INNER_FARM = new Location("INNER_FARM", 0); - - - private static final Location[] SIDES = {N, E, S, W}; - private static final Location[] DIAGONAL_SIDES = {NE, SE, SW, NW}; - private static final Location[] FARM_SIDES = {NL, NR, EL, ER, SL, SR, WL, WR}; - - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Location)) return false; - return mask == ((Location)obj).mask; - } - - @Override - public int hashCode() { - return mask; - } - - /** Rotation about quarter circle clockwise */ - public Location next() { - return shift(2); - } - - /** Rotation about quarter circle counter-clockwise */ - public Location prev() { - return shift(6); - } - - /** Returns opposite location, mirrored by axis */ - public Location rev() { - // odd bits shift by 5, even by 3; - int mLo = mask & 255; - mLo = ((mLo & 85) << 5) | ((mLo & 170) << 3); - mLo = (mLo | (mLo >> 8)) & 255; - - int mHi = (mask & 65280) >> 8; - mHi = ((mHi & 85) << 5) | ((mHi & 170) << 3); - mHi = (mHi | (mHi >> 8)) & 255; - - return create((mask & ~65535) | (mHi << 8) | mLo); - } - - /** - * Bitwise mask rotation about given number of bites. - * @param i number of bites to rotate - * @return rotated location - */ - private Location shift(int i) { - int mLo = (mask & 255) << i; - mLo = (mLo | mLo >> 8) & 255; - - int mHi = (mask & 65280) << i; - mHi = (mHi | mHi >> 8) & 65280; - - return create((mask & ~65535) | mHi | mLo); - } - - /** - * Relative rotations in counter-clockwise location - * @param d how much rotate - * @return rotated location - */ - public Location rotateCCW(Rotation rot) { - return shift((rot.ordinal()*6)%8); - } - - /** - * Relative rotations in clockwise location - */ - public Location rotateCW(Rotation rot) { - return shift(rot.ordinal()*2); - } - - public static Location[] sides() { - return SIDES; - } - - public static Location[] sidesFarm() { - return FARM_SIDES; - } - - public static Location[] sidesDiagonal() { - return DIAGONAL_SIDES; - } - - public Location getLeftFarm() { - assert isEdgeLocation(); - return create((mask >> 8) & 85); - } - - public Location getRightFarm() { - assert isEdgeLocation(); - return create((mask >> 8) & 170); - } - - - /** Checks if this is part of given location */ - public boolean isPartOf(Location d) { - if (mask == 0) return this == d; - return ((mask ^ d.mask) & mask) == 0; - } - - @Override - public String toString() { - if (name != null) return name; - StringBuilder str = new StringBuilder(); - for (Location atom : FARM_SIDES) { - if (intersect(atom) != null) { - if (str.length() > 0) str.append("."); - str.append(atom); - } - } - return str.toString(); - } - - /** Merge two locations together */ - public Location union(Location d) { - if (d == null) return this; - assert !isSpecialLocation() && !(isEdgeLocation() ^ d.isEdgeLocation()) & !(isFarmLocation() ^ d.isFarmLocation()) : "union("+this+','+d+')'; - return create(mask | d.mask); - } - - /** Subtract given location from this */ - public Location substract(Location d) { - if (d == null) return this; - assert !isSpecialLocation() && !(isEdgeLocation() ^ d.isEdgeLocation()) & !(isFarmLocation() ^ d.isFarmLocation()) : "substract("+this+','+d+')'; - return create((~(mask & d.mask)) & mask); - } - - public Location intersect(Location d) { - if (d == null || (mask & d.mask) == 0) return null; - assert !isSpecialLocation() && !(isEdgeLocation() ^ d.isEdgeLocation()) & !(isFarmLocation() ^ d.isFarmLocation()) : "interasect("+this+','+d+')'; - return create(mask & d.mask); - } - - public Location[] intersectMulti(Location[] locs) { - List result = new ArrayList<>(); - for (Location loc: locs) { - Location i = this.intersect(loc); - if (i != null) { - result.add(i); - } - } - return result.toArray(new Location[result.size()]); - } - - /** Creates instance according to name */ - public static Location valueOf(String name) { - Location value = null; - for (String part : name.split("\\.")) { - try { - Location item = (Location) Location.class.getField(part).get(null); - value = item.union(value); - } catch (Exception ex) { - throw new IllegalArgumentException("Unknown location " + name, ex); - } - } - assert value != null; - return value; - } - - public Rotation getRotationOf(Location loc) { - for (Rotation r : Rotation.values()) { - if (this.equals(loc.rotateCW(r))) return r; - } - return null; - } - - /** - * Check if this rotated another location - */ - public boolean isRotationOf(Location loc) { - return getRotationOf(loc) != null; - } - - //assertion methods - - public boolean isFarmLocation() { - return this == INNER_FARM || (mask & 255) > 0; - } - - public boolean isEdgeLocation() { - return (mask & 65280) > 0; - } - - public boolean isSpecialLocation() { - return (mask & ~65535) > 0; - } -} +package com.jcloisterzone.board; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * bite order corresponding constants + * + * 0 1 1 2 + * 7 2 128 4 + * 6 3 64 8 + * 5 4 32 16 + */ +public class Location implements Serializable { + + private static final long serialVersionUID = -8348910171518350353L; + + transient private String name; + private int mask; + + private static Map instances = new HashMap<>(); + + /** + * Obtains instance with given mask. For named location + * instance is unique. + * @param mask bite mask of demand instance + */ + public static Location create(int mask) { + Location loc = instances.get(mask); + if (loc != null) return loc; + //TODO prepare name here + return new Location(null, mask); + } + + private Object readResolve() throws ObjectStreamException { + return create(mask); + } + + private Location(String name, int mask) { + this.name = name; + this.mask = mask; + + instances.put(mask, this); + } + + /** North */ + public static final Location N = new Location("N", 3 << 8); + /** West */ + public static final Location W = new Location("W", 192 << 8); + /** South */ + public static final Location S = new Location("S", 48 << 8); + /** East */ + public static final Location E = new Location("E", 12 << 8); + + /** North-west */ + public static final Location NW = new Location("NW", 195 << 8); + /** South-west */ + public static final Location SW = new Location("SW", 240 << 8); + /** South-east */ + public static final Location SE = new Location("SE", 60 << 8); + /** North-east */ + public static final Location NE = new Location("NE", 15 << 8); + + /** Horizontal location - W + E */ + public static final Location WE = new Location("WE", 204 << 8); + /** Vertical location - N + S */ + public static final Location NS = new Location("NS", 51 << 8); + /** All edge locations */ + public static final Location NWSE = new Location("NWSE", 255 << 8); + + /** Supplement to the north */ + public static final Location _N = new Location("_N", 252 << 8); + /** Supplement to the west */ + public static final Location _W = new Location("_W", 63 << 8); + /** Supplement to the south */ + public static final Location _S = new Location("_S", 207 << 8); + /** Supplement to the east */ + public static final Location _E = new Location("_E", 243 << 8); + + /** Cloister on tile */ + public static final Location CLOISTER = new Location("CLOISTER", 1 << 16 ); + /** Tower on tile */ + public static final Location TOWER = new Location("TOWER", 1 << 17); + /** Inprisoned follwer */ + public static final Location PRISON = new Location("PRISON", 1 << 18); + + // --- farm locations --- + + /** North left farm */ + public static final Location NL = new Location("NL", 1); + /** North right farm */ + public static final Location NR = new Location("NR", 2); + /** East left farm */ + public static final Location EL = new Location("EL", 4); + /** East right farm */ + public static final Location ER = new Location("ER", 8); + /** South left farm */ + public static final Location SL = new Location("SL", 16); + /** South right farm */ + public static final Location SR = new Location("SR", 32); + /** West left farm */ + public static final Location WL = new Location("WL", 64); + /** West right farm */ + public static final Location WR = new Location("WR", 128); + /** Center farm*/ + public static final Location INNER_FARM = new Location("INNER_FARM", 0); + + + private static final Location[] SIDES = {N, E, S, W}; + private static final Location[] DIAGONAL_SIDES = {NE, SE, SW, NW}; + private static final Location[] FARM_SIDES = {NL, NR, EL, ER, SL, SR, WL, WR}; + + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Location)) return false; + return mask == ((Location)obj).mask; + } + + @Override + public int hashCode() { + return mask; + } + + /** Rotation about quarter circle clockwise */ + public Location next() { + return shift(2); + } + + /** Rotation about quarter circle counter-clockwise */ + public Location prev() { + return shift(6); + } + + /** Returns opposite location, mirrored by axis */ + public Location rev() { + // odd bits shift by 5, even by 3; + int mLo = mask & 255; + mLo = ((mLo & 85) << 5) | ((mLo & 170) << 3); + mLo = (mLo | (mLo >> 8)) & 255; + + int mHi = (mask & 65280) >> 8; + mHi = ((mHi & 85) << 5) | ((mHi & 170) << 3); + mHi = (mHi | (mHi >> 8)) & 255; + + return create((mask & ~65535) | (mHi << 8) | mLo); + } + + /** + * Bitwise mask rotation about given number of bites. + * @param i number of bites to rotate + * @return rotated location + */ + private Location shift(int i) { + int mLo = (mask & 255) << i; + mLo = (mLo | mLo >> 8) & 255; + + int mHi = (mask & 65280) << i; + mHi = (mHi | mHi >> 8) & 65280; + + return create((mask & ~65535) | mHi | mLo); + } + + /** + * Relative rotations in counter-clockwise location + * @param d how much rotate + * @return rotated location + */ + public Location rotateCCW(Rotation rot) { + return shift((rot.ordinal()*6)%8); + } + + /** + * Relative rotations in clockwise location + */ + public Location rotateCW(Rotation rot) { + return shift(rot.ordinal()*2); + } + + public static Location[] sides() { + return SIDES; + } + + public static Location[] sidesFarm() { + return FARM_SIDES; + } + + public static Location[] sidesDiagonal() { + return DIAGONAL_SIDES; + } + + public Location getLeftFarm() { + assert isEdgeLocation(); + return create((mask >> 8) & 85); + } + + public Location getRightFarm() { + assert isEdgeLocation(); + return create((mask >> 8) & 170); + } + + + /** Checks if this is part of given location */ + public boolean isPartOf(Location d) { + if (mask == 0) return this == d; + return ((mask ^ d.mask) & mask) == 0; + } + + @Override + public String toString() { + if (name != null) return name; + StringBuilder str = new StringBuilder(); + for (Location atom : FARM_SIDES) { + if (intersect(atom) != null) { + if (str.length() > 0) str.append("."); + str.append(atom); + } + } + return str.toString(); + } + + /** Merge two locations together */ + public Location union(Location d) { + if (d == null) return this; + assert !isSpecialLocation() && !(isEdgeLocation() ^ d.isEdgeLocation()) & !(isFarmLocation() ^ d.isFarmLocation()) : "union("+this+','+d+')'; + return create(mask | d.mask); + } + + /** Subtract given location from this */ + public Location substract(Location d) { + if (d == null) return this; + assert !isSpecialLocation() && !(isEdgeLocation() ^ d.isEdgeLocation()) & !(isFarmLocation() ^ d.isFarmLocation()) : "substract("+this+','+d+')'; + return create((~(mask & d.mask)) & mask); + } + + public Location intersect(Location d) { + if (d == null || (mask & d.mask) == 0) return null; + assert !isSpecialLocation() && !(isEdgeLocation() ^ d.isEdgeLocation()) & !(isFarmLocation() ^ d.isFarmLocation()) : "interasect("+this+','+d+')'; + return create(mask & d.mask); + } + + public Location[] intersectMulti(Location[] locs) { + List result = new ArrayList<>(); + for (Location loc: locs) { + Location i = this.intersect(loc); + if (i != null) { + result.add(i); + } + } + return result.toArray(new Location[result.size()]); + } + + /** Creates instance according to name */ + public static Location valueOf(String name) { + Location value = null; + for (String part : name.split("\\.")) { + try { + Location item = (Location) Location.class.getField(part).get(null); + value = item.union(value); + } catch (Exception ex) { + throw new IllegalArgumentException("Unknown location " + name, ex); + } + } + assert value != null; + return value; + } + + public Rotation getRotationOf(Location loc) { + for (Rotation r : Rotation.values()) { + if (this.equals(loc.rotateCW(r))) return r; + } + return null; + } + + /** + * Check if this rotated another location + */ + public boolean isRotationOf(Location loc) { + return getRotationOf(loc) != null; + } + + //assertion methods + + public boolean isFarmLocation() { + return this == INNER_FARM || (mask & 255) > 0; + } + + public boolean isEdgeLocation() { + return (mask & 65280) > 0; + } + + public boolean isSpecialLocation() { + return (mask & ~65535) > 0; + } +} diff --git a/src/main/java/com/jcloisterzone/board/Position.java b/src/main/java/com/jcloisterzone/board/Position.java index 31d243b6d..e68a4d521 100644 --- a/src/main/java/com/jcloisterzone/board/Position.java +++ b/src/main/java/com/jcloisterzone/board/Position.java @@ -1,101 +1,101 @@ -package com.jcloisterzone.board; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Map; - -import com.google.common.collect.ImmutableMap; - - -/** - * Represents position on board. Immutable class. - * - * @author Roman Krejcik - */ -public class Position implements Serializable { - - public final int x; - public final int y; - - private static final long serialVersionUID = -345L; - - public static final Map ADJACENT; - public static final Map ADJACENT_AND_DIAGONAL; - - static { - ADJACENT = new ImmutableMap.Builder() - .put(Location.N, new Position(0, -1)) - .put(Location.E, new Position(1, 0)) - .put(Location.S, new Position(0, 1)) - .put(Location.W, new Position(-1, 0)) - .build(); - - ADJACENT_AND_DIAGONAL= new ImmutableMap.Builder() - .putAll(ADJACENT) - .put(Location.NE, new Position(1, -1)) - .put(Location.SE, new Position(1, 1)) - .put(Location.SW, new Position(-1, 1)) - .put(Location.NW, new Position(-1, -1)) - .build(); - } - - public Position(int x, int y) { - this.x = x; - this.y = y; - } - - public Position(Position p) { - this(p.x,p.y); - } - - public String toString() { - return "[x=" + x + ",y=" + y + "]"; - } - - public Position add(Position p) { - return new Position(x+p.x, y+p.y); - } - - public Position[] addMulti(Position[] offsets) { - Position[] result = new Position[offsets.length]; - for (int i = 0; i < result.length; i++) { - result[i] = add(offsets[i]); - } - return result; - } - - public Position[] addMulti(Collection offsets) { - Position[] arr = new Position[offsets.size()]; - arr = offsets.toArray(arr); - return addMulti(arr); - } - - public Position add(Location loc) { - int x = this.x; - int y = this.y; - if (Location.N.isPartOf(loc)) y--; - if (Location.S.isPartOf(loc)) y++; - if (Location.W.isPartOf(loc)) x--; - if (Location.E.isPartOf(loc)) x++; - return new Position(x,y); - } - - public int squareDistance(Position p) { - //orthogonal distance - return Math.abs(x - p.x) + Math.abs(y - p.y); - } - - @Override - public int hashCode() { - return (x << 16) ^ y; - } - @Override - public boolean equals(Object obj) { - if (obj instanceof Position) { - Position p = (Position)obj; - return (x == p.x) && (y == p.y); - } - return false; - } - +package com.jcloisterzone.board; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; + + +/** + * Represents position on board. Immutable class. + * + * @author Roman Krejcik + */ +public class Position implements Serializable { + + public final int x; + public final int y; + + private static final long serialVersionUID = -345L; + + public static final Map ADJACENT; + public static final Map ADJACENT_AND_DIAGONAL; + + static { + ADJACENT = new ImmutableMap.Builder() + .put(Location.N, new Position(0, -1)) + .put(Location.E, new Position(1, 0)) + .put(Location.S, new Position(0, 1)) + .put(Location.W, new Position(-1, 0)) + .build(); + + ADJACENT_AND_DIAGONAL= new ImmutableMap.Builder() + .putAll(ADJACENT) + .put(Location.NE, new Position(1, -1)) + .put(Location.SE, new Position(1, 1)) + .put(Location.SW, new Position(-1, 1)) + .put(Location.NW, new Position(-1, -1)) + .build(); + } + + public Position(int x, int y) { + this.x = x; + this.y = y; + } + + public Position(Position p) { + this(p.x,p.y); + } + + public String toString() { + return "[x=" + x + ",y=" + y + "]"; + } + + public Position add(Position p) { + return new Position(x+p.x, y+p.y); + } + + public Position[] addMulti(Position[] offsets) { + Position[] result = new Position[offsets.length]; + for (int i = 0; i < result.length; i++) { + result[i] = add(offsets[i]); + } + return result; + } + + public Position[] addMulti(Collection offsets) { + Position[] arr = new Position[offsets.size()]; + arr = offsets.toArray(arr); + return addMulti(arr); + } + + public Position add(Location loc) { + int x = this.x; + int y = this.y; + if (Location.N.isPartOf(loc)) y--; + if (Location.S.isPartOf(loc)) y++; + if (Location.W.isPartOf(loc)) x--; + if (Location.E.isPartOf(loc)) x++; + return new Position(x,y); + } + + public int squareDistance(Position p) { + //orthogonal distance + return Math.abs(x - p.x) + Math.abs(y - p.y); + } + + @Override + public int hashCode() { + return (x << 16) ^ y; + } + @Override + public boolean equals(Object obj) { + if (obj instanceof Position) { + Position p = (Position)obj; + return (x == p.x) && (y == p.y); + } + return false; + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/board/Rotation.java b/src/main/java/com/jcloisterzone/board/Rotation.java index 4ade8c4dc..8e7aaa59b 100644 --- a/src/main/java/com/jcloisterzone/board/Rotation.java +++ b/src/main/java/com/jcloisterzone/board/Rotation.java @@ -1,54 +1,54 @@ -package com.jcloisterzone.board; - -import java.awt.geom.AffineTransform; - -public enum Rotation { - - R0, - R90, - R180, - R270; - - public AffineTransform getAffineTransform(int size) { - AffineTransform at; - switch (this) { - case R0: - at = new AffineTransform(); - return at; - case R90: - at = AffineTransform.getRotateInstance(Math.PI * 0.5); - at.translate(0, -size); - return at; - case R180: - at = AffineTransform.getRotateInstance(Math.PI); - at.translate(-size, -size); - return at; - case R270: - at = AffineTransform.getRotateInstance(Math.PI * 1.5); - at.translate(-size, 0); - return at; - } - return null; - } - - public Rotation next() { - if (ordinal() == values().length - 1) return values()[0]; - return values()[ordinal()+1]; - } - - public Rotation prev() { - if (ordinal() == 0) return values()[values().length - 1]; - return values()[ordinal()-1]; - } - - public Rotation inverse() { - switch (this) { - case R0: return R0; - case R90: return R270; - case R180: return R180; - case R270: return R90; - } - throw new IllegalStateException(); - } - -} +package com.jcloisterzone.board; + +import java.awt.geom.AffineTransform; + +public enum Rotation { + + R0, + R90, + R180, + R270; + + public AffineTransform getAffineTransform(int size) { + AffineTransform at; + switch (this) { + case R0: + at = new AffineTransform(); + return at; + case R90: + at = AffineTransform.getRotateInstance(Math.PI * 0.5); + at.translate(0, -size); + return at; + case R180: + at = AffineTransform.getRotateInstance(Math.PI); + at.translate(-size, -size); + return at; + case R270: + at = AffineTransform.getRotateInstance(Math.PI * 1.5); + at.translate(-size, 0); + return at; + } + return null; + } + + public Rotation next() { + if (ordinal() == values().length - 1) return values()[0]; + return values()[ordinal()+1]; + } + + public Rotation prev() { + if (ordinal() == 0) return values()[values().length - 1]; + return values()[ordinal()-1]; + } + + public Rotation inverse() { + switch (this) { + case R0: return R0; + case R90: return R270; + case R180: return R180; + case R270: return R90; + } + throw new IllegalStateException(); + } + +} diff --git a/src/main/java/com/jcloisterzone/board/Tile.java b/src/main/java/com/jcloisterzone/board/Tile.java index 5be019d63..713a0e952 100644 --- a/src/main/java/com/jcloisterzone/board/Tile.java +++ b/src/main/java/com/jcloisterzone/board/Tile.java @@ -1,343 +1,343 @@ -package com.jcloisterzone.board; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Bridge; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.MultiTileFeature; -import com.jcloisterzone.feature.Scoreable; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.feature.visitor.IsOccupied; -import com.jcloisterzone.feature.visitor.IsOccupiedOrCompleted; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.game.Game; - - -/** - * Represents one game tile. Contains references on score objects - * which lays on tile and provides logic for tiles merging, rotating - * and placing figures. - * - * @author Roman Krejcik - */ -public class Tile /*implements Cloneable*/ { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - public static final String ABBEY_TILE_ID = "AM.A"; - - protected Game game; - private final Expansion origin; - private final String id; - - private ArrayList features; - private Bridge bridge; //direct reference to bridge feature - - protected TileSymmetry symmetry; - protected Position position = null; - private Rotation rotation = Rotation.R0; - - private EdgePattern edgePattern; - - //expansions data - maybe some map instead ? but still it is only few tiles - private TileTrigger trigger; - private Location river; - private Location flier; - private Location windRose; - private Class cornCircle; - - public Tile(Expansion origin, String id) { - this.origin = origin; - this.id = id; - } - - @Override - public int hashCode() { - //TODO tiles with same id has same hashcode, is it ok? - return id.hashCode(); - } - - public EdgePattern getEdgePattern() { - return edgePattern; - } - - public void setEdgePattern(EdgePattern edgePattern) { - this.edgePattern = edgePattern; - } - - public char getEdge(Location side) { - return getEdgePattern().at(side, rotation); - } - - public String getId() { - return id; - } - - public Expansion getOrigin() { - return origin; - } - - protected boolean check(Tile tile, Location rel, Board board) { - return getEdge(rel) == tile.getEdge(rel.rev()); - } - - public void setFeatures(ArrayList features) { - assert this.features == null; - this.features = features; - } - - public List getFeatures() { - return features; - } - - public Feature getFeature(Location loc) { - for (Feature p : features) { - if (p.getLocation().equals(loc)) return p; - } - return null; - } - - public Feature getFeaturePartOf(Location loc) { - for (Feature p : features) { - if (loc.isPartOf(p.getLocation())) { - return p; - } - } - return null; - } - - /** merge this to another tile - method argument is tile placed before */ - protected void merge(Tile tile, Location loc) { - //if (logger.isDebugEnabled()) logger.debug("Merging " + id + " with " + tile.getId()); - Location oppositeLoc = loc.rev(); - MultiTileFeature oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeLoc); - if (oppositePiece != null) { - if (isAbbeyTile()) { - oppositePiece.setAbbeyEdge(oppositeLoc); - } else { - MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(loc); - oppositePiece.setEdge(oppositeLoc, thisPiece); - thisPiece.setEdge(loc, oppositePiece); - } - } - for (int i = 0; i < 2; i++) { - Location halfSide = i == 0 ? loc.getLeftFarm() : loc.getRightFarm(); - Location oppositeHalfSide = halfSide.rev(); - oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeHalfSide); - if (oppositePiece != null) { - if (isAbbeyTile()) { - oppositePiece.setAbbeyEdge(oppositeHalfSide); - } else { - MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(halfSide); - oppositePiece.setEdge(oppositeHalfSide, thisPiece); - thisPiece.setEdge(halfSide, oppositePiece); - } - } - } - } - - protected void unmerge(Tile tile, Location loc) { - Location oppositeLoc = loc.rev(); - MultiTileFeature oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeLoc); - if (oppositePiece != null) { - oppositePiece.setEdge(oppositeLoc, null); - if (!isAbbeyTile()) { - MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(loc); - thisPiece.setEdge(loc, null); - } - } - for (int i = 0; i < 2; i++) { - Location halfSide = i == 0 ? loc.getLeftFarm() : loc.getRightFarm(); - Location oppositeHalfSide = halfSide.rev(); - oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeHalfSide); - if (oppositePiece != null) { - oppositePiece.setEdge(oppositeHalfSide, null); - if (!isAbbeyTile()) { - MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(halfSide); - thisPiece.setEdge(halfSide, null); - } - } - } - } - - protected void rotate() { - rotation = rotation.next(); - } - - public void setRotation(Rotation rotation) { - assert rotation != null; - this.rotation = rotation; - } - - public Rotation getRotation() { - return rotation; - } - - public TileSymmetry getSymmetry() { - return symmetry; - } - - public void setSymmetry(TileSymmetry symmetry) { - this.symmetry = symmetry; - } - - public boolean isAbbeyTile() { - return id.equals(ABBEY_TILE_ID); - } - - public boolean hasCloister() { - return getFeature(Location.CLOISTER) != null; - } - - - public Cloister getCloister() { - return (Cloister) getFeature(Location.CLOISTER); - } - - public Tower getTower() { - return (Tower) getFeature(Location.TOWER); - } - - public Game getGame() { - return game; - } - - public void setGame(Game game) { - this.game = game; - } - - - public void setPosition(Position p) { - position = p; - } - - public Position getPosition() { - return position; - } - - - public Bridge getBridge() { - return bridge; - } - - public void placeBridge(Location bridgeLoc) { - assert bridge == null && bridgeLoc != null; //TODO AI support - remove bridge from tile - Location normalizedLoc = bridgeLoc.rotateCCW(rotation); - bridge = new Bridge(); - bridge.setId(game.idSequnceNextVal()); - bridge.setTile(this); - bridge.setLocation(normalizedLoc); - features.add(bridge); - edgePattern = edgePattern.getBridgePattern(normalizedLoc); - } - - public Set getUnoccupiedScoreables(boolean excludeCompleted) { - Set locations = new HashSet<>(); - for (Feature f : features) { - //if (f instanceof Farm && !game.hasCapability(Capability.FARM_PLACEMENT)) continue; - if (f instanceof Scoreable) { - IsOccupied visitor; - if (excludeCompleted && f instanceof Completable) { - visitor = new IsOccupiedOrCompleted(); - } else { - visitor = new IsOccupied(); - } - if (f.walk(visitor)) continue; - locations.add(f.getLocation()); - } - } - return locations; - } - - - public Set getPlayerFeatures(Player player, Class featureClass) { - Set locations = new HashSet<>(); - for (Feature f : features) { - if (!featureClass.isInstance(f)) continue; - if (f.walk(new IsOccupied().with(player).with(Follower.class))) { - locations.add(f.getLocation()); - } - } - return locations; - } - - @Override - public String toString() { - return getId() + '(' + getRotation() + ')'; - } - - public TileTrigger getTrigger() { - return trigger; - } - - public void setTrigger(TileTrigger trigger) { - this.trigger = trigger; - } - - public boolean hasTrigger(TileTrigger trigger) { - return trigger == this.trigger; - } - - public Class getCornCircle() { - return cornCircle; - } - - public void setCornCircle(Class cornCircle) { - this.cornCircle = cornCircle; - } - - public City getCityWithPrincess() { - for (Feature p : features) { - if (p instanceof City ) { - City cp = (City) p; - if (cp.isPricenss()) { - return cp; - } - } - } - return null; - } - - - public Location getRiver() { - return river; - } - - public void setRiver(Location river) { - this.river = river; - } - - - public Location getFlier() { - return flier; - } - - public void setFlier(Location flier) { - this.flier = flier; - } - - public Location getWindRose() { - return windRose; - } - - public void setWindRose(Location windRose) { - this.windRose = windRose; - } - - public boolean isBridgeAllowed(Location bridgeLoc) { - if (origin == Expansion.COUNT || getBridge() != null) return false; - return edgePattern.isBridgeAllowed(bridgeLoc, rotation); - } - -} +package com.jcloisterzone.board; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Bridge; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.MultiTileFeature; +import com.jcloisterzone.feature.Scoreable; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.feature.visitor.IsOccupied; +import com.jcloisterzone.feature.visitor.IsOccupiedOrCompleted; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.game.Game; + + +/** + * Represents one game tile. Contains references on score objects + * which lays on tile and provides logic for tiles merging, rotating + * and placing figures. + * + * @author Roman Krejcik + */ +public class Tile /*implements Cloneable*/ { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + public static final String ABBEY_TILE_ID = "AM.A"; + + protected Game game; + private final Expansion origin; + private final String id; + + private ArrayList features; + private Bridge bridge; //direct reference to bridge feature + + protected TileSymmetry symmetry; + protected Position position = null; + private Rotation rotation = Rotation.R0; + + private EdgePattern edgePattern; + + //expansions data - maybe some map instead ? but still it is only few tiles + private TileTrigger trigger; + private Location river; + private Location flier; + private Location windRose; + private Class cornCircle; + + public Tile(Expansion origin, String id) { + this.origin = origin; + this.id = id; + } + + @Override + public int hashCode() { + //TODO tiles with same id has same hashcode, is it ok? + return id.hashCode(); + } + + public EdgePattern getEdgePattern() { + return edgePattern; + } + + public void setEdgePattern(EdgePattern edgePattern) { + this.edgePattern = edgePattern; + } + + public char getEdge(Location side) { + return getEdgePattern().at(side, rotation); + } + + public String getId() { + return id; + } + + public Expansion getOrigin() { + return origin; + } + + protected boolean check(Tile tile, Location rel, Board board) { + return getEdge(rel) == tile.getEdge(rel.rev()); + } + + public void setFeatures(ArrayList features) { + assert this.features == null; + this.features = features; + } + + public List getFeatures() { + return features; + } + + public Feature getFeature(Location loc) { + for (Feature p : features) { + if (p.getLocation().equals(loc)) return p; + } + return null; + } + + public Feature getFeaturePartOf(Location loc) { + for (Feature p : features) { + if (loc.isPartOf(p.getLocation())) { + return p; + } + } + return null; + } + + /** merge this to another tile - method argument is tile placed before */ + protected void merge(Tile tile, Location loc) { + //if (logger.isDebugEnabled()) logger.debug("Merging " + id + " with " + tile.getId()); + Location oppositeLoc = loc.rev(); + MultiTileFeature oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeLoc); + if (oppositePiece != null) { + if (isAbbeyTile()) { + oppositePiece.setAbbeyEdge(oppositeLoc); + } else { + MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(loc); + oppositePiece.setEdge(oppositeLoc, thisPiece); + thisPiece.setEdge(loc, oppositePiece); + } + } + for (int i = 0; i < 2; i++) { + Location halfSide = i == 0 ? loc.getLeftFarm() : loc.getRightFarm(); + Location oppositeHalfSide = halfSide.rev(); + oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeHalfSide); + if (oppositePiece != null) { + if (isAbbeyTile()) { + oppositePiece.setAbbeyEdge(oppositeHalfSide); + } else { + MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(halfSide); + oppositePiece.setEdge(oppositeHalfSide, thisPiece); + thisPiece.setEdge(halfSide, oppositePiece); + } + } + } + } + + protected void unmerge(Tile tile, Location loc) { + Location oppositeLoc = loc.rev(); + MultiTileFeature oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeLoc); + if (oppositePiece != null) { + oppositePiece.setEdge(oppositeLoc, null); + if (!isAbbeyTile()) { + MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(loc); + thisPiece.setEdge(loc, null); + } + } + for (int i = 0; i < 2; i++) { + Location halfSide = i == 0 ? loc.getLeftFarm() : loc.getRightFarm(); + Location oppositeHalfSide = halfSide.rev(); + oppositePiece = (MultiTileFeature) tile.getFeaturePartOf(oppositeHalfSide); + if (oppositePiece != null) { + oppositePiece.setEdge(oppositeHalfSide, null); + if (!isAbbeyTile()) { + MultiTileFeature thisPiece = (MultiTileFeature) getFeaturePartOf(halfSide); + thisPiece.setEdge(halfSide, null); + } + } + } + } + + protected void rotate() { + rotation = rotation.next(); + } + + public void setRotation(Rotation rotation) { + assert rotation != null; + this.rotation = rotation; + } + + public Rotation getRotation() { + return rotation; + } + + public TileSymmetry getSymmetry() { + return symmetry; + } + + public void setSymmetry(TileSymmetry symmetry) { + this.symmetry = symmetry; + } + + public boolean isAbbeyTile() { + return id.equals(ABBEY_TILE_ID); + } + + public boolean hasCloister() { + return getFeature(Location.CLOISTER) != null; + } + + + public Cloister getCloister() { + return (Cloister) getFeature(Location.CLOISTER); + } + + public Tower getTower() { + return (Tower) getFeature(Location.TOWER); + } + + public Game getGame() { + return game; + } + + public void setGame(Game game) { + this.game = game; + } + + + public void setPosition(Position p) { + position = p; + } + + public Position getPosition() { + return position; + } + + + public Bridge getBridge() { + return bridge; + } + + public void placeBridge(Location bridgeLoc) { + assert bridge == null && bridgeLoc != null; //TODO AI support - remove bridge from tile + Location normalizedLoc = bridgeLoc.rotateCCW(rotation); + bridge = new Bridge(); + bridge.setId(game.idSequnceNextVal()); + bridge.setTile(this); + bridge.setLocation(normalizedLoc); + features.add(bridge); + edgePattern = edgePattern.getBridgePattern(normalizedLoc); + } + + public Set getUnoccupiedScoreables(boolean excludeCompleted) { + Set locations = new HashSet<>(); + for (Feature f : features) { + //if (f instanceof Farm && !game.hasCapability(Capability.FARM_PLACEMENT)) continue; + if (f instanceof Scoreable) { + IsOccupied visitor; + if (excludeCompleted && f instanceof Completable) { + visitor = new IsOccupiedOrCompleted(); + } else { + visitor = new IsOccupied(); + } + if (f.walk(visitor)) continue; + locations.add(f.getLocation()); + } + } + return locations; + } + + + public Set getPlayerFeatures(Player player, Class featureClass) { + Set locations = new HashSet<>(); + for (Feature f : features) { + if (!featureClass.isInstance(f)) continue; + if (f.walk(new IsOccupied().with(player).with(Follower.class))) { + locations.add(f.getLocation()); + } + } + return locations; + } + + @Override + public String toString() { + return getId() + '(' + getRotation() + ')'; + } + + public TileTrigger getTrigger() { + return trigger; + } + + public void setTrigger(TileTrigger trigger) { + this.trigger = trigger; + } + + public boolean hasTrigger(TileTrigger trigger) { + return trigger == this.trigger; + } + + public Class getCornCircle() { + return cornCircle; + } + + public void setCornCircle(Class cornCircle) { + this.cornCircle = cornCircle; + } + + public City getCityWithPrincess() { + for (Feature p : features) { + if (p instanceof City ) { + City cp = (City) p; + if (cp.isPricenss()) { + return cp; + } + } + } + return null; + } + + + public Location getRiver() { + return river; + } + + public void setRiver(Location river) { + this.river = river; + } + + + public Location getFlier() { + return flier; + } + + public void setFlier(Location flier) { + this.flier = flier; + } + + public Location getWindRose() { + return windRose; + } + + public void setWindRose(Location windRose) { + this.windRose = windRose; + } + + public boolean isBridgeAllowed(Location bridgeLoc) { + if (origin == Expansion.COUNT || getBridge() != null) return false; + return edgePattern.isBridgeAllowed(bridgeLoc, rotation); + } + +} diff --git a/src/main/java/com/jcloisterzone/board/TileFactory.java b/src/main/java/com/jcloisterzone/board/TileFactory.java index c795effc9..b4442251d 100644 --- a/src/main/java/com/jcloisterzone/board/TileFactory.java +++ b/src/main/java/com/jcloisterzone/board/TileFactory.java @@ -1,181 +1,181 @@ -package com.jcloisterzone.board; - -import static com.jcloisterzone.XmlUtils.asLocation; -import static com.jcloisterzone.XmlUtils.asLocations; -import static com.jcloisterzone.XmlUtils.attributeBoolValue; -import static com.jcloisterzone.XmlUtils.attributeIntValue; - -import java.util.ArrayList; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.TileFeature; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; - - -public class TileFactory { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private Tile tile; //context - private ArrayList features; - - private Game game; - - - public Game getGame() { - return game; - } - - public void setGame(Game game) { - this.game = game; - } - - public Tile createTile(Expansion expansion, String fullId, Element xml, boolean isTunnelActive) { - Tile tile = new Tile(expansion, fullId); - this.tile = tile; - features = new ArrayList<>(); - tile.setGame(game); - - logger.debug("Creating " + tile.getId()); - - NodeList nl; - nl = xml.getElementsByTagName("cloister"); - for (int i = 0; i < nl.getLength(); i++) { - processCloisterElement((Element) nl.item(i)); - } - nl = xml.getElementsByTagName("road"); - for (int i = 0; i < nl.getLength(); i++) { - processRoadElement((Element) nl.item(i), isTunnelActive); - } - nl = xml.getElementsByTagName("city"); - for (int i = 0; i < nl.getLength(); i++) { - processCityElement((Element) nl.item(i)); - } - nl = xml.getElementsByTagName("farm"); - for (int i = 0; i < nl.getLength(); i++) { - processFarmElement((Element) nl.item(i)); - } - nl = xml.getElementsByTagName("tower"); - for (int i = 0; i < nl.getLength(); i++) { - processTowerElement((Element) nl.item(i)); - } - - tile.setFeatures(features); - tile.setSymmetry(TileSymmetry.forTile(tile)); - tile.setEdgePattern(EdgePattern.forTile(tile)); - - features = null; - this.tile = null; //clear context - return tile; - } - - private void processCloisterElement(Element e) { - Cloister cloister = new Cloister(); - cloister.setId(game.idSequnceNextVal()); - cloister.setTile(tile); - cloister.setLocation(Location.CLOISTER); - features.add(cloister); - game.initFeature(tile, cloister, e); - } - - private void processTowerElement(Element e) { - Tower tower = new Tower(); - tower.setId(game.idSequnceNextVal()); - tower.setTile(tile); - tower.setLocation(Location.TOWER); - features.add(tower); - game.initFeature(tile, tower, e); - } - - - private void processRoadElement(Element e, boolean isTunnelActive) { - String[] sides = asLocation(e); - //using tunnel argument for two cases, tunnel entrance and tunnel underpass - sides.lenght distinguish it - if (sides.length > 1 && isTunnelActive && attributeBoolValue(e, "tunnel")) { - for (String side: sides) { - String[] side_as_array = { side }; - processRoadElement(side_as_array, e, true); - } - } else { - processRoadElement(sides, e, isTunnelActive); - } - } - - private void processRoadElement(String[] sides, Element e, boolean isTunnelActive) { - //Road road = new Road(tile, sides.length, sides.length == 1 && attributeBoolValue(e, "tunnel")); - Road road = new Road(); - road.setId(game.idSequnceNextVal()); - if (isTunnelActive && attributeBoolValue(e, "tunnel")) { - road.setTunnelEnd(Road.OPEN_TUNNEL); - } - initFromDirList(road, sides); - game.initFeature(tile, road, e); - } - - private void processCityElement(Element e) { - String[] sides = asLocation(e); - City c = new City(); - c.setId(game.idSequnceNextVal()); - c.setPennants(attributeIntValue(e, "pennant", 0)); - initFromDirList(c, sides); - game.initFeature(tile, c, e); - } - - //TODO move expansion specific stuff - private void processFarmElement(Element e) { - String[] sides = asLocation(e); - Farm farm = new Farm(); - farm.setId(game.idSequnceNextVal()); - if (e.hasAttribute("city")) { - List cities = new ArrayList<>(); - String[] citiesLocs = asLocations(e, "city"); - for (int j = 0; j < citiesLocs.length; j++) { - Location d = Location.valueOf(citiesLocs[j]); - for (Feature p : features) { - if (p instanceof City) { - if (d.isPartOf(p.getLocation())) { - cities.add((City) p); - break; - } - } - } - } - farm.setAdjoiningCities(cities.toArray(new Feature[cities.size()])); - } - if (attributeBoolValue(e, "pig")) { - //for river is pig herd always present - if (game.hasRule(CustomRule.PIG_HERD_ON_GQ_FARM) || tile.getId() != "GQ.F") { - farm.setPigHerd(true); - } - } - initFromDirList(farm, sides); - game.initFeature(tile, farm, e); - } - - private void initFromDirList(TileFeature piece, String[] sides) { - Location loc = null; - for (int i = 0; i < sides.length; i++) { - Location l = Location.valueOf(sides[i]); - assert !(piece instanceof Farm ^ l.isFarmLocation()) : String.format("Invalid location %s kind for tile %s", l, tile.getId()); - loc = loc == null ? l : loc.union(l); - } - //logger.debug(tile.getId() + "/" + piece.getClass().getSimpleName() + "/" + loc); - piece.setTile(tile); - piece.setLocation(loc); - features.add(piece); - } - -} +package com.jcloisterzone.board; + +import static com.jcloisterzone.XmlUtils.asLocation; +import static com.jcloisterzone.XmlUtils.asLocations; +import static com.jcloisterzone.XmlUtils.attributeBoolValue; +import static com.jcloisterzone.XmlUtils.attributeIntValue; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.TileFeature; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; + + +public class TileFactory { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private Tile tile; //context + private ArrayList features; + + private Game game; + + + public Game getGame() { + return game; + } + + public void setGame(Game game) { + this.game = game; + } + + public Tile createTile(Expansion expansion, String fullId, Element xml, boolean isTunnelActive) { + Tile tile = new Tile(expansion, fullId); + this.tile = tile; + features = new ArrayList<>(); + tile.setGame(game); + + logger.debug("Creating " + tile.getId()); + + NodeList nl; + nl = xml.getElementsByTagName("cloister"); + for (int i = 0; i < nl.getLength(); i++) { + processCloisterElement((Element) nl.item(i)); + } + nl = xml.getElementsByTagName("road"); + for (int i = 0; i < nl.getLength(); i++) { + processRoadElement((Element) nl.item(i), isTunnelActive); + } + nl = xml.getElementsByTagName("city"); + for (int i = 0; i < nl.getLength(); i++) { + processCityElement((Element) nl.item(i)); + } + nl = xml.getElementsByTagName("farm"); + for (int i = 0; i < nl.getLength(); i++) { + processFarmElement((Element) nl.item(i)); + } + nl = xml.getElementsByTagName("tower"); + for (int i = 0; i < nl.getLength(); i++) { + processTowerElement((Element) nl.item(i)); + } + + tile.setFeatures(features); + tile.setSymmetry(TileSymmetry.forTile(tile)); + tile.setEdgePattern(EdgePattern.forTile(tile)); + + features = null; + this.tile = null; //clear context + return tile; + } + + private void processCloisterElement(Element e) { + Cloister cloister = new Cloister(); + cloister.setId(game.idSequnceNextVal()); + cloister.setTile(tile); + cloister.setLocation(Location.CLOISTER); + features.add(cloister); + game.initFeature(tile, cloister, e); + } + + private void processTowerElement(Element e) { + Tower tower = new Tower(); + tower.setId(game.idSequnceNextVal()); + tower.setTile(tile); + tower.setLocation(Location.TOWER); + features.add(tower); + game.initFeature(tile, tower, e); + } + + + private void processRoadElement(Element e, boolean isTunnelActive) { + String[] sides = asLocation(e); + //using tunnel argument for two cases, tunnel entrance and tunnel underpass - sides.lenght distinguish it + if (sides.length > 1 && isTunnelActive && attributeBoolValue(e, "tunnel")) { + for (String side: sides) { + String[] side_as_array = { side }; + processRoadElement(side_as_array, e, true); + } + } else { + processRoadElement(sides, e, isTunnelActive); + } + } + + private void processRoadElement(String[] sides, Element e, boolean isTunnelActive) { + //Road road = new Road(tile, sides.length, sides.length == 1 && attributeBoolValue(e, "tunnel")); + Road road = new Road(); + road.setId(game.idSequnceNextVal()); + if (isTunnelActive && attributeBoolValue(e, "tunnel")) { + road.setTunnelEnd(Road.OPEN_TUNNEL); + } + initFromDirList(road, sides); + game.initFeature(tile, road, e); + } + + private void processCityElement(Element e) { + String[] sides = asLocation(e); + City c = new City(); + c.setId(game.idSequnceNextVal()); + c.setPennants(attributeIntValue(e, "pennant", 0)); + initFromDirList(c, sides); + game.initFeature(tile, c, e); + } + + //TODO move expansion specific stuff + private void processFarmElement(Element e) { + String[] sides = asLocation(e); + Farm farm = new Farm(); + farm.setId(game.idSequnceNextVal()); + if (e.hasAttribute("city")) { + List cities = new ArrayList<>(); + String[] citiesLocs = asLocations(e, "city"); + for (int j = 0; j < citiesLocs.length; j++) { + Location d = Location.valueOf(citiesLocs[j]); + for (Feature p : features) { + if (p instanceof City) { + if (d.isPartOf(p.getLocation())) { + cities.add((City) p); + break; + } + } + } + } + farm.setAdjoiningCities(cities.toArray(new Feature[cities.size()])); + } + if (attributeBoolValue(e, "pig")) { + //for river is pig herd always present + if (game.hasRule(CustomRule.PIG_HERD_ON_GQ_FARM) || tile.getId() != "GQ.F") { + farm.setPigHerd(true); + } + } + initFromDirList(farm, sides); + game.initFeature(tile, farm, e); + } + + private void initFromDirList(TileFeature piece, String[] sides) { + Location loc = null; + for (int i = 0; i < sides.length; i++) { + Location l = Location.valueOf(sides[i]); + assert !(piece instanceof Farm ^ l.isFarmLocation()) : String.format("Invalid location %s kind for tile %s", l, tile.getId()); + loc = loc == null ? l : loc.union(l); + } + //logger.debug(tile.getId() + "/" + piece.getClass().getSimpleName() + "/" + loc); + piece.setTile(tile); + piece.setLocation(loc); + features.add(piece); + } + +} diff --git a/src/main/java/com/jcloisterzone/board/TilePack.java b/src/main/java/com/jcloisterzone/board/TilePack.java index b12c68e2c..e8c85f8fc 100644 --- a/src/main/java/com/jcloisterzone/board/TilePack.java +++ b/src/main/java/com/jcloisterzone/board/TilePack.java @@ -1,26 +1,26 @@ -package com.jcloisterzone.board; - -import java.util.Set; - -public interface TilePack { - - static final String INACTIVE_GROUP = "inactive"; - - int totalSize(); - boolean isEmpty(); - int size(); - - Tile drawTile(int index); - Tile drawTile(String groupId, String tileId); - Tile drawTile(String tileId); - - /* special Abbey related methods - refactor je to jen kvuli klientovi */ - Tile getAbbeyTile(); - - void activateGroup(String group); - void deactivateGroup(String group); - boolean isGroupActive(String group); - Set getGroups(); - - int getSizeForEdgePattern(EdgePattern edgePattern); -} +package com.jcloisterzone.board; + +import java.util.Set; + +public interface TilePack { + + static final String INACTIVE_GROUP = "inactive"; + + int totalSize(); + boolean isEmpty(); + int size(); + + Tile drawTile(int index); + Tile drawTile(String groupId, String tileId); + Tile drawTile(String tileId); + + /* special Abbey related methods - refactor je to jen kvuli klientovi */ + Tile getAbbeyTile(); + + void activateGroup(String group); + void deactivateGroup(String group); + boolean isGroupActive(String group); + Set getGroups(); + + int getSizeForEdgePattern(EdgePattern edgePattern); +} diff --git a/src/main/java/com/jcloisterzone/board/TilePackFactory.java b/src/main/java/com/jcloisterzone/board/TilePackFactory.java index dfd55f687..9b1ed454e 100644 --- a/src/main/java/com/jcloisterzone/board/TilePackFactory.java +++ b/src/main/java/com/jcloisterzone/board/TilePackFactory.java @@ -1,212 +1,212 @@ -package com.jcloisterzone.board; - -import static com.jcloisterzone.XmlUtils.attributeIntValue; -import static com.jcloisterzone.XmlUtils.attributeStringValue; -import static com.jcloisterzone.XmlUtils.getTileId; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.ini4j.Ini; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.google.common.collect.Maps; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.capability.RiverCapability; -import com.jcloisterzone.game.capability.TunnelCapability; - - -public class TilePackFactory { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - public static final String DEFAULT_TILE_GROUP = "default"; - - private final TileFactory tileFactory = new TileFactory(); - - protected Game game; - protected Ini config; - protected Map defs; - - private Set usedIds = new HashSet<>(); //for assertion only - - - public void setGame(Game game) { - this.game = game; - tileFactory.setGame(game); - } - - public void setConfig(Ini config) { - this.config = config; - } - - public void setExpansions(Set expansions) { - defs = Maps.newLinkedHashMap(); - for (Expansion expansion : expansions) { - defs.put(expansion, getExpansionDefinition(expansion)); - } - } - - public int getExpansionSize(Expansion expansion) { - Element el = getExpansionDefinition(expansion); - NodeList nl = el.getElementsByTagName("tile"); - int size = 0; - for (int i = 0; i < nl.getLength(); i++) { - Element tileElement = (Element) nl.item(i); - String tileId = getTileId(expansion, tileElement); - if (!Tile.ABBEY_TILE_ID.equals(tileId)) { - size += getTileCount(tileElement, tileId); - } - } - return size; - } - - private URL getCardsConfig(Expansion expansion) { - String fileName = config.get("debug", "tiles_"+expansion.name()); - if (fileName == null) { - fileName = "tile-definitions/"+expansion.name().toLowerCase()+".xml"; - } - return TilePackFactory.class.getClassLoader().getResource(fileName); - } - - protected Element getExpansionDefinition(Expansion expansion) { - return XmlUtils.parseDocument(getCardsConfig(expansion)).getDocumentElement(); - } - - protected Map getDiscardTiles() { - Map discard = new HashMap<>(); - for (Element expansionDef: defs.values()) { - NodeList nl = expansionDef.getElementsByTagName("discard"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - String tileId = el.getAttribute("tile"); - if (discard.containsKey(tileId)) { - discard.put(tileId, 1 + discard.get(tileId)); - } else { - discard.put(tileId, 1); - } - } - } - return discard; - } - - protected boolean isTunnelActive(Expansion expansion) { - return expansion == Expansion.TUNNEL || - (game.hasCapability(TunnelCapability.class) && game.hasRule(CustomRule.TUNNELIZE_ALL_EXPANSIONS)); - } - - protected int getTileCount(Element card, String tileId) { - if (Tile.ABBEY_TILE_ID.equals(tileId)) { - return PlayerSlot.COUNT; - } else { - return attributeIntValue(card, "count", 1); - } - } - - protected String getTileGroup(Tile tile, Element card) { - String group = game.getTileGroup(tile); - if (group != null) return group; - return attributeStringValue(card, "group", DEFAULT_TILE_GROUP); - } - - public List createTiles(Expansion expansion, String tileId, Element card, Map discardList) { - if (usedIds.contains(tileId)) { - throw new IllegalArgumentException("Multiple occurences of id " + tileId + " in tile definition xml."); - } - usedIds.add(tileId); - - int count = getTileCount(card, tileId); - - if (discardList.containsKey(tileId)) { - int n = discardList.get(tileId); - count -= n; - if (count <= 0) { //discard can be in multiple expansions and than can be nagative - return Collections.emptyList(); - } - } - - List tiles = new ArrayList(count); - for (int j = 0; j < count; j++) { - Tile tile = tileFactory.createTile(expansion, tileId, card, isTunnelActive(expansion)); - game.initTile(tile, card); //must be called before rotation! - tiles.add(tile); - } - return tiles; - } - - public LinkedList getPreplacedPositions(String tileId, Element card) { - NodeList nl = card.getElementsByTagName("position"); - if (nl.getLength() == 0) return null; - - LinkedList result = new LinkedList(); - for (int i = 0; i < nl.getLength(); i++) { - Element posEl = (Element) nl.item(i); - result.add(new Position(attributeIntValue(posEl, "x"), attributeIntValue(posEl, "y"))); - } - return result; - } - - public DefaultTilePack createTilePack() { - DefaultTilePack tilePack = new DefaultTilePack(); - - Map discardList = getDiscardTiles(); - - for (Entry entry: defs.entrySet()) { - Expansion expansion = entry.getKey(); - NodeList nl = entry.getValue().getElementsByTagName("tile"); - for (int i = 0; i < nl.getLength(); i++) { - Element tileElement = (Element) nl.item(i); - String tileId = getTileId(expansion, tileElement); - LinkedList positions = getPreplacedPositions(tileId, tileElement); - for (Tile tile : createTiles(expansion, tileId, tileElement, discardList)) { - tilePack.addTile(tile, getTileGroup(tile, tileElement)); - if (positions != null && !positions.isEmpty()) { - Position pos = positions.removeFirst(); - //hard coded exceptions - should be declared in pack def - if (game.hasExpansion(Expansion.COUNT)) { - if (tile.getId().equals("BA.RCr")) continue; - if (tile.getId().equals("R1.I.s") || - tile.getId().equals("R2.I.s") || - tile.getId().equals("GQ.RFI")) { - pos = new Position(1, 2); - } - if (tile.getId().equals("WR.CFR")) { - pos = new Position(-2, -2); - } - } else if (game.hasExpansion(Expansion.WIND_ROSE)) { - if (tile.getId().equals("BA.RCr")) continue; - if (game.hasCapability(RiverCapability.class)) { - if (tile.getId().equals("WR.CFR")) { - pos = new Position(0, 1); - } - } - } - logger.info("Setting initial placement {} for {}", pos, tile); - tile.setPosition(pos); - } - } - } - } - return tilePack; - } - - public Game getGame() { - return game; - } - -} +package com.jcloisterzone.board; + +import static com.jcloisterzone.XmlUtils.attributeIntValue; +import static com.jcloisterzone.XmlUtils.attributeStringValue; +import static com.jcloisterzone.XmlUtils.getTileId; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.ini4j.Ini; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.google.common.collect.Maps; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.capability.RiverCapability; +import com.jcloisterzone.game.capability.TunnelCapability; + + +public class TilePackFactory { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + public static final String DEFAULT_TILE_GROUP = "default"; + + private final TileFactory tileFactory = new TileFactory(); + + protected Game game; + protected Ini config; + protected Map defs; + + private Set usedIds = new HashSet<>(); //for assertion only + + + public void setGame(Game game) { + this.game = game; + tileFactory.setGame(game); + } + + public void setConfig(Ini config) { + this.config = config; + } + + public void setExpansions(Set expansions) { + defs = Maps.newLinkedHashMap(); + for (Expansion expansion : expansions) { + defs.put(expansion, getExpansionDefinition(expansion)); + } + } + + public int getExpansionSize(Expansion expansion) { + Element el = getExpansionDefinition(expansion); + NodeList nl = el.getElementsByTagName("tile"); + int size = 0; + for (int i = 0; i < nl.getLength(); i++) { + Element tileElement = (Element) nl.item(i); + String tileId = getTileId(expansion, tileElement); + if (!Tile.ABBEY_TILE_ID.equals(tileId)) { + size += getTileCount(tileElement, tileId); + } + } + return size; + } + + private URL getCardsConfig(Expansion expansion) { + String fileName = config.get("debug", "tiles_"+expansion.name()); + if (fileName == null) { + fileName = "tile-definitions/"+expansion.name().toLowerCase()+".xml"; + } + return TilePackFactory.class.getClassLoader().getResource(fileName); + } + + protected Element getExpansionDefinition(Expansion expansion) { + return XmlUtils.parseDocument(getCardsConfig(expansion)).getDocumentElement(); + } + + protected Map getDiscardTiles() { + Map discard = new HashMap<>(); + for (Element expansionDef: defs.values()) { + NodeList nl = expansionDef.getElementsByTagName("discard"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + String tileId = el.getAttribute("tile"); + if (discard.containsKey(tileId)) { + discard.put(tileId, 1 + discard.get(tileId)); + } else { + discard.put(tileId, 1); + } + } + } + return discard; + } + + protected boolean isTunnelActive(Expansion expansion) { + return expansion == Expansion.TUNNEL || + (game.hasCapability(TunnelCapability.class) && game.hasRule(CustomRule.TUNNELIZE_ALL_EXPANSIONS)); + } + + protected int getTileCount(Element card, String tileId) { + if (Tile.ABBEY_TILE_ID.equals(tileId)) { + return PlayerSlot.COUNT; + } else { + return attributeIntValue(card, "count", 1); + } + } + + protected String getTileGroup(Tile tile, Element card) { + String group = game.getTileGroup(tile); + if (group != null) return group; + return attributeStringValue(card, "group", DEFAULT_TILE_GROUP); + } + + public List createTiles(Expansion expansion, String tileId, Element card, Map discardList) { + if (usedIds.contains(tileId)) { + throw new IllegalArgumentException("Multiple occurences of id " + tileId + " in tile definition xml."); + } + usedIds.add(tileId); + + int count = getTileCount(card, tileId); + + if (discardList.containsKey(tileId)) { + int n = discardList.get(tileId); + count -= n; + if (count <= 0) { //discard can be in multiple expansions and than can be nagative + return Collections.emptyList(); + } + } + + List tiles = new ArrayList(count); + for (int j = 0; j < count; j++) { + Tile tile = tileFactory.createTile(expansion, tileId, card, isTunnelActive(expansion)); + game.initTile(tile, card); //must be called before rotation! + tiles.add(tile); + } + return tiles; + } + + public LinkedList getPreplacedPositions(String tileId, Element card) { + NodeList nl = card.getElementsByTagName("position"); + if (nl.getLength() == 0) return null; + + LinkedList result = new LinkedList(); + for (int i = 0; i < nl.getLength(); i++) { + Element posEl = (Element) nl.item(i); + result.add(new Position(attributeIntValue(posEl, "x"), attributeIntValue(posEl, "y"))); + } + return result; + } + + public DefaultTilePack createTilePack() { + DefaultTilePack tilePack = new DefaultTilePack(); + + Map discardList = getDiscardTiles(); + + for (Entry entry: defs.entrySet()) { + Expansion expansion = entry.getKey(); + NodeList nl = entry.getValue().getElementsByTagName("tile"); + for (int i = 0; i < nl.getLength(); i++) { + Element tileElement = (Element) nl.item(i); + String tileId = getTileId(expansion, tileElement); + LinkedList positions = getPreplacedPositions(tileId, tileElement); + for (Tile tile : createTiles(expansion, tileId, tileElement, discardList)) { + tilePack.addTile(tile, getTileGroup(tile, tileElement)); + if (positions != null && !positions.isEmpty()) { + Position pos = positions.removeFirst(); + //hard coded exceptions - should be declared in pack def + if (game.hasExpansion(Expansion.COUNT)) { + if (tile.getId().equals("BA.RCr")) continue; + if (tile.getId().equals("R1.I.s") || + tile.getId().equals("R2.I.s") || + tile.getId().equals("GQ.RFI")) { + pos = new Position(1, 2); + } + if (tile.getId().equals("WR.CFR")) { + pos = new Position(-2, -2); + } + } else if (game.hasExpansion(Expansion.WIND_ROSE)) { + if (tile.getId().equals("BA.RCr")) continue; + if (game.hasCapability(RiverCapability.class)) { + if (tile.getId().equals("WR.CFR")) { + pos = new Position(0, 1); + } + } + } + logger.info("Setting initial placement {} for {}", pos, tile); + tile.setPosition(pos); + } + } + } + } + return tilePack; + } + + public Game getGame() { + return game; + } + +} diff --git a/src/main/java/com/jcloisterzone/board/TileSymmetry.java b/src/main/java/com/jcloisterzone/board/TileSymmetry.java index 4749cc982..76f40caf9 100644 --- a/src/main/java/com/jcloisterzone/board/TileSymmetry.java +++ b/src/main/java/com/jcloisterzone/board/TileSymmetry.java @@ -1,47 +1,47 @@ -package com.jcloisterzone.board; - -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; - - -public enum TileSymmetry { - - NONE, - S2, - S4; - - static TileSymmetry forTile(Tile tile) { - TileSymmetry symetry = countBaseSymetry(tile); - Location river = tile.getRiver(); - if (river != null) { - if (river == Location.WE || river == Location.NS) { - if (symetry == TileSymmetry.S4) symetry = TileSymmetry.S2; - } else { - symetry = TileSymmetry.NONE; - } - } - return symetry; - } - - private static TileSymmetry countBaseSymetry(Tile tile) { - for (Feature piece : tile.getFeatures()) { - if (piece instanceof Road|| piece instanceof City) { - Feature opposite = tile.getFeature(piece.getLocation().rev()); - if (opposite == null || ! opposite.getClass().equals(piece.getClass())) { - return TileSymmetry.NONE; - } - } - } - for (Feature piece : tile.getFeatures()) { - if (piece instanceof Road|| piece instanceof City) { - Feature opposite = tile.getFeature(piece.getLocation().rotateCW(Rotation.R90)); - if (opposite == null || ! opposite.getClass().equals(piece.getClass())) { - return TileSymmetry.S2; - } - } - } - return TileSymmetry.S4; - } - -} +package com.jcloisterzone.board; + +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; + + +public enum TileSymmetry { + + NONE, + S2, + S4; + + static TileSymmetry forTile(Tile tile) { + TileSymmetry symetry = countBaseSymetry(tile); + Location river = tile.getRiver(); + if (river != null) { + if (river == Location.WE || river == Location.NS) { + if (symetry == TileSymmetry.S4) symetry = TileSymmetry.S2; + } else { + symetry = TileSymmetry.NONE; + } + } + return symetry; + } + + private static TileSymmetry countBaseSymetry(Tile tile) { + for (Feature piece : tile.getFeatures()) { + if (piece instanceof Road|| piece instanceof City) { + Feature opposite = tile.getFeature(piece.getLocation().rev()); + if (opposite == null || ! opposite.getClass().equals(piece.getClass())) { + return TileSymmetry.NONE; + } + } + } + for (Feature piece : tile.getFeatures()) { + if (piece instanceof Road|| piece instanceof City) { + Feature opposite = tile.getFeature(piece.getLocation().rotateCW(Rotation.R90)); + if (opposite == null || ! opposite.getClass().equals(piece.getClass())) { + return TileSymmetry.S2; + } + } + } + return TileSymmetry.S4; + } + +} diff --git a/src/main/java/com/jcloisterzone/board/TileTrigger.java b/src/main/java/com/jcloisterzone/board/TileTrigger.java index d512acd5a..2c5fc7fbd 100644 --- a/src/main/java/com/jcloisterzone/board/TileTrigger.java +++ b/src/main/java/com/jcloisterzone/board/TileTrigger.java @@ -1,12 +1,12 @@ -package com.jcloisterzone.board; - -public enum TileTrigger { - - VOLCANO, - DRAGON, - PORTAL, - BESIEGED, - BAZAAR, - FESTIVAL, - PLAGUE; -} +package com.jcloisterzone.board; + +public enum TileTrigger { + + VOLCANO, + DRAGON, + PORTAL, + BESIEGED, + BAZAAR, + FESTIVAL, + PLAGUE; +} diff --git a/src/main/java/com/jcloisterzone/collection/LocationsMap.java b/src/main/java/com/jcloisterzone/collection/LocationsMap.java index 1a07c640c..a68cd4938 100644 --- a/src/main/java/com/jcloisterzone/collection/LocationsMap.java +++ b/src/main/java/com/jcloisterzone/collection/LocationsMap.java @@ -1,23 +1,23 @@ -package com.jcloisterzone.collection; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; - -public class LocationsMap extends HashMap> { - - private static final long serialVersionUID = -3854304371401326525L; - - public Set getOrCreate(Position p) { - Set locations = get(p); - if (locations == null) { - locations = new HashSet<>(); - put(p, locations); - } - return locations; - } - -} +package com.jcloisterzone.collection; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; + +public class LocationsMap extends HashMap> { + + private static final long serialVersionUID = -3854304371401326525L; + + public Set getOrCreate(Position p) { + Set locations = get(p); + if (locations == null) { + locations = new HashSet<>(); + put(p, locations); + } + return locations; + } + +} diff --git a/src/main/java/com/jcloisterzone/debug/ElementDataDebugDecorator.java b/src/main/java/com/jcloisterzone/debug/ElementDataDebugDecorator.java index f07c0d74f..61d79c26f 100644 --- a/src/main/java/com/jcloisterzone/debug/ElementDataDebugDecorator.java +++ b/src/main/java/com/jcloisterzone/debug/ElementDataDebugDecorator.java @@ -1,46 +1,46 @@ -package com.jcloisterzone.debug; - -import java.awt.Graphics2D; - - -public class ElementDataDebugDecorator /*implements SquareDecoration*/ { - - //TODO use Fonts IF -// private static Font font = new Font(null, Font.BOLD, 11); - - //@Override - public int getZIndex() { - return 1000; - } - -// private static final Map textPosition = -// new ImmutableMap.Builder() -// .put(Direction.N, new ImmutablePoint(10,15)) -// .put(Direction.W, new ImmutablePoint(0,35)) -// .put(Direction.E, new ImmutablePoint(40,55)) -// .put(Direction.S, new ImmutablePoint(30,85)) -// .build(); - - //@Override - public void paint(Graphics2D g) { -// if (sq.getTile() != null) { -// /*Tile tile = Server.instance.getBoard().get(sq.x, sq.y); -// g.setFont(font); -// -// for (Direction d : Direction.sides()) { -// MultiTileFeature mte = tile.getSideElement(d); -// ImmutablePoint tp = textPosition.get(d); -// if (mte == null) { -// g.setColor(Color.RED); -// g.drawString("NULL", tp.getX(), tp.getY()); -// } else { -// g.setColor(Color.BLACK); -// g.drawString(mte.toString(), tp.getX(), tp.getY()); -// } -// } -// g.drawString(tile.getRotation().toString(), 50, 50);*/ -// } - - } - -} +package com.jcloisterzone.debug; + +import java.awt.Graphics2D; + + +public class ElementDataDebugDecorator /*implements SquareDecoration*/ { + + //TODO use Fonts IF +// private static Font font = new Font(null, Font.BOLD, 11); + + //@Override + public int getZIndex() { + return 1000; + } + +// private static final Map textPosition = +// new ImmutableMap.Builder() +// .put(Direction.N, new ImmutablePoint(10,15)) +// .put(Direction.W, new ImmutablePoint(0,35)) +// .put(Direction.E, new ImmutablePoint(40,55)) +// .put(Direction.S, new ImmutablePoint(30,85)) +// .build(); + + //@Override + public void paint(Graphics2D g) { +// if (sq.getTile() != null) { +// /*Tile tile = Server.instance.getBoard().get(sq.x, sq.y); +// g.setFont(font); +// +// for (Direction d : Direction.sides()) { +// MultiTileFeature mte = tile.getSideElement(d); +// ImmutablePoint tp = textPosition.get(d); +// if (mte == null) { +// g.setColor(Color.RED); +// g.drawString("NULL", tp.getX(), tp.getY()); +// } else { +// g.setColor(Color.BLACK); +// g.drawString(mte.toString(), tp.getX(), tp.getY()); +// } +// } +// g.drawString(tile.getRotation().toString(), 50, 50);*/ +// } + + } + +} diff --git a/src/main/java/com/jcloisterzone/event/EventMulticaster.java b/src/main/java/com/jcloisterzone/event/EventMulticaster.java index ad506a41d..c2742cf1d 100644 --- a/src/main/java/com/jcloisterzone/event/EventMulticaster.java +++ b/src/main/java/com/jcloisterzone/event/EventMulticaster.java @@ -1,260 +1,260 @@ -package com.jcloisterzone.event; - -import java.util.EnumSet; -import java.util.EventListener; -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BazaarItem; -import com.jcloisterzone.game.phase.Phase; - - -public class EventMulticaster implements GameEventListener, UserInterface { - - protected final EventListener a, b; - - protected EventMulticaster(EventListener a, EventListener b) { - this.b = b; - this.a = a; - } - - public static EventListener addListener(EventListener a, EventListener b) { - if (a == null) return b; - if (b == null) return a; - return new EventMulticaster(a, b); - } - - public static EventListener removeListener(EventListener l, EventListener lOld) { - if (l instanceof EventMulticaster) { - EventMulticaster mc = (EventMulticaster) l; - return addListener(removeListener(mc.a, lOld), removeListener(mc.b, lOld)); - } else { - return l == lOld ? null : l; - } - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - ((GameEventListener)a).updateCustomRule(rule, enabled); - ((GameEventListener)b).updateCustomRule(rule, enabled); - - } - - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - ((GameEventListener)a).updateExpansion(expansion, enabled); - ((GameEventListener)b).updateExpansion(expansion, enabled); - } - - @Override - public void updateSlot(PlayerSlot slot) { - ((GameEventListener)a).updateSlot(slot); - ((GameEventListener)b).updateSlot(slot); - } - - @Override - public void updateSupportedExpansions(EnumSet expansions) { - ((GameEventListener)a).updateSupportedExpansions(expansions); - ((GameEventListener)b).updateSupportedExpansions(expansions); - } - - @Override - public void started(Snapshot snapshot) { - ((GameEventListener)a).started(snapshot); - ((GameEventListener)b).started(snapshot); - } - - @Override - public void playerActivated(Player p, Player p2) { - ((GameEventListener)a).playerActivated(p, p2); - ((GameEventListener)b).playerActivated(p, p2); - } - - @Override - public void tileDrawn(Tile tile) { - ((GameEventListener)a).tileDrawn(tile); - ((GameEventListener)b).tileDrawn(tile); - } - - @Override - public void tileDiscarded(Tile tile) { - ((GameEventListener)a).tileDiscarded(tile); - ((GameEventListener)b).tileDiscarded(tile); - } - - @Override - public void tilePlaced(Tile tile) { - ((GameEventListener)a).tilePlaced(tile); - ((GameEventListener)b).tilePlaced(tile); - } - - @Override - public void dragonMoved(Position p) { - ((GameEventListener)a).dragonMoved(p); - ((GameEventListener)b).dragonMoved(p); - - } - - @Override - public void fairyMoved(Position p) { - ((GameEventListener)a).fairyMoved(p); - ((GameEventListener)b).fairyMoved(p); - } - - @Override - public void towerIncreased(Position p, Integer height) { - ((GameEventListener)a).towerIncreased(p, height); - ((GameEventListener)b).towerIncreased(p, height); - } - - @Override - public void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem) { - ((GameEventListener)a).bazaarTileSelected(supplyIndex, bazaarItem); - ((GameEventListener)b).bazaarTileSelected(supplyIndex, bazaarItem); - } - - @Override - public void selectAction(List actions, boolean canPass) { - ((UserInterface)a).selectAction(actions, canPass); - ((UserInterface)b).selectAction(actions, canPass); - } - - @Override - public void selectBazaarTile() { - ((UserInterface)a).selectBazaarTile(); - ((UserInterface)b).selectBazaarTile(); - } - - - - @Override - public void makeBazaarBid(int supplyIndex) { - ((UserInterface)a).makeBazaarBid(supplyIndex); - ((UserInterface)b).makeBazaarBid(supplyIndex); - } - - @Override - public void selectBuyOrSellBazaarOffer(int supplyIndex) { - ((UserInterface)a).selectBuyOrSellBazaarOffer(supplyIndex); - ((UserInterface)b).selectBuyOrSellBazaarOffer(supplyIndex); - } - - @Override - public void selectCornCircleOption() { - ((UserInterface)a).selectCornCircleOption(); - ((UserInterface)b).selectCornCircleOption(); - } - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - ((UserInterface)a).selectDragonMove(positions, movesLeft); - ((UserInterface)b).selectDragonMove(positions, movesLeft); - } - - @Override - public void showWarning(String title, String message) { - ((UserInterface)a).showWarning(title, message); - ((UserInterface)b).showWarning(title, message); - } - - @Override - public void gameOver() { - ((GameEventListener)a).gameOver(); - ((GameEventListener)b).gameOver(); - } - - @Override - public void phaseEntered(Phase phase) { - ((GameEventListener)a).phaseEntered(phase); - ((GameEventListener)b).phaseEntered(phase); - } - - @Override - public void ransomPaid(Player from, Player to, Follower ft) { - ((GameEventListener)a).ransomPaid(from, to, ft); - ((GameEventListener)b).ransomPaid(from, to, ft); - } - - @Override - public void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece) { - ((GameEventListener)a).tunnelPiecePlaced(player, p, d, isSecondPiece); - ((GameEventListener)b).tunnelPiecePlaced(player, p, d, isSecondPiece); - } - - @Override - public void deployed(Meeple m) { - ((GameEventListener)a).deployed(m); - ((GameEventListener)b).deployed(m); - } - - - @Override - public void undeployed(Meeple m) { - ((GameEventListener)a).undeployed(m); - ((GameEventListener)b).undeployed(m); - } - - @Override - public void completed(Completable feature, CompletableScoreContext ctx) { - ((GameEventListener)a).completed(feature, ctx); - ((GameEventListener)b).completed(feature, ctx); - } - - @Override - public void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal) { - ((GameEventListener)a).scored(feature, points, label, meeple, isFinal); - ((GameEventListener)b).scored(feature, points, label, meeple, isFinal); - } - - @Override - public void scored(Position position, Player player, int points, String label, boolean isFinal) { - ((GameEventListener)a).scored(position, player, points, label, isFinal); - ((GameEventListener)b).scored(position, player, points, label, isFinal); - } - - @Override - public void bridgeDeployed(Position pos, Location loc) { - ((GameEventListener)a).bridgeDeployed(pos, loc); - ((GameEventListener)b).bridgeDeployed(pos, loc); - } - - @Override - public void castleDeployed(Castle castle1, Castle castle2) { - ((GameEventListener)a).castleDeployed(castle1, castle2); - ((GameEventListener)b).castleDeployed(castle1, castle2); - } - - @Override - public void bazaarAuctionsEnded() { - ((GameEventListener)a).bazaarAuctionsEnded(); - ((GameEventListener)b).bazaarAuctionsEnded(); - } - - @Override - public void plagueSpread() { - ((GameEventListener)a).plagueSpread(); - ((GameEventListener)b).plagueSpread(); - } - - @Override - public String toString() { - return String.valueOf(a) + "," + String.valueOf(b); - } - -} +package com.jcloisterzone.event; + +import java.util.EnumSet; +import java.util.EventListener; +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BazaarItem; +import com.jcloisterzone.game.phase.Phase; + + +public class EventMulticaster implements GameEventListener, UserInterface { + + protected final EventListener a, b; + + protected EventMulticaster(EventListener a, EventListener b) { + this.b = b; + this.a = a; + } + + public static EventListener addListener(EventListener a, EventListener b) { + if (a == null) return b; + if (b == null) return a; + return new EventMulticaster(a, b); + } + + public static EventListener removeListener(EventListener l, EventListener lOld) { + if (l instanceof EventMulticaster) { + EventMulticaster mc = (EventMulticaster) l; + return addListener(removeListener(mc.a, lOld), removeListener(mc.b, lOld)); + } else { + return l == lOld ? null : l; + } + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + ((GameEventListener)a).updateCustomRule(rule, enabled); + ((GameEventListener)b).updateCustomRule(rule, enabled); + + } + + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + ((GameEventListener)a).updateExpansion(expansion, enabled); + ((GameEventListener)b).updateExpansion(expansion, enabled); + } + + @Override + public void updateSlot(PlayerSlot slot) { + ((GameEventListener)a).updateSlot(slot); + ((GameEventListener)b).updateSlot(slot); + } + + @Override + public void updateSupportedExpansions(EnumSet expansions) { + ((GameEventListener)a).updateSupportedExpansions(expansions); + ((GameEventListener)b).updateSupportedExpansions(expansions); + } + + @Override + public void started(Snapshot snapshot) { + ((GameEventListener)a).started(snapshot); + ((GameEventListener)b).started(snapshot); + } + + @Override + public void playerActivated(Player p, Player p2) { + ((GameEventListener)a).playerActivated(p, p2); + ((GameEventListener)b).playerActivated(p, p2); + } + + @Override + public void tileDrawn(Tile tile) { + ((GameEventListener)a).tileDrawn(tile); + ((GameEventListener)b).tileDrawn(tile); + } + + @Override + public void tileDiscarded(Tile tile) { + ((GameEventListener)a).tileDiscarded(tile); + ((GameEventListener)b).tileDiscarded(tile); + } + + @Override + public void tilePlaced(Tile tile) { + ((GameEventListener)a).tilePlaced(tile); + ((GameEventListener)b).tilePlaced(tile); + } + + @Override + public void dragonMoved(Position p) { + ((GameEventListener)a).dragonMoved(p); + ((GameEventListener)b).dragonMoved(p); + + } + + @Override + public void fairyMoved(Position p) { + ((GameEventListener)a).fairyMoved(p); + ((GameEventListener)b).fairyMoved(p); + } + + @Override + public void towerIncreased(Position p, Integer height) { + ((GameEventListener)a).towerIncreased(p, height); + ((GameEventListener)b).towerIncreased(p, height); + } + + @Override + public void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem) { + ((GameEventListener)a).bazaarTileSelected(supplyIndex, bazaarItem); + ((GameEventListener)b).bazaarTileSelected(supplyIndex, bazaarItem); + } + + @Override + public void selectAction(List actions, boolean canPass) { + ((UserInterface)a).selectAction(actions, canPass); + ((UserInterface)b).selectAction(actions, canPass); + } + + @Override + public void selectBazaarTile() { + ((UserInterface)a).selectBazaarTile(); + ((UserInterface)b).selectBazaarTile(); + } + + + + @Override + public void makeBazaarBid(int supplyIndex) { + ((UserInterface)a).makeBazaarBid(supplyIndex); + ((UserInterface)b).makeBazaarBid(supplyIndex); + } + + @Override + public void selectBuyOrSellBazaarOffer(int supplyIndex) { + ((UserInterface)a).selectBuyOrSellBazaarOffer(supplyIndex); + ((UserInterface)b).selectBuyOrSellBazaarOffer(supplyIndex); + } + + @Override + public void selectCornCircleOption() { + ((UserInterface)a).selectCornCircleOption(); + ((UserInterface)b).selectCornCircleOption(); + } + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + ((UserInterface)a).selectDragonMove(positions, movesLeft); + ((UserInterface)b).selectDragonMove(positions, movesLeft); + } + + @Override + public void showWarning(String title, String message) { + ((UserInterface)a).showWarning(title, message); + ((UserInterface)b).showWarning(title, message); + } + + @Override + public void gameOver() { + ((GameEventListener)a).gameOver(); + ((GameEventListener)b).gameOver(); + } + + @Override + public void phaseEntered(Phase phase) { + ((GameEventListener)a).phaseEntered(phase); + ((GameEventListener)b).phaseEntered(phase); + } + + @Override + public void ransomPaid(Player from, Player to, Follower ft) { + ((GameEventListener)a).ransomPaid(from, to, ft); + ((GameEventListener)b).ransomPaid(from, to, ft); + } + + @Override + public void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece) { + ((GameEventListener)a).tunnelPiecePlaced(player, p, d, isSecondPiece); + ((GameEventListener)b).tunnelPiecePlaced(player, p, d, isSecondPiece); + } + + @Override + public void deployed(Meeple m) { + ((GameEventListener)a).deployed(m); + ((GameEventListener)b).deployed(m); + } + + + @Override + public void undeployed(Meeple m) { + ((GameEventListener)a).undeployed(m); + ((GameEventListener)b).undeployed(m); + } + + @Override + public void completed(Completable feature, CompletableScoreContext ctx) { + ((GameEventListener)a).completed(feature, ctx); + ((GameEventListener)b).completed(feature, ctx); + } + + @Override + public void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal) { + ((GameEventListener)a).scored(feature, points, label, meeple, isFinal); + ((GameEventListener)b).scored(feature, points, label, meeple, isFinal); + } + + @Override + public void scored(Position position, Player player, int points, String label, boolean isFinal) { + ((GameEventListener)a).scored(position, player, points, label, isFinal); + ((GameEventListener)b).scored(position, player, points, label, isFinal); + } + + @Override + public void bridgeDeployed(Position pos, Location loc) { + ((GameEventListener)a).bridgeDeployed(pos, loc); + ((GameEventListener)b).bridgeDeployed(pos, loc); + } + + @Override + public void castleDeployed(Castle castle1, Castle castle2) { + ((GameEventListener)a).castleDeployed(castle1, castle2); + ((GameEventListener)b).castleDeployed(castle1, castle2); + } + + @Override + public void bazaarAuctionsEnded() { + ((GameEventListener)a).bazaarAuctionsEnded(); + ((GameEventListener)b).bazaarAuctionsEnded(); + } + + @Override + public void plagueSpread() { + ((GameEventListener)a).plagueSpread(); + ((GameEventListener)b).plagueSpread(); + } + + @Override + public String toString() { + return String.valueOf(a) + "," + String.valueOf(b); + } + +} diff --git a/src/main/java/com/jcloisterzone/event/GameEventAdapter.java b/src/main/java/com/jcloisterzone/event/GameEventAdapter.java index af2ccc89b..33ce120bc 100644 --- a/src/main/java/com/jcloisterzone/event/GameEventAdapter.java +++ b/src/main/java/com/jcloisterzone/event/GameEventAdapter.java @@ -1,128 +1,128 @@ -package com.jcloisterzone.event; - -import java.util.EnumSet; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BazaarItem; -import com.jcloisterzone.game.phase.Phase; - -public class GameEventAdapter implements GameEventListener { - - @Override - public void updateSlot(PlayerSlot slot) { - } - - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - } - - @Override - public void updateSupportedExpansions(EnumSet expansions) { - } - - @Override - public void started(Snapshot snapshot) { - } - - @Override - public void playerActivated(Player turnPlayer, Player activePlayer) { - } - - @Override - public void ransomPaid(Player from, Player to, Follower meeple) { - } - - @Override - public void tileDrawn(Tile tile) { - } - - @Override - public void tileDiscarded(Tile tile) { - } - - @Override - public void tilePlaced(Tile tile) { - } - - @Override - public void dragonMoved(Position p) { - } - - @Override - public void fairyMoved(Position p) { - } - - @Override - public void towerIncreased(Position p, Integer height) { - } - - @Override - public void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece) { - } - - @Override - public void gameOver() { - } - - @Override - public void phaseEntered(Phase phase) { - } - - @Override - public void completed(Completable feature, CompletableScoreContext ctx) { - } - - @Override - public void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal) { - } - - @Override - public void scored(Position position, Player player, int points, String label, boolean isFinal) { - } - - @Override - public void deployed(Meeple meeple) { - } - - @Override - public void undeployed(Meeple meeple) { - } - - @Override - public void bridgeDeployed(Position pos, Location loc) { - } - - @Override - public void castleDeployed(Castle castle1, Castle castle2) { - } - - @Override - public void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem) { - } - - @Override - public void bazaarAuctionsEnded() { - } - - @Override - public void plagueSpread() { - } - -} +package com.jcloisterzone.event; + +import java.util.EnumSet; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BazaarItem; +import com.jcloisterzone.game.phase.Phase; + +public class GameEventAdapter implements GameEventListener { + + @Override + public void updateSlot(PlayerSlot slot) { + } + + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + } + + @Override + public void updateSupportedExpansions(EnumSet expansions) { + } + + @Override + public void started(Snapshot snapshot) { + } + + @Override + public void playerActivated(Player turnPlayer, Player activePlayer) { + } + + @Override + public void ransomPaid(Player from, Player to, Follower meeple) { + } + + @Override + public void tileDrawn(Tile tile) { + } + + @Override + public void tileDiscarded(Tile tile) { + } + + @Override + public void tilePlaced(Tile tile) { + } + + @Override + public void dragonMoved(Position p) { + } + + @Override + public void fairyMoved(Position p) { + } + + @Override + public void towerIncreased(Position p, Integer height) { + } + + @Override + public void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece) { + } + + @Override + public void gameOver() { + } + + @Override + public void phaseEntered(Phase phase) { + } + + @Override + public void completed(Completable feature, CompletableScoreContext ctx) { + } + + @Override + public void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal) { + } + + @Override + public void scored(Position position, Player player, int points, String label, boolean isFinal) { + } + + @Override + public void deployed(Meeple meeple) { + } + + @Override + public void undeployed(Meeple meeple) { + } + + @Override + public void bridgeDeployed(Position pos, Location loc) { + } + + @Override + public void castleDeployed(Castle castle1, Castle castle2) { + } + + @Override + public void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem) { + } + + @Override + public void bazaarAuctionsEnded() { + } + + @Override + public void plagueSpread() { + } + +} diff --git a/src/main/java/com/jcloisterzone/event/GameEventListener.java b/src/main/java/com/jcloisterzone/event/GameEventListener.java index aca44d6c6..5da14b036 100644 --- a/src/main/java/com/jcloisterzone/event/GameEventListener.java +++ b/src/main/java/com/jcloisterzone/event/GameEventListener.java @@ -1,72 +1,72 @@ -package com.jcloisterzone.event; - -import java.util.EnumSet; -import java.util.EventListener; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BazaarItem; -import com.jcloisterzone.game.phase.Phase; - -//TODO change event system - allow adding events withou signature change -public interface GameEventListener extends EventListener { - - void updateSlot(PlayerSlot slot); - void updateExpansion(Expansion expansion, Boolean enabled); - void updateCustomRule(CustomRule rule, Boolean enabled); - void updateSupportedExpansions(EnumSet expansions); - - void started(Snapshot snapshot); - - void playerActivated(Player turnPlayer, Player activePlayer); - - //void scoreAssigned(int score, PlacedFigure pf); //TODO not used, revise use or delete - void ransomPaid(Player from, Player to, Follower meeple); - //void scoreAssigned(int score, Tile tile, Player player); //non-feature score (fairy?) - - void tileDrawn(Tile tile); - - void tileDiscarded(Tile tile); - void tilePlaced(Tile tile); - - void dragonMoved(Position p); - void fairyMoved(Position p); - void towerIncreased(Position p, Integer height); - - void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece); - - void gameOver(); - - void phaseEntered(Phase phase); - - //feature events - void completed(Completable feature, CompletableScoreContext ctx); - - //TODO ad cattegory, pack into object adne merge ? - void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal); - void scored(Position position, Player player, int points, String label, boolean isFinal); - - //meeple events - void deployed(Meeple meeple); - void undeployed(Meeple meeple); - - //BB events - void bridgeDeployed(Position pos, Location loc); - void castleDeployed(Castle castle1, Castle castle2); - void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem); - void bazaarAuctionsEnded(); - - void plagueSpread(); -} +package com.jcloisterzone.event; + +import java.util.EnumSet; +import java.util.EventListener; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BazaarItem; +import com.jcloisterzone.game.phase.Phase; + +//TODO change event system - allow adding events withou signature change +public interface GameEventListener extends EventListener { + + void updateSlot(PlayerSlot slot); + void updateExpansion(Expansion expansion, Boolean enabled); + void updateCustomRule(CustomRule rule, Boolean enabled); + void updateSupportedExpansions(EnumSet expansions); + + void started(Snapshot snapshot); + + void playerActivated(Player turnPlayer, Player activePlayer); + + //void scoreAssigned(int score, PlacedFigure pf); //TODO not used, revise use or delete + void ransomPaid(Player from, Player to, Follower meeple); + //void scoreAssigned(int score, Tile tile, Player player); //non-feature score (fairy?) + + void tileDrawn(Tile tile); + + void tileDiscarded(Tile tile); + void tilePlaced(Tile tile); + + void dragonMoved(Position p); + void fairyMoved(Position p); + void towerIncreased(Position p, Integer height); + + void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece); + + void gameOver(); + + void phaseEntered(Phase phase); + + //feature events + void completed(Completable feature, CompletableScoreContext ctx); + + //TODO ad cattegory, pack into object adne merge ? + void scored(Feature feature, int points, String label, Meeple meeple, boolean isFinal); + void scored(Position position, Player player, int points, String label, boolean isFinal); + + //meeple events + void deployed(Meeple meeple); + void undeployed(Meeple meeple); + + //BB events + void bridgeDeployed(Position pos, Location loc); + void castleDeployed(Castle castle1, Castle castle2); + void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem); + void bazaarAuctionsEnded(); + + void plagueSpread(); +} diff --git a/src/main/java/com/jcloisterzone/feature/Bridge.java b/src/main/java/com/jcloisterzone/feature/Bridge.java index e0fbe5c90..0ecba5f5c 100644 --- a/src/main/java/com/jcloisterzone/feature/Bridge.java +++ b/src/main/java/com/jcloisterzone/feature/Bridge.java @@ -1,11 +1,11 @@ -package com.jcloisterzone.feature; - -import static com.jcloisterzone.ui.I18nUtils._; - -public class Bridge extends Road { - - public static String name() { - return _("Bridge"); - } - -} +package com.jcloisterzone.feature; + +import static com.jcloisterzone.ui.I18nUtils._; + +public class Bridge extends Road { + + public static String name() { + return _("Bridge"); + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/Castle.java b/src/main/java/com/jcloisterzone/feature/Castle.java index fa26dda58..7122aa749 100644 --- a/src/main/java/com/jcloisterzone/feature/Castle.java +++ b/src/main/java/com/jcloisterzone/feature/Castle.java @@ -1,61 +1,61 @@ -package com.jcloisterzone.feature; - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.visitor.score.ScoreContext; - -public class Castle extends MultiTileFeature { - - @Override - public PointCategory getPointCategory() { - return PointCategory.CASTLE; - } - - @Override - public ScoreContext getScoreContext() { - throw new UnsupportedOperationException(); - } - - public Castle getSecondFeature() { - return (Castle) getEdges()[0]; - } - - @Override - public Castle getMaster() { - Castle other = getSecondFeature(); - return getId() < other.getId() ? this : other; - } - - public Position[] getCastleBase() { - Position[] positions = new Position[6]; - positions[0] = getTile().getPosition(); - positions[1] = getSecondFeature().getTile().getPosition(); - return positions; - } - - public Position[] getVicinity() { - Position[] vicinity = new Position[6]; - vicinity[0] = getTile().getPosition(); - vicinity[1] = getSecondFeature().getTile().getPosition(); - if (vicinity[0].x == vicinity[1].x) { - vicinity[2] = vicinity[0].add(Location.W); - vicinity[3] = vicinity[0].add(Location.E); - vicinity[4] = vicinity[1].add(Location.W); - vicinity[5] = vicinity[1].add(Location.E); - } else { - vicinity[2] = vicinity[0].add(Location.N); - vicinity[3] = vicinity[0].add(Location.S); - vicinity[4] = vicinity[1].add(Location.N); - vicinity[5] = vicinity[1].add(Location.S); - } - return vicinity; - } - - public static String name() { - return _("Castle"); - } - -} +package com.jcloisterzone.feature; + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.visitor.score.ScoreContext; + +public class Castle extends MultiTileFeature { + + @Override + public PointCategory getPointCategory() { + return PointCategory.CASTLE; + } + + @Override + public ScoreContext getScoreContext() { + throw new UnsupportedOperationException(); + } + + public Castle getSecondFeature() { + return (Castle) getEdges()[0]; + } + + @Override + public Castle getMaster() { + Castle other = getSecondFeature(); + return getId() < other.getId() ? this : other; + } + + public Position[] getCastleBase() { + Position[] positions = new Position[6]; + positions[0] = getTile().getPosition(); + positions[1] = getSecondFeature().getTile().getPosition(); + return positions; + } + + public Position[] getVicinity() { + Position[] vicinity = new Position[6]; + vicinity[0] = getTile().getPosition(); + vicinity[1] = getSecondFeature().getTile().getPosition(); + if (vicinity[0].x == vicinity[1].x) { + vicinity[2] = vicinity[0].add(Location.W); + vicinity[3] = vicinity[0].add(Location.E); + vicinity[4] = vicinity[1].add(Location.W); + vicinity[5] = vicinity[1].add(Location.E); + } else { + vicinity[2] = vicinity[0].add(Location.N); + vicinity[3] = vicinity[0].add(Location.S); + vicinity[4] = vicinity[1].add(Location.N); + vicinity[5] = vicinity[1].add(Location.S); + } + return vicinity; + } + + public static String name() { + return _("Castle"); + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/City.java b/src/main/java/com/jcloisterzone/feature/City.java index 60e2574f0..6a0d30844 100644 --- a/src/main/java/com/jcloisterzone/feature/City.java +++ b/src/main/java/com/jcloisterzone/feature/City.java @@ -1,69 +1,69 @@ -package com.jcloisterzone.feature; - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.TradeResource; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; - -public class City extends CompletableFeature { - - private int pennants = 0; - private TradeResource tradeResource; - private boolean besieged, cathedral, pricenss, castleBase; - - public TradeResource getTradeResource() { - return tradeResource; - } - public void setTradeResource(TradeResource tradeResource) { - this.tradeResource = tradeResource; - } - public int getPennants() { - return pennants; - } - public void setPennants(int pennants) { - this.pennants = pennants; - } - - public boolean isBesieged() { - return besieged; - } - public void setBesieged(boolean besieged) { - this.besieged = besieged; - } - public boolean isCathedral() { - return cathedral; - } - public void setCathedral(boolean cathedral) { - this.cathedral = cathedral; - } - public boolean isPricenss() { - return pricenss; - } - public void setPricenss(boolean pricenss) { - this.pricenss = pricenss; - } - - public boolean isCastleBase() { - return castleBase; - } - public void setCastleBase(boolean castleBase) { - this.castleBase = castleBase; - } - - @Override - public CityScoreContext getScoreContext() { - return new CityScoreContext(getGame()); - } - - @Override - public PointCategory getPointCategory() { - return PointCategory.CITY; - } - - public static String name() { - return _("City"); - } - - -} +package com.jcloisterzone.feature; + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.TradeResource; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; + +public class City extends CompletableFeature { + + private int pennants = 0; + private TradeResource tradeResource; + private boolean besieged, cathedral, pricenss, castleBase; + + public TradeResource getTradeResource() { + return tradeResource; + } + public void setTradeResource(TradeResource tradeResource) { + this.tradeResource = tradeResource; + } + public int getPennants() { + return pennants; + } + public void setPennants(int pennants) { + this.pennants = pennants; + } + + public boolean isBesieged() { + return besieged; + } + public void setBesieged(boolean besieged) { + this.besieged = besieged; + } + public boolean isCathedral() { + return cathedral; + } + public void setCathedral(boolean cathedral) { + this.cathedral = cathedral; + } + public boolean isPricenss() { + return pricenss; + } + public void setPricenss(boolean pricenss) { + this.pricenss = pricenss; + } + + public boolean isCastleBase() { + return castleBase; + } + public void setCastleBase(boolean castleBase) { + this.castleBase = castleBase; + } + + @Override + public CityScoreContext getScoreContext() { + return new CityScoreContext(getGame()); + } + + @Override + public PointCategory getPointCategory() { + return PointCategory.CITY; + } + + public static String name() { + return _("City"); + } + + +} diff --git a/src/main/java/com/jcloisterzone/feature/Cloister.java b/src/main/java/com/jcloisterzone/feature/Cloister.java index 243691eef..10421e6fe 100644 --- a/src/main/java/com/jcloisterzone/feature/Cloister.java +++ b/src/main/java/com/jcloisterzone/feature/Cloister.java @@ -1,44 +1,44 @@ -package com.jcloisterzone.feature; - - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.visitor.score.CloisterScoreContext; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; - - -public class Cloister extends TileFeature implements Completable { - - private boolean shrine; - - public boolean isShrine() { - return shrine; - } - - public void setShrine(boolean shrine) { - this.shrine = shrine; - } - - @Override - public boolean isOpen() { - Position p = getTile().getPosition(); - return getGame().getBoard().getAdjacentAndDiagonalTiles(p).size() < 8; - } - - @Override - public CompletableScoreContext getScoreContext() { - return new CloisterScoreContext(getGame()); - } - - @Override - public PointCategory getPointCategory() { - return PointCategory.CLOISTER; - } - - public static String name() { - return _("Cloister"); - } - -} +package com.jcloisterzone.feature; + + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.visitor.score.CloisterScoreContext; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; + + +public class Cloister extends TileFeature implements Completable { + + private boolean shrine; + + public boolean isShrine() { + return shrine; + } + + public void setShrine(boolean shrine) { + this.shrine = shrine; + } + + @Override + public boolean isOpen() { + Position p = getTile().getPosition(); + return getGame().getBoard().getAdjacentAndDiagonalTiles(p).size() < 8; + } + + @Override + public CompletableScoreContext getScoreContext() { + return new CloisterScoreContext(getGame()); + } + + @Override + public PointCategory getPointCategory() { + return PointCategory.CLOISTER; + } + + public static String name() { + return _("Cloister"); + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/Completable.java b/src/main/java/com/jcloisterzone/feature/Completable.java index 5822ebfa1..a9a63b5b5 100644 --- a/src/main/java/com/jcloisterzone/feature/Completable.java +++ b/src/main/java/com/jcloisterzone/feature/Completable.java @@ -1,10 +1,10 @@ -package com.jcloisterzone.feature; - -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; - -public interface Completable extends Scoreable { - - boolean isOpen(); - CompletableScoreContext getScoreContext(); - -} +package com.jcloisterzone.feature; + +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; + +public interface Completable extends Scoreable { + + boolean isOpen(); + CompletableScoreContext getScoreContext(); + +} diff --git a/src/main/java/com/jcloisterzone/feature/CompletableFeature.java b/src/main/java/com/jcloisterzone/feature/CompletableFeature.java index dc4019347..a89b5f1be 100644 --- a/src/main/java/com/jcloisterzone/feature/CompletableFeature.java +++ b/src/main/java/com/jcloisterzone/feature/CompletableFeature.java @@ -1,15 +1,15 @@ -package com.jcloisterzone.feature; - - - -public abstract class CompletableFeature extends MultiTileFeature implements Completable { - - @Override - public boolean isOpen() { - for (MultiTileFeature edge : getEdges()) { - if (edge == null) return true; - } - return false; - } - -} +package com.jcloisterzone.feature; + + + +public abstract class CompletableFeature extends MultiTileFeature implements Completable { + + @Override + public boolean isOpen() { + for (MultiTileFeature edge : getEdges()) { + if (edge == null) return true; + } + return false; + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/Farm.java b/src/main/java/com/jcloisterzone/feature/Farm.java index 982a3e172..0a891a830 100644 --- a/src/main/java/com/jcloisterzone/feature/Farm.java +++ b/src/main/java/com/jcloisterzone/feature/Farm.java @@ -1,49 +1,49 @@ -package com.jcloisterzone.feature; - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; - -public class Farm extends MultiTileFeature { - - protected Feature[] adjoiningCities; //or castles - protected boolean pigHerd; - - - public Feature[] getAdjoiningCities() { - return adjoiningCities; - } - - public void setAdjoiningCities(Feature[] adjoiningCities) { - this.adjoiningCities = adjoiningCities; - } - - public boolean isPigHerd() { - return pigHerd; - } - - public void setPigHerd(boolean pigHerd) { - this.pigHerd = pigHerd; - } - - @Override - protected Location[] getSides() { - return Location.sidesFarm(); - } - - @Override - public PointCategory getPointCategory() { - return PointCategory.FARM; - } - - @Override - public FarmScoreContext getScoreContext() { - return new FarmScoreContext(getGame()); - } - - public static String name() { - return _("Farm"); - } -} +package com.jcloisterzone.feature; + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; + +public class Farm extends MultiTileFeature { + + protected Feature[] adjoiningCities; //or castles + protected boolean pigHerd; + + + public Feature[] getAdjoiningCities() { + return adjoiningCities; + } + + public void setAdjoiningCities(Feature[] adjoiningCities) { + this.adjoiningCities = adjoiningCities; + } + + public boolean isPigHerd() { + return pigHerd; + } + + public void setPigHerd(boolean pigHerd) { + this.pigHerd = pigHerd; + } + + @Override + protected Location[] getSides() { + return Location.sidesFarm(); + } + + @Override + public PointCategory getPointCategory() { + return PointCategory.FARM; + } + + @Override + public FarmScoreContext getScoreContext() { + return new FarmScoreContext(getGame()); + } + + public static String name() { + return _("Farm"); + } +} diff --git a/src/main/java/com/jcloisterzone/feature/Feature.java b/src/main/java/com/jcloisterzone/feature/Feature.java index 356570a1f..466c5ab08 100644 --- a/src/main/java/com/jcloisterzone/feature/Feature.java +++ b/src/main/java/com/jcloisterzone/feature/Feature.java @@ -1,29 +1,29 @@ -package com.jcloisterzone.feature; - -import java.util.List; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.figure.Meeple; - -public interface Feature { - - int getId(); - - Location getLocation(); - Location getRawLocation(); - Tile getTile(); - Feature[] getNeighbouring(); - - void addMeeple(Meeple meeple); - void removeMeeple(Meeple meeple); - List getMeeples(); - - T walk(FeatureVisitor visitor); - /** - * Returns feature part with minimal ID. - */ - Feature getMaster(); - -} +package com.jcloisterzone.feature; + +import java.util.List; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.figure.Meeple; + +public interface Feature { + + int getId(); + + Location getLocation(); + Location getRawLocation(); + Tile getTile(); + Feature[] getNeighbouring(); + + void addMeeple(Meeple meeple); + void removeMeeple(Meeple meeple); + List getMeeples(); + + T walk(FeatureVisitor visitor); + /** + * Returns feature part with minimal ID. + */ + Feature getMaster(); + +} diff --git a/src/main/java/com/jcloisterzone/feature/MultiTileFeature.java b/src/main/java/com/jcloisterzone/feature/MultiTileFeature.java index 46dd4f1fb..287fe22f3 100644 --- a/src/main/java/com/jcloisterzone/feature/MultiTileFeature.java +++ b/src/main/java/com/jcloisterzone/feature/MultiTileFeature.java @@ -1,92 +1,92 @@ -package com.jcloisterzone.feature; - -import java.util.HashSet; -import java.util.Set; -import java.util.Stack; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.feature.visitor.FindMaster; - -public abstract class MultiTileFeature extends TileFeature implements Scoreable { - - protected MultiTileFeature[] edges; - - @Override - public void setLocation(Location location) { - super.setLocation(location); - - int edgeCount = 0; - for (Location side : getSides()) { - if (side.intersect(location) != null) { - edgeCount++; - } - } - edges = new MultiTileFeature[edgeCount]; - } - - public MultiTileFeature[] getEdges() { - return edges; - } - - public boolean containsEdge(MultiTileFeature f) { - for (MultiTileFeature edge : edges) { - if (edge == f) return true; - } - return false; - } - - protected Location[] getSides() { - return Location.sides(); - } - - private int getEdgeIndex(Location edge) { - int i = 0; - for (Location side : getSides()) { - if (side.intersect(getLocation()) != null) { - if (side.isPartOf(edge)) return i; - i++; - } - } - throw new IllegalArgumentException("No such edge " + edge); - } - - public void setEdge(Location loc, MultiTileFeature piece) { - edges[getEdgeIndex(loc)] = piece; - } - - public void setAbbeyEdge(Location loc) { - edges[getEdgeIndex(loc)] = this; //special value - } - - - @Override - public Feature getMaster() { - return walk(new FindMaster()); - } - - @Override - public T walk(FeatureVisitor visitor) { - Stack stack = new Stack(); - //TODO implement by bit set or marking - this method can be optimized - Set visited = new HashSet<>(); - MultiTileFeature previous = null; //little optimization - less touching set - stack.push(this); - visited.add(this); - while(! stack.isEmpty()) { - MultiTileFeature nextToVisit = stack.pop(); - if (!visitor.visit(nextToVisit)) { - break; - } - for (MultiTileFeature feature : nextToVisit.edges) { - if (feature != null && feature != nextToVisit && previous != feature && ! visited.contains(feature)) { - visited.add(feature); - stack.push(feature); - } - } - previous = nextToVisit; - } - return visitor.getResult(); - } - -} +package com.jcloisterzone.feature; + +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.feature.visitor.FindMaster; + +public abstract class MultiTileFeature extends TileFeature implements Scoreable { + + protected MultiTileFeature[] edges; + + @Override + public void setLocation(Location location) { + super.setLocation(location); + + int edgeCount = 0; + for (Location side : getSides()) { + if (side.intersect(location) != null) { + edgeCount++; + } + } + edges = new MultiTileFeature[edgeCount]; + } + + public MultiTileFeature[] getEdges() { + return edges; + } + + public boolean containsEdge(MultiTileFeature f) { + for (MultiTileFeature edge : edges) { + if (edge == f) return true; + } + return false; + } + + protected Location[] getSides() { + return Location.sides(); + } + + private int getEdgeIndex(Location edge) { + int i = 0; + for (Location side : getSides()) { + if (side.intersect(getLocation()) != null) { + if (side.isPartOf(edge)) return i; + i++; + } + } + throw new IllegalArgumentException("No such edge " + edge); + } + + public void setEdge(Location loc, MultiTileFeature piece) { + edges[getEdgeIndex(loc)] = piece; + } + + public void setAbbeyEdge(Location loc) { + edges[getEdgeIndex(loc)] = this; //special value + } + + + @Override + public Feature getMaster() { + return walk(new FindMaster()); + } + + @Override + public T walk(FeatureVisitor visitor) { + Stack stack = new Stack(); + //TODO implement by bit set or marking - this method can be optimized + Set visited = new HashSet<>(); + MultiTileFeature previous = null; //little optimization - less touching set + stack.push(this); + visited.add(this); + while(! stack.isEmpty()) { + MultiTileFeature nextToVisit = stack.pop(); + if (!visitor.visit(nextToVisit)) { + break; + } + for (MultiTileFeature feature : nextToVisit.edges) { + if (feature != null && feature != nextToVisit && previous != feature && ! visited.contains(feature)) { + visited.add(feature); + stack.push(feature); + } + } + previous = nextToVisit; + } + return visitor.getResult(); + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/Road.java b/src/main/java/com/jcloisterzone/feature/Road.java index c921ad5da..6e01d3e90 100644 --- a/src/main/java/com/jcloisterzone/feature/Road.java +++ b/src/main/java/com/jcloisterzone/feature/Road.java @@ -1,69 +1,69 @@ -package com.jcloisterzone.feature; - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.feature.visitor.score.RoadScoreContext; - -public class Road extends CompletableFeature { - - private boolean inn = false; - /* - * 0 - no tunnel -1 - open tunnel n - player token n+100 - player token B (2 - * players game) - */ - private int tunnelEnd; - public static final int OPEN_TUNNEL = -1; - - public boolean isInn() { - return inn; - } - - public void setInn(boolean inn) { - this.inn = inn; - } - - public int getTunnelEnd() { - return tunnelEnd; - } - - public void setTunnelEnd(int tunnelEnd) { - this.tunnelEnd = tunnelEnd; - } - - public boolean isTunnelEnd() { - return tunnelEnd != 0; - } - - public boolean isTunnelOpen() { - return tunnelEnd == OPEN_TUNNEL; - } - - @Override - public void setLocation(Location location) { - super.setLocation(location); - if (isTunnelEnd()) { - // reallocate - extra edge for tunnel - edges = new MultiTileFeature[edges.length + 1]; - } - } - - public void setTunnelEdge(MultiTileFeature f) { - edges[edges.length - 1] = f; - } - - @Override - public RoadScoreContext getScoreContext() { - return new RoadScoreContext(getGame()); - } - - @Override - public PointCategory getPointCategory() { - return PointCategory.ROAD; - } - - public static String name() { - return _("Road"); - } -} +package com.jcloisterzone.feature; + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.feature.visitor.score.RoadScoreContext; + +public class Road extends CompletableFeature { + + private boolean inn = false; + /* + * 0 - no tunnel -1 - open tunnel n - player token n+100 - player token B (2 + * players game) + */ + private int tunnelEnd; + public static final int OPEN_TUNNEL = -1; + + public boolean isInn() { + return inn; + } + + public void setInn(boolean inn) { + this.inn = inn; + } + + public int getTunnelEnd() { + return tunnelEnd; + } + + public void setTunnelEnd(int tunnelEnd) { + this.tunnelEnd = tunnelEnd; + } + + public boolean isTunnelEnd() { + return tunnelEnd != 0; + } + + public boolean isTunnelOpen() { + return tunnelEnd == OPEN_TUNNEL; + } + + @Override + public void setLocation(Location location) { + super.setLocation(location); + if (isTunnelEnd()) { + // reallocate - extra edge for tunnel + edges = new MultiTileFeature[edges.length + 1]; + } + } + + public void setTunnelEdge(MultiTileFeature f) { + edges[edges.length - 1] = f; + } + + @Override + public RoadScoreContext getScoreContext() { + return new RoadScoreContext(getGame()); + } + + @Override + public PointCategory getPointCategory() { + return PointCategory.ROAD; + } + + public static String name() { + return _("Road"); + } +} diff --git a/src/main/java/com/jcloisterzone/feature/Scoreable.java b/src/main/java/com/jcloisterzone/feature/Scoreable.java index 8df2564b5..2e4ad28ed 100644 --- a/src/main/java/com/jcloisterzone/feature/Scoreable.java +++ b/src/main/java/com/jcloisterzone/feature/Scoreable.java @@ -1,11 +1,11 @@ -package com.jcloisterzone.feature; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.feature.visitor.score.ScoreContext; - -public interface Scoreable extends Feature { - - PointCategory getPointCategory(); - ScoreContext getScoreContext(); - -} +package com.jcloisterzone.feature; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.feature.visitor.score.ScoreContext; + +public interface Scoreable extends Feature { + + PointCategory getPointCategory(); + ScoreContext getScoreContext(); + +} diff --git a/src/main/java/com/jcloisterzone/feature/TileFeature.java b/src/main/java/com/jcloisterzone/feature/TileFeature.java index 4f34d18ac..eed336aae 100644 --- a/src/main/java/com/jcloisterzone/feature/TileFeature.java +++ b/src/main/java/com/jcloisterzone/feature/TileFeature.java @@ -1,146 +1,146 @@ -package com.jcloisterzone.feature; - -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -import com.google.common.collect.ObjectArrays; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; - -public abstract class TileFeature implements Feature { - - private int id; //unique feature identifier - private Tile tile; - private Location location; - private Feature[] neighbouring; - - private List meeples = Collections.emptyList(); - - protected Game getGame() { - return tile.getGame(); - } - - @Override - public T walk(FeatureVisitor visitor) { - visitor.visit(this); - return visitor.getResult(); - } - - @Override - public Feature getMaster() { - return this; - } - - @Override - public void addMeeple(Meeple meeple) { - if (meeples.isEmpty()) { - meeples = Collections.singletonList(meeple); - meeple.setIndex(0); - } else { - //rare case (eg. Crop circles allows this) when more then one followe stay on same feature - int index = -1; - for (Meeple m : meeples) { - if (m.getIndex() > index) index = m.getIndex(); - } - meeples = new LinkedList<>(meeples); - meeples.add(meeple); - meeple.setIndex(index+1); - } - } - - @Override - public void removeMeeple(Meeple meeple) { - if (meeples.size() == 1) { - assert meeples.get(0) == meeple; - meeples = Collections.emptyList(); - } else { - meeples.remove(meeple); - } - meeple.setIndex(null); - } - - @Override - public final List getMeeples() { - return meeples; - } - -// @Override -// public final Set> getMeepleTypes() { -// if (meeples.size() == 1) { -// return Collections.>singleton(meeples.get(0).getClass()); -// } -// Set> types = new HashSet<>(); -// for (Meeple m : meeples) { -// types.add(m.getClass()); -// } -// return types; -// } - - public Feature[] getNeighbouring() { - return neighbouring; - } - - public void addNeighbouring(Feature[] neighbouring) { - if (this.neighbouring == null) { - this.neighbouring = neighbouring; - } else { - this.neighbouring = ObjectArrays.concat(this.neighbouring, neighbouring, Feature.class); - } - } - - public Tile getTile() { - return tile; - } - - public void setTile(Tile tile) { - assert this.tile == null; - this.tile = tile; - } - - public Location getLocation() { - return location.rotateCW(tile.getRotation()); - } - - public Location getRawLocation() { - return location; - } - - public void setLocation(Location location) { - assert this.location == null; - this.location = location; - } - - @Override - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Override - public int hashCode() { - return id; - } - - @Override - public String toString() { - return getClass().getSimpleName()+"@"+getId(); - } - - public static String getLocalizedNamefor (Class feature) { - try { - Method m = feature.getMethod("name"); - return (String) m.invoke(null); - } catch (Exception e) { - return feature.getSimpleName(); - } - } - -} +package com.jcloisterzone.feature; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import com.google.common.collect.ObjectArrays; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; + +public abstract class TileFeature implements Feature { + + private int id; //unique feature identifier + private Tile tile; + private Location location; + private Feature[] neighbouring; + + private List meeples = Collections.emptyList(); + + protected Game getGame() { + return tile.getGame(); + } + + @Override + public T walk(FeatureVisitor visitor) { + visitor.visit(this); + return visitor.getResult(); + } + + @Override + public Feature getMaster() { + return this; + } + + @Override + public void addMeeple(Meeple meeple) { + if (meeples.isEmpty()) { + meeples = Collections.singletonList(meeple); + meeple.setIndex(0); + } else { + //rare case (eg. Crop circles allows this) when more then one followe stay on same feature + int index = -1; + for (Meeple m : meeples) { + if (m.getIndex() > index) index = m.getIndex(); + } + meeples = new LinkedList<>(meeples); + meeples.add(meeple); + meeple.setIndex(index+1); + } + } + + @Override + public void removeMeeple(Meeple meeple) { + if (meeples.size() == 1) { + assert meeples.get(0) == meeple; + meeples = Collections.emptyList(); + } else { + meeples.remove(meeple); + } + meeple.setIndex(null); + } + + @Override + public final List getMeeples() { + return meeples; + } + +// @Override +// public final Set> getMeepleTypes() { +// if (meeples.size() == 1) { +// return Collections.>singleton(meeples.get(0).getClass()); +// } +// Set> types = new HashSet<>(); +// for (Meeple m : meeples) { +// types.add(m.getClass()); +// } +// return types; +// } + + public Feature[] getNeighbouring() { + return neighbouring; + } + + public void addNeighbouring(Feature[] neighbouring) { + if (this.neighbouring == null) { + this.neighbouring = neighbouring; + } else { + this.neighbouring = ObjectArrays.concat(this.neighbouring, neighbouring, Feature.class); + } + } + + public Tile getTile() { + return tile; + } + + public void setTile(Tile tile) { + assert this.tile == null; + this.tile = tile; + } + + public Location getLocation() { + return location.rotateCW(tile.getRotation()); + } + + public Location getRawLocation() { + return location; + } + + public void setLocation(Location location) { + assert this.location == null; + this.location = location; + } + + @Override + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + return getClass().getSimpleName()+"@"+getId(); + } + + public static String getLocalizedNamefor (Class feature) { + try { + Method m = feature.getMethod("name"); + return (String) m.invoke(null); + } catch (Exception e) { + return feature.getSimpleName(); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/Tower.java b/src/main/java/com/jcloisterzone/feature/Tower.java index 7ee2e5dc7..49836d491 100644 --- a/src/main/java/com/jcloisterzone/feature/Tower.java +++ b/src/main/java/com/jcloisterzone/feature/Tower.java @@ -1,36 +1,36 @@ -package com.jcloisterzone.feature; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.util.List; - -import com.jcloisterzone.figure.Meeple; - - -public class Tower extends TileFeature { - - private int height; - - public int increaseHeight() { - return ++height; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public Meeple getMeeple() { - List meeples = getMeeples(); - if (meeples.isEmpty()) return null; - return meeples.get(0); - } - - public static String name() { - return _("Tower"); - } - -} +package com.jcloisterzone.feature; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.util.List; + +import com.jcloisterzone.figure.Meeple; + + +public class Tower extends TileFeature { + + private int height; + + public int increaseHeight() { + return ++height; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public Meeple getMeeple() { + List meeples = getMeeples(); + if (meeples.isEmpty()) return null; + return meeples.get(0); + } + + public static String name() { + return _("Tower"); + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/score/ScoreAllCallback.java b/src/main/java/com/jcloisterzone/feature/score/ScoreAllCallback.java index 47b6c5939..a97079ab0 100644 --- a/src/main/java/com/jcloisterzone/feature/score/ScoreAllCallback.java +++ b/src/main/java/com/jcloisterzone/feature/score/ScoreAllCallback.java @@ -1,23 +1,23 @@ -package com.jcloisterzone.feature.score; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Meeple; - -public interface ScoreAllCallback { - - void scoreCompletableFeature(CompletableScoreContext ctx); - void scoreFarm(FarmScoreContext ctx, Player player); - void scoreBarn(FarmScoreContext ctx, Barn meeple); - void scoreCastle(Meeple meeple, Castle castle); - - CompletableScoreContext getCompletableScoreContext(Completable completable); - FarmScoreContext getFarmScoreContext(Farm farm); - -} - +package com.jcloisterzone.feature.score; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Meeple; + +public interface ScoreAllCallback { + + void scoreCompletableFeature(CompletableScoreContext ctx); + void scoreFarm(FarmScoreContext ctx, Player player); + void scoreBarn(FarmScoreContext ctx, Barn meeple); + void scoreCastle(Meeple meeple, Castle castle); + + CompletableScoreContext getCompletableScoreContext(Completable completable); + FarmScoreContext getFarmScoreContext(Farm farm); + +} + diff --git a/src/main/java/com/jcloisterzone/feature/score/ScoreAllFeatureFinder.java b/src/main/java/com/jcloisterzone/feature/score/ScoreAllFeatureFinder.java index ccb358e3c..89627d32f 100644 --- a/src/main/java/com/jcloisterzone/feature/score/ScoreAllFeatureFinder.java +++ b/src/main/java/com/jcloisterzone/feature/score/ScoreAllFeatureFinder.java @@ -1,117 +1,117 @@ -package com.jcloisterzone.feature.score; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Sets; -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Special; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; - -/** - * Sort farm for correct 1st edition scoring. - */ -public class ScoreAllFeatureFinder { - - private Set alreadyRated = new HashSet<>(); - private List farmContexts = new ArrayList<>(); - private Map cityCache = new HashMap<>(); - private Map> scoredCities; - - public void scoreAll(Game game, ScoreAllCallback callback) { - if (game.hasRule(CustomRule.FARM_CITY_SCORED_ONCE)) { - scoredCities = new HashMap<>(); - for (Player p : game.getAllPlayers()) { - scoredCities.put(p, Sets.newHashSet()); - } - } - for (Meeple m : game.getDeployedMeeples()) { - if (!(m instanceof Follower)) continue; - Feature f = m.getFeature(); - - if (f instanceof Castle) { - callback.scoreCastle(m, (Castle) f); - continue; - } - - if (!(f instanceof Completable)) continue; - if (alreadyRated.contains(m)) continue; - - Completable completable = (Completable) f; - CompletableScoreContext ctx = callback.getCompletableScoreContext(completable); - if (ctx instanceof CityScoreContext) { - ((CityScoreContext) ctx).setCityCache(cityCache); - } - completable.walk(ctx); - alreadyRated.addAll(ctx.getFollowers()); - callback.scoreCompletableFeature(ctx); - } - for (Meeple m : game.getDeployedMeeples()) { - if (!(m instanceof Follower) && !(m instanceof Barn)) continue; - Feature f = m.getFeature(); - if (!(f instanceof Farm)) continue; - if (alreadyRated.contains(m)) continue; - - Farm farm = (Farm) f; - FarmScoreContext ctx = callback.getFarmScoreContext(farm); - ctx.setCityCache(cityCache); - if (scoredCities != null) { - ctx.setScoredCities(scoredCities); - } - farm.walk(ctx); - alreadyRated.addAll(ctx.getFollowers()); - alreadyRated.addAll(ctx.getSpecialMeeples()); //farm can contains Barn! - farmContexts.add(ctx); - } - - for (Player p : game.getAllPlayers()) { - //2nd edition farm scoring (CustomRule.FARM_CITY_SCORED_ONCE) requires sort to assign correct (highest) points - Collections.sort(farmContexts, new FarmPoitsPerCityComparator(p)); - for (FarmScoreContext ctx : farmContexts) { - if (ctx.getMajorOwners().contains(p)) { - callback.scoreFarm(ctx, p); - } - } - } - for (FarmScoreContext ctx : farmContexts) { - for (Special m : ctx.getSpecialMeeples()) { - if (m instanceof Barn) { - callback.scoreBarn(ctx, (Barn) m); - } - } - } - } - - private static class FarmPoitsPerCityComparator implements Comparator { - - private final Player player; - - public FarmPoitsPerCityComparator(Player player) { - this.player = player; - } - - @Override - public int compare(FarmScoreContext o1, FarmScoreContext o2) { - //reverse order according to city points - return o2.getPointsPerCity(player) - o1.getPointsPerCity(player); - } - } -} +package com.jcloisterzone.feature.score; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Sets; +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Special; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; + +/** + * Sort farm for correct 1st edition scoring. + */ +public class ScoreAllFeatureFinder { + + private Set alreadyRated = new HashSet<>(); + private List farmContexts = new ArrayList<>(); + private Map cityCache = new HashMap<>(); + private Map> scoredCities; + + public void scoreAll(Game game, ScoreAllCallback callback) { + if (game.hasRule(CustomRule.FARM_CITY_SCORED_ONCE)) { + scoredCities = new HashMap<>(); + for (Player p : game.getAllPlayers()) { + scoredCities.put(p, Sets.newHashSet()); + } + } + for (Meeple m : game.getDeployedMeeples()) { + if (!(m instanceof Follower)) continue; + Feature f = m.getFeature(); + + if (f instanceof Castle) { + callback.scoreCastle(m, (Castle) f); + continue; + } + + if (!(f instanceof Completable)) continue; + if (alreadyRated.contains(m)) continue; + + Completable completable = (Completable) f; + CompletableScoreContext ctx = callback.getCompletableScoreContext(completable); + if (ctx instanceof CityScoreContext) { + ((CityScoreContext) ctx).setCityCache(cityCache); + } + completable.walk(ctx); + alreadyRated.addAll(ctx.getFollowers()); + callback.scoreCompletableFeature(ctx); + } + for (Meeple m : game.getDeployedMeeples()) { + if (!(m instanceof Follower) && !(m instanceof Barn)) continue; + Feature f = m.getFeature(); + if (!(f instanceof Farm)) continue; + if (alreadyRated.contains(m)) continue; + + Farm farm = (Farm) f; + FarmScoreContext ctx = callback.getFarmScoreContext(farm); + ctx.setCityCache(cityCache); + if (scoredCities != null) { + ctx.setScoredCities(scoredCities); + } + farm.walk(ctx); + alreadyRated.addAll(ctx.getFollowers()); + alreadyRated.addAll(ctx.getSpecialMeeples()); //farm can contains Barn! + farmContexts.add(ctx); + } + + for (Player p : game.getAllPlayers()) { + //2nd edition farm scoring (CustomRule.FARM_CITY_SCORED_ONCE) requires sort to assign correct (highest) points + Collections.sort(farmContexts, new FarmPoitsPerCityComparator(p)); + for (FarmScoreContext ctx : farmContexts) { + if (ctx.getMajorOwners().contains(p)) { + callback.scoreFarm(ctx, p); + } + } + } + for (FarmScoreContext ctx : farmContexts) { + for (Special m : ctx.getSpecialMeeples()) { + if (m instanceof Barn) { + callback.scoreBarn(ctx, (Barn) m); + } + } + } + } + + private static class FarmPoitsPerCityComparator implements Comparator { + + private final Player player; + + public FarmPoitsPerCityComparator(Player player) { + this.player = player; + } + + @Override + public int compare(FarmScoreContext o1, FarmScoreContext o2) { + //reverse order according to city points + return o2.getPointsPerCity(player) - o1.getPointsPerCity(player); + } + } +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/FeatureVisitor.java b/src/main/java/com/jcloisterzone/feature/visitor/FeatureVisitor.java index 90a4c7c59..e9dfee72b 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/FeatureVisitor.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/FeatureVisitor.java @@ -1,12 +1,12 @@ -package com.jcloisterzone.feature.visitor; - -import com.jcloisterzone.feature.Feature; - -public interface FeatureVisitor { - - /** if false is returned visiting is stopped immediately */ - boolean visit(Feature feature); - - /** helper method for retrieving simple results */ - T getResult(); -} +package com.jcloisterzone.feature.visitor; + +import com.jcloisterzone.feature.Feature; + +public interface FeatureVisitor { + + /** if false is returned visiting is stopped immediately */ + boolean visit(Feature feature); + + /** helper method for retrieving simple results */ + T getResult(); +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/FindMaster.java b/src/main/java/com/jcloisterzone/feature/visitor/FindMaster.java index d11fe4da6..2863969ac 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/FindMaster.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/FindMaster.java @@ -1,27 +1,27 @@ -package com.jcloisterzone.feature.visitor; - -import com.jcloisterzone.feature.Feature; - -public class FindMaster implements FeatureVisitor { - - private Feature master; - - @Override - public boolean visit(Feature feature) { - if (master == null || master.getId() > feature.getId()) { - master = feature; - } - return true; - } - - @Deprecated // - public Feature getMasterFeature() { - return master; - } - - @Override - public Feature getResult() { - return master; - } - -} +package com.jcloisterzone.feature.visitor; + +import com.jcloisterzone.feature.Feature; + +public class FindMaster implements FeatureVisitor { + + private Feature master; + + @Override + public boolean visit(Feature feature) { + if (master == null || master.getId() > feature.getId()) { + master = feature; + } + return true; + } + + @Deprecated // + public Feature getMasterFeature() { + return master; + } + + @Override + public Feature getResult() { + return master; + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/IsCompleted.java b/src/main/java/com/jcloisterzone/feature/visitor/IsCompleted.java index a1817055b..78936435a 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/IsCompleted.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/IsCompleted.java @@ -1,25 +1,25 @@ -package com.jcloisterzone.feature.visitor; - -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; - -public class IsCompleted implements FeatureVisitor { - - private boolean isCompleted = true; - - @Override - public boolean visit(Feature feature) { - Completable completable = (Completable) feature; - if (completable.isOpen()) { - isCompleted = false; - return false; - } - return true; - } - - @Override - public Boolean getResult() { - return isCompleted; - } - -} +package com.jcloisterzone.feature.visitor; + +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; + +public class IsCompleted implements FeatureVisitor { + + private boolean isCompleted = true; + + @Override + public boolean visit(Feature feature) { + Completable completable = (Completable) feature; + if (completable.isOpen()) { + isCompleted = false; + return false; + } + return true; + } + + @Override + public Boolean getResult() { + return isCompleted; + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/IsOccupied.java b/src/main/java/com/jcloisterzone/feature/visitor/IsOccupied.java index 1ecf568be..f0ddf61f6 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/IsOccupied.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/IsOccupied.java @@ -1,42 +1,42 @@ -package com.jcloisterzone.feature.visitor; - -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Meeple; - -public class IsOccupied implements FeatureVisitor { - - private Player player; - private Class clazz; - - private boolean isOccupied = false; - - public IsOccupied with(Player player) { - this.player = player; - return this; - } - - public IsOccupied with(Class clazz) { - this.clazz = clazz; - return this; - } - - @Override - public boolean visit(Feature feature) { - List meeples = feature.getMeeples(); - for (Meeple m : meeples) { - if (player != null && m.getPlayer() != player) continue; - if (clazz != null && !clazz.isInstance(m)) continue; - isOccupied = true; - return false; - } - return true; - } - - @Override - public Boolean getResult() { - return isOccupied; - } -} +package com.jcloisterzone.feature.visitor; + +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Meeple; + +public class IsOccupied implements FeatureVisitor { + + private Player player; + private Class clazz; + + private boolean isOccupied = false; + + public IsOccupied with(Player player) { + this.player = player; + return this; + } + + public IsOccupied with(Class clazz) { + this.clazz = clazz; + return this; + } + + @Override + public boolean visit(Feature feature) { + List meeples = feature.getMeeples(); + for (Meeple m : meeples) { + if (player != null && m.getPlayer() != player) continue; + if (clazz != null && !clazz.isInstance(m)) continue; + isOccupied = true; + return false; + } + return true; + } + + @Override + public Boolean getResult() { + return isOccupied; + } +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/IsOccupiedOrCompleted.java b/src/main/java/com/jcloisterzone/feature/visitor/IsOccupiedOrCompleted.java index 469b32e5b..c440242de 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/IsOccupiedOrCompleted.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/IsOccupiedOrCompleted.java @@ -1,23 +1,23 @@ -package com.jcloisterzone.feature.visitor; - -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; - -public class IsOccupiedOrCompleted extends IsOccupied { - - private boolean isCompleted = true; - - @Override - public boolean visit(Feature feature) { - Completable completable = (Completable) feature; - if (completable.isOpen()) { - isCompleted = false; - } - return super.visit(feature); - } - - @Override - public Boolean getResult() { - return isCompleted || super.getResult(); - } -} +package com.jcloisterzone.feature.visitor; + +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; + +public class IsOccupiedOrCompleted extends IsOccupied { + + private boolean isCompleted = true; + + @Override + public boolean visit(Feature feature) { + Completable completable = (Completable) feature; + if (completable.isOpen()) { + isCompleted = false; + } + return super.visit(feature); + } + + @Override + public Boolean getResult() { + return isCompleted || super.getResult(); + } +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/RemoveLonelyBuilderAndPig.java b/src/main/java/com/jcloisterzone/feature/visitor/RemoveLonelyBuilderAndPig.java index 9536c855e..5dae2cd96 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/RemoveLonelyBuilderAndPig.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/RemoveLonelyBuilderAndPig.java @@ -1,43 +1,43 @@ -package com.jcloisterzone.feature.visitor; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Builder; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Pig; -import com.jcloisterzone.figure.Special; - -public class RemoveLonelyBuilderAndPig implements FeatureVisitor { - - Player player; - Special toRemove = null; - - public RemoveLonelyBuilderAndPig(Player player) { - this.player = player; - } - - @Override - public boolean visit(Feature feature) { - for (Meeple m : feature.getMeeples()) { - if (m.getPlayer() != player) continue; - if (m instanceof Builder || m instanceof Pig) { - toRemove = (Special) m; - continue; - } - if (m instanceof Follower) { - //another follower exists - toRemove = null; - return false; //can stop immediately - } - } - return true; - } - - @Override - public Special getResult() { - return toRemove; - } - - +package com.jcloisterzone.feature.visitor; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Builder; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Pig; +import com.jcloisterzone.figure.Special; + +public class RemoveLonelyBuilderAndPig implements FeatureVisitor { + + Player player; + Special toRemove = null; + + public RemoveLonelyBuilderAndPig(Player player) { + this.player = player; + } + + @Override + public boolean visit(Feature feature) { + for (Meeple m : feature.getMeeples()) { + if (m.getPlayer() != player) continue; + if (m instanceof Builder || m instanceof Pig) { + toRemove = (Special) m; + continue; + } + if (m instanceof Follower) { + //another follower exists + toRemove = null; + return false; //can stop immediately + } + } + return true; + } + + @Override + public Special getResult() { + return toRemove; + } + + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/feature/visitor/SelfReturningVisitor.java b/src/main/java/com/jcloisterzone/feature/visitor/SelfReturningVisitor.java index 0fdaa1528..e7727a95d 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/SelfReturningVisitor.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/SelfReturningVisitor.java @@ -1,10 +1,10 @@ -package com.jcloisterzone.feature.visitor; - -public abstract class SelfReturningVisitor implements FeatureVisitor { - - @Override - public SelfReturningVisitor getResult() { - return this; - } - -} +package com.jcloisterzone.feature.visitor; + +public abstract class SelfReturningVisitor implements FeatureVisitor { + + @Override + public SelfReturningVisitor getResult() { + return this; + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/AbstractScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/AbstractScoreContext.java index 37999c8ed..d89cb5555 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/AbstractScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/AbstractScoreContext.java @@ -1,116 +1,116 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Iterables; -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Scoreable; -import com.jcloisterzone.feature.visitor.SelfReturningVisitor; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Special; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.FairyCapability; - -public abstract class AbstractScoreContext extends SelfReturningVisitor implements ScoreContext { - - private final Game game; - - private Scoreable feature; - - int bestPower = 1; //minimal power to score must be 1 (mayor power can be 0) - - private Map power = new HashMap<>(); - private Map sample = new HashMap<>(); - private Position preferedPos = null; - - private List followers = new ArrayList<>(); - private List specialMeeples = new ArrayList<>(); - - public AbstractScoreContext(Game game) { - this.game = game; - if (game.hasCapability(FairyCapability.class)) { - preferedPos = game.getCapability(FairyCapability.class).getFairyPosition(); - } - } - - public Game getGame() { - return game; - } - - @Override - public Scoreable getMasterFeature() { - return feature; - } - - @Override - public boolean visit(Feature feature) { - for (Meeple meeple : feature.getMeeples()) { - if (meeple instanceof Follower) { - Follower follower = (Follower) meeple; - Integer prev = power.get(follower.getPlayer()); - int followerPower = follower.getPower(); - int curr = prev == null ? followerPower : prev + followerPower; - power.put(follower.getPlayer(), curr); - if (curr > bestPower) bestPower = curr; - if (sample.containsKey(follower.getPlayer())) { - if (follower.at(preferedPos)) { - sample.put(follower.getPlayer(), follower); - } - } else { - sample.put(follower.getPlayer(), follower); - } - } - if (meeple instanceof Follower) { - followers.add((Follower) meeple); - } else if (meeple instanceof Special) { - specialMeeples.add((Special) meeple); - } - } - if (this.feature == null || this.feature.getId() > feature.getId()) { - this.feature = (Scoreable) feature; - } - return true; - } - - public Follower getSampleFollower(Player player) { - return sample.get(player); - } - - public Set getMajorOwners() { - Set majorOwners = new HashSet<>(); - for (Player player: power.keySet()) { - int pwr = power.get(player); - if (pwr == bestPower) { - majorOwners.add(player); - } - } - return majorOwners; - } - - public List getFollowers() { - return followers; - } - - public List getSpecialMeeples() { - return specialMeeples; - } - - @Override - public Iterable getMeeples() { - return Iterables.concat(followers, specialMeeples); - } - - public Map getPowers() { - return power; - } - -} - +package com.jcloisterzone.feature.visitor.score; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Iterables; +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Scoreable; +import com.jcloisterzone.feature.visitor.SelfReturningVisitor; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Special; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.FairyCapability; + +public abstract class AbstractScoreContext extends SelfReturningVisitor implements ScoreContext { + + private final Game game; + + private Scoreable feature; + + int bestPower = 1; //minimal power to score must be 1 (mayor power can be 0) + + private Map power = new HashMap<>(); + private Map sample = new HashMap<>(); + private Position preferedPos = null; + + private List followers = new ArrayList<>(); + private List specialMeeples = new ArrayList<>(); + + public AbstractScoreContext(Game game) { + this.game = game; + if (game.hasCapability(FairyCapability.class)) { + preferedPos = game.getCapability(FairyCapability.class).getFairyPosition(); + } + } + + public Game getGame() { + return game; + } + + @Override + public Scoreable getMasterFeature() { + return feature; + } + + @Override + public boolean visit(Feature feature) { + for (Meeple meeple : feature.getMeeples()) { + if (meeple instanceof Follower) { + Follower follower = (Follower) meeple; + Integer prev = power.get(follower.getPlayer()); + int followerPower = follower.getPower(); + int curr = prev == null ? followerPower : prev + followerPower; + power.put(follower.getPlayer(), curr); + if (curr > bestPower) bestPower = curr; + if (sample.containsKey(follower.getPlayer())) { + if (follower.at(preferedPos)) { + sample.put(follower.getPlayer(), follower); + } + } else { + sample.put(follower.getPlayer(), follower); + } + } + if (meeple instanceof Follower) { + followers.add((Follower) meeple); + } else if (meeple instanceof Special) { + specialMeeples.add((Special) meeple); + } + } + if (this.feature == null || this.feature.getId() > feature.getId()) { + this.feature = (Scoreable) feature; + } + return true; + } + + public Follower getSampleFollower(Player player) { + return sample.get(player); + } + + public Set getMajorOwners() { + Set majorOwners = new HashSet<>(); + for (Player player: power.keySet()) { + int pwr = power.get(player); + if (pwr == bestPower) { + majorOwners.add(player); + } + } + return majorOwners; + } + + public List getFollowers() { + return followers; + } + + public List getSpecialMeeples() { + return specialMeeples; + } + + @Override + public Iterable getMeeples() { + return Iterables.concat(followers, specialMeeples); + } + + public Map getPowers() { + return power; + } + +} + diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/CityScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/CityScoreContext.java index 8bf96e117..b339595e6 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/CityScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/CityScoreContext.java @@ -1,94 +1,94 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.Map; - -import com.jcloisterzone.TradeResource; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; - -public class CityScoreContext extends PositionCollectingScoreContext { - - private Map cityCache; - - private boolean cathedral, besieged; - private int pennants; - private int cityTradeResources[]; - - - public CityScoreContext(Game game) { - super(game); - } - - public Map getCityCache() { - return cityCache; - } - - public void setCityCache(Map cityCache) { - this.cityCache = cityCache; - } - - @Override - public boolean visit(Feature feature) { - City city = (City) feature; - pennants += city.getPennants(); - cathedral = cathedral || city.isCathedral(); - besieged = besieged || city.isBesieged(); - TradeResource tr = city.getTradeResource(); - if (tr != null) { - if (cityTradeResources == null) { - cityTradeResources = new int[TradeResource.values().length]; - } - cityTradeResources[tr.ordinal()]++; - } - if (cityCache != null) { - cityCache.put(city, this); - } - return super.visit(feature); - } - - @Override - public int getPoints() { - return getPoints(isCompleted()); - } - - @Override - public int getPoints(boolean completed) { - int size = getPositions().size(); - if (size <= 2 && getGame().hasRule(CustomRule.TINY_CITY_2_POINTS)) { - //small city can has pennant! (Abbey and Mayor) - return size + pennants; - } - int pointsPerUnit = 2; - if (completed) { - if (cathedral) pointsPerUnit = 3; - } else { - if (cathedral) return 0; - pointsPerUnit = 1; - } - if (besieged) { - pointsPerUnit--; - } - return pointsPerUnit * (size + pennants); - } - - public int[] getCityTradeResources() { - return cityTradeResources; - } - - public boolean isCathedral() { - return cathedral; - } - - public boolean isBesieged() { - return besieged; - } - - public int getPennants() { - return pennants; - } - - - -} +package com.jcloisterzone.feature.visitor.score; + +import java.util.Map; + +import com.jcloisterzone.TradeResource; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; + +public class CityScoreContext extends PositionCollectingScoreContext { + + private Map cityCache; + + private boolean cathedral, besieged; + private int pennants; + private int cityTradeResources[]; + + + public CityScoreContext(Game game) { + super(game); + } + + public Map getCityCache() { + return cityCache; + } + + public void setCityCache(Map cityCache) { + this.cityCache = cityCache; + } + + @Override + public boolean visit(Feature feature) { + City city = (City) feature; + pennants += city.getPennants(); + cathedral = cathedral || city.isCathedral(); + besieged = besieged || city.isBesieged(); + TradeResource tr = city.getTradeResource(); + if (tr != null) { + if (cityTradeResources == null) { + cityTradeResources = new int[TradeResource.values().length]; + } + cityTradeResources[tr.ordinal()]++; + } + if (cityCache != null) { + cityCache.put(city, this); + } + return super.visit(feature); + } + + @Override + public int getPoints() { + return getPoints(isCompleted()); + } + + @Override + public int getPoints(boolean completed) { + int size = getPositions().size(); + if (size <= 2 && getGame().hasRule(CustomRule.TINY_CITY_2_POINTS)) { + //small city can has pennant! (Abbey and Mayor) + return size + pennants; + } + int pointsPerUnit = 2; + if (completed) { + if (cathedral) pointsPerUnit = 3; + } else { + if (cathedral) return 0; + pointsPerUnit = 1; + } + if (besieged) { + pointsPerUnit--; + } + return pointsPerUnit * (size + pennants); + } + + public int[] getCityTradeResources() { + return cityTradeResources; + } + + public boolean isCathedral() { + return cathedral; + } + + public boolean isBesieged() { + return besieged; + } + + public int getPennants() { + return pennants; + } + + + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/CloisterScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/CloisterScoreContext.java index 490223ad1..6cd965e34 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/CloisterScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/CloisterScoreContext.java @@ -1,130 +1,130 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.google.common.primitives.Ints; -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.SelfReturningVisitor; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Special; -import com.jcloisterzone.game.Game; - -public class CloisterScoreContext extends SelfReturningVisitor implements CompletableScoreContext { - - private int neigbouringTiles; - private Cloister cloister; - private Game game; - - public CloisterScoreContext(Game game) { - this.game = game; - } - - @Override - public Cloister getMasterFeature() { - return cloister; - } - - @Override - public int getPoints() { - return neigbouringTiles + 1; - } - - @Override - public Set getPositions() { - return Collections.singleton(cloister.getTile().getPosition()); - } - - @Override - public boolean visit(Feature feature) { - cloister = (Cloister) feature; - Position pos = cloister.getTile().getPosition(); - neigbouringTiles = game.getBoard().getAdjacentAndDiagonalTiles(pos).size(); - return true; - } - - @Override - public Follower getSampleFollower(Player player) { - for (Meeple m : cloister.getMeeples()) { - if (m instanceof Follower && m.getPlayer() == player) return (Follower) m; - } - return null; - } - - @Override - public Set getMajorOwners() { - int size = cloister.getMeeples().size(); - if (size == 0) return Collections.emptySet(); - if (size == 1) return Collections.singleton(cloister.getMeeples().iterator().next().getPlayer()); - - //rare case - more then one follower placed on cloister (possible by Flier expansion) - int[] power = new int[game.getAllPlayers().length]; - for (Meeple m : cloister.getMeeples()) { - if (m instanceof Follower) { - Follower f = (Follower) m; - power[f.getPlayer().getIndex()] += f.getPower(); - } - } - int maxPower = Ints.max(power); - Set owners = new HashSet<>(); - for (int i = 0; i < power.length; i++) { - if (power[i] == maxPower) { - owners.add(game.getAllPlayers()[i]); - } - } - return owners; - } - - public Map getPowers() { - int size = cloister.getMeeples().size(); - if (size == 0) return Collections.emptyMap(); - if (size == 1) { - Follower m = (Follower) cloister.getMeeples().iterator().next(); - return Collections.singletonMap(m.getPlayer(), m.getPower()); - } - //rare cases - Map result = new HashMap(); - for (Meeple m : cloister.getMeeples()) { - Follower follower = (Follower) m; - Integer val = result.get(follower.getPlayer()); - result.put(follower.getPlayer(), val == null ? follower.getPower() : val + follower.getPower()); - } - return result; - - } - - @SuppressWarnings("unchecked") - @Override - public List getFollowers() { - //nowdays only followers can be placed on cloister - List followers = (List)(Object)cloister.getMeeples(); - //copy required - origin is modified during copy iteration - return new ArrayList(followers); - } - - @Override - public List getSpecialMeeples() { - return Collections.emptyList(); - } - - @Override - public Iterable getMeeples() { - //copy required - origin is modified during copy iteration - return new ArrayList(cloister.getMeeples()); - } - - @Override - public boolean isCompleted() { - return neigbouringTiles == 8; - } - -} +package com.jcloisterzone.feature.visitor.score; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.primitives.Ints; +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.SelfReturningVisitor; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Special; +import com.jcloisterzone.game.Game; + +public class CloisterScoreContext extends SelfReturningVisitor implements CompletableScoreContext { + + private int neigbouringTiles; + private Cloister cloister; + private Game game; + + public CloisterScoreContext(Game game) { + this.game = game; + } + + @Override + public Cloister getMasterFeature() { + return cloister; + } + + @Override + public int getPoints() { + return neigbouringTiles + 1; + } + + @Override + public Set getPositions() { + return Collections.singleton(cloister.getTile().getPosition()); + } + + @Override + public boolean visit(Feature feature) { + cloister = (Cloister) feature; + Position pos = cloister.getTile().getPosition(); + neigbouringTiles = game.getBoard().getAdjacentAndDiagonalTiles(pos).size(); + return true; + } + + @Override + public Follower getSampleFollower(Player player) { + for (Meeple m : cloister.getMeeples()) { + if (m instanceof Follower && m.getPlayer() == player) return (Follower) m; + } + return null; + } + + @Override + public Set getMajorOwners() { + int size = cloister.getMeeples().size(); + if (size == 0) return Collections.emptySet(); + if (size == 1) return Collections.singleton(cloister.getMeeples().iterator().next().getPlayer()); + + //rare case - more then one follower placed on cloister (possible by Flier expansion) + int[] power = new int[game.getAllPlayers().length]; + for (Meeple m : cloister.getMeeples()) { + if (m instanceof Follower) { + Follower f = (Follower) m; + power[f.getPlayer().getIndex()] += f.getPower(); + } + } + int maxPower = Ints.max(power); + Set owners = new HashSet<>(); + for (int i = 0; i < power.length; i++) { + if (power[i] == maxPower) { + owners.add(game.getAllPlayers()[i]); + } + } + return owners; + } + + public Map getPowers() { + int size = cloister.getMeeples().size(); + if (size == 0) return Collections.emptyMap(); + if (size == 1) { + Follower m = (Follower) cloister.getMeeples().iterator().next(); + return Collections.singletonMap(m.getPlayer(), m.getPower()); + } + //rare cases + Map result = new HashMap(); + for (Meeple m : cloister.getMeeples()) { + Follower follower = (Follower) m; + Integer val = result.get(follower.getPlayer()); + result.put(follower.getPlayer(), val == null ? follower.getPower() : val + follower.getPower()); + } + return result; + + } + + @SuppressWarnings("unchecked") + @Override + public List getFollowers() { + //nowdays only followers can be placed on cloister + List followers = (List)(Object)cloister.getMeeples(); + //copy required - origin is modified during copy iteration + return new ArrayList(followers); + } + + @Override + public List getSpecialMeeples() { + return Collections.emptyList(); + } + + @Override + public Iterable getMeeples() { + //copy required - origin is modified during copy iteration + return new ArrayList(cloister.getMeeples()); + } + + @Override + public boolean isCompleted() { + return neigbouringTiles == 8; + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/CompletableScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/CompletableScoreContext.java index 153698179..b7edcb27f 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/CompletableScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/CompletableScoreContext.java @@ -1,19 +1,19 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.Set; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.Completable; - - -public interface CompletableScoreContext extends ScoreContext { - - boolean isCompleted(); - Set getPositions(); - - int getPoints(); - - @Override - public Completable getMasterFeature(); - -} +package com.jcloisterzone.feature.visitor.score; + +import java.util.Set; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.Completable; + + +public interface CompletableScoreContext extends ScoreContext { + + boolean isCompleted(); + Set getPositions(); + + int getPoints(); + + @Override + public Completable getMasterFeature(); + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/FarmScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/FarmScoreContext.java index e11db9f17..3c68b89da 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/FarmScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/FarmScoreContext.java @@ -1,145 +1,145 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Pig; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.SiegeCapability; - -public class FarmScoreContext extends AbstractScoreContext { - - private Map adjoiningCompletedCities = new HashMap<>(); - private Set adjoiningCastles = new HashSet<>(); - private Set pigs = new HashSet<>(); - private int pigHerds = 0; - - private Map cityCache; - private Map> scoredCities; - - public FarmScoreContext(Game game) { - super(game); - } - - public Map getCityCache() { - return cityCache; - } - - public void setCityCache(Map cityCache) { - this.cityCache = cityCache; - } - - public Map> getScoredCities() { - return scoredCities; - } - - public void setScoredCities(Map> scoredCities) { - this.scoredCities = scoredCities; - } - - private void addAdjoiningCompletedCities(Feature[] adjoiningCities) { - for (Feature feature : adjoiningCities) { - if (feature instanceof City) { - City c = (City) feature; - CityScoreContext ctx = cityCache.get(c); - if (ctx == null) { - ctx = c.getScoreContext(); - ctx.setCityCache(cityCache); - c.walk(ctx); - } - if (ctx.isCompleted()) { - adjoiningCompletedCities.put((City) ctx.getMasterFeature(), ctx); - } - } else if (feature instanceof Castle) { - adjoiningCastles.add((Castle) feature.getMaster()); - } - - } - } - - - @Override - public boolean visit(Feature feature) { - Farm farm = (Farm) feature; - if (farm.getAdjoiningCities() != null) { - addAdjoiningCompletedCities(farm.getAdjoiningCities()); - } - for (Meeple m : farm.getMeeples()) { - if (m instanceof Pig) { - pigs.add(m.getPlayer()); - } - } - if (farm.isPigHerd()) { - pigHerds += 1; - } - return super.visit(feature); - } - - private int getPointsPerCity(Player player, int basePoints) { - int pointsPerCity = basePoints + pigHerds; - if (pigs.contains(player)) pointsPerCity += 1; - return pointsPerCity; - } - - public int getPointsPerCity(Player player) { - return getPointsPerCity(player, 3); - } - - public int getPoints(Player player) { - return getPlayerPoints(player, getPointsPerCity(player)); - } - - public int getPointsWhenBarnIsConnected(Player player) { - return getPlayerPoints(player, getPointsPerCity(player, 1)); - } - - private int getPlayerPoints(Player player, int pointsPerCity) { - //optimalization - if (scoredCities == null && !getGame().hasCapability(SiegeCapability.class)) { - return pointsPerCity * adjoiningCompletedCities.size() + - (pointsPerCity + 1) * adjoiningCastles.size(); - } - - int points = 0; - for (CityScoreContext ctx : adjoiningCompletedCities.values()) { - if (scoredCities != null) { - if (scoredCities.get(player).contains(ctx.getMasterFeature())) { - continue; - } - scoredCities.get(player).add((City) ctx.getMasterFeature()); - } - points += pointsPerCity; - if (ctx.isBesieged()) { //count city twice - points += pointsPerCity; - } - } - points += (pointsPerCity + 1) * adjoiningCastles.size(); - return points; - } - - public int getBarnPoints() { - if (getGame().hasCapability(SiegeCapability.class)) { - int points = 0; - for (CityScoreContext ctx : adjoiningCompletedCities.values()) { - points += 4; - if (ctx.isBesieged()) { //count city twice - points += 4; - } - } - points += 5 * adjoiningCastles.size(); - return points; - } else { - return adjoiningCompletedCities.size() * 4 + - adjoiningCastles.size() * 5; - } - } - -} +package com.jcloisterzone.feature.visitor.score; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Pig; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.SiegeCapability; + +public class FarmScoreContext extends AbstractScoreContext { + + private Map adjoiningCompletedCities = new HashMap<>(); + private Set adjoiningCastles = new HashSet<>(); + private Set pigs = new HashSet<>(); + private int pigHerds = 0; + + private Map cityCache; + private Map> scoredCities; + + public FarmScoreContext(Game game) { + super(game); + } + + public Map getCityCache() { + return cityCache; + } + + public void setCityCache(Map cityCache) { + this.cityCache = cityCache; + } + + public Map> getScoredCities() { + return scoredCities; + } + + public void setScoredCities(Map> scoredCities) { + this.scoredCities = scoredCities; + } + + private void addAdjoiningCompletedCities(Feature[] adjoiningCities) { + for (Feature feature : adjoiningCities) { + if (feature instanceof City) { + City c = (City) feature; + CityScoreContext ctx = cityCache.get(c); + if (ctx == null) { + ctx = c.getScoreContext(); + ctx.setCityCache(cityCache); + c.walk(ctx); + } + if (ctx.isCompleted()) { + adjoiningCompletedCities.put((City) ctx.getMasterFeature(), ctx); + } + } else if (feature instanceof Castle) { + adjoiningCastles.add((Castle) feature.getMaster()); + } + + } + } + + + @Override + public boolean visit(Feature feature) { + Farm farm = (Farm) feature; + if (farm.getAdjoiningCities() != null) { + addAdjoiningCompletedCities(farm.getAdjoiningCities()); + } + for (Meeple m : farm.getMeeples()) { + if (m instanceof Pig) { + pigs.add(m.getPlayer()); + } + } + if (farm.isPigHerd()) { + pigHerds += 1; + } + return super.visit(feature); + } + + private int getPointsPerCity(Player player, int basePoints) { + int pointsPerCity = basePoints + pigHerds; + if (pigs.contains(player)) pointsPerCity += 1; + return pointsPerCity; + } + + public int getPointsPerCity(Player player) { + return getPointsPerCity(player, 3); + } + + public int getPoints(Player player) { + return getPlayerPoints(player, getPointsPerCity(player)); + } + + public int getPointsWhenBarnIsConnected(Player player) { + return getPlayerPoints(player, getPointsPerCity(player, 1)); + } + + private int getPlayerPoints(Player player, int pointsPerCity) { + //optimalization + if (scoredCities == null && !getGame().hasCapability(SiegeCapability.class)) { + return pointsPerCity * adjoiningCompletedCities.size() + + (pointsPerCity + 1) * adjoiningCastles.size(); + } + + int points = 0; + for (CityScoreContext ctx : adjoiningCompletedCities.values()) { + if (scoredCities != null) { + if (scoredCities.get(player).contains(ctx.getMasterFeature())) { + continue; + } + scoredCities.get(player).add((City) ctx.getMasterFeature()); + } + points += pointsPerCity; + if (ctx.isBesieged()) { //count city twice + points += pointsPerCity; + } + } + points += (pointsPerCity + 1) * adjoiningCastles.size(); + return points; + } + + public int getBarnPoints() { + if (getGame().hasCapability(SiegeCapability.class)) { + int points = 0; + for (CityScoreContext ctx : adjoiningCompletedCities.values()) { + points += 4; + if (ctx.isBesieged()) { //count city twice + points += 4; + } + } + points += 5 * adjoiningCastles.size(); + return points; + } else { + return adjoiningCompletedCities.size() * 4 + + adjoiningCastles.size() * 5; + } + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/PositionCollectingScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/PositionCollectingScoreContext.java index cde7fa853..f43ad38a8 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/PositionCollectingScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/PositionCollectingScoreContext.java @@ -1,47 +1,47 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.HashSet; -import java.util.Set; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.game.Game; - -public abstract class PositionCollectingScoreContext extends AbstractScoreContext implements CompletableScoreContext { - - private Set positions = new HashSet<>(); - private boolean isCompleted = true; - - public PositionCollectingScoreContext(Game game) { - super(game); - } - - public abstract int getPoints(boolean completed); - - public Completable getMasterFeature() { - return (Completable) super.getMasterFeature(); - } - - public int getSize() { - return positions.size(); - } - - public Set getPositions() { - return positions; - } - - public boolean isCompleted() { - return isCompleted; - } - - @Override - public boolean visit(Feature feature) { - positions.add(feature.getTile().getPosition()); - if (((Completable)feature).isOpen()) { - isCompleted = false; - } - return super.visit(feature); - } - -} +package com.jcloisterzone.feature.visitor.score; + +import java.util.HashSet; +import java.util.Set; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.game.Game; + +public abstract class PositionCollectingScoreContext extends AbstractScoreContext implements CompletableScoreContext { + + private Set positions = new HashSet<>(); + private boolean isCompleted = true; + + public PositionCollectingScoreContext(Game game) { + super(game); + } + + public abstract int getPoints(boolean completed); + + public Completable getMasterFeature() { + return (Completable) super.getMasterFeature(); + } + + public int getSize() { + return positions.size(); + } + + public Set getPositions() { + return positions; + } + + public boolean isCompleted() { + return isCompleted; + } + + @Override + public boolean visit(Feature feature) { + positions.add(feature.getTile().getPosition()); + if (((Completable)feature).isOpen()) { + isCompleted = false; + } + return super.visit(feature); + } + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/RoadScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/RoadScoreContext.java index 35f0652b2..d8d8ed905 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/RoadScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/RoadScoreContext.java @@ -1,41 +1,41 @@ -package com.jcloisterzone.feature.visitor.score; - -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.game.Game; - -public class RoadScoreContext extends PositionCollectingScoreContext { - - private boolean isInn; - - public RoadScoreContext(Game game) { - super(game); - } - - @Override - public boolean visit(Feature feature) { - isInn = isInn || ((Road)feature).isInn(); - return super.visit(feature); - } - - @Override - public int getPoints() { - return getPoints(isCompleted()); - } - - @Override - public int getPoints(boolean completed) { - int length = getPositions().size(); - if (isInn) { - return completed ? length * 2 : 0; - } else { - return length; - } - } - - public boolean isInn() { - return isInn; - } - - -} +package com.jcloisterzone.feature.visitor.score; + +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.game.Game; + +public class RoadScoreContext extends PositionCollectingScoreContext { + + private boolean isInn; + + public RoadScoreContext(Game game) { + super(game); + } + + @Override + public boolean visit(Feature feature) { + isInn = isInn || ((Road)feature).isInn(); + return super.visit(feature); + } + + @Override + public int getPoints() { + return getPoints(isCompleted()); + } + + @Override + public int getPoints(boolean completed) { + int length = getPositions().size(); + if (isInn) { + return completed ? length * 2 : 0; + } else { + return length; + } + } + + public boolean isInn() { + return isInn; + } + + +} diff --git a/src/main/java/com/jcloisterzone/feature/visitor/score/ScoreContext.java b/src/main/java/com/jcloisterzone/feature/visitor/score/ScoreContext.java index 4900a6c60..2d4e622a5 100644 --- a/src/main/java/com/jcloisterzone/feature/visitor/score/ScoreContext.java +++ b/src/main/java/com/jcloisterzone/feature/visitor/score/ScoreContext.java @@ -1,29 +1,29 @@ -package com.jcloisterzone.feature.visitor.score; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Scoreable; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.feature.visitor.SelfReturningVisitor; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Special; - -public interface ScoreContext extends FeatureVisitor { - - Scoreable getMasterFeature(); - - Follower getSampleFollower(Player player); - Set getMajorOwners(); - - List getFollowers(); - List getSpecialMeeples(); - Iterable getMeeples(); - Map getPowers(); - - - -} +package com.jcloisterzone.feature.visitor.score; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Scoreable; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.feature.visitor.SelfReturningVisitor; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Special; + +public interface ScoreContext extends FeatureVisitor { + + Scoreable getMasterFeature(); + + Follower getSampleFollower(Player player); + Set getMajorOwners(); + + List getFollowers(); + List getSpecialMeeples(); + Iterable getMeeples(); + Map getPowers(); + + + +} diff --git a/src/main/java/com/jcloisterzone/figure/Barn.java b/src/main/java/com/jcloisterzone/figure/Barn.java index 67bbd5ea6..38baf9c71 100644 --- a/src/main/java/com/jcloisterzone/figure/Barn.java +++ b/src/main/java/com/jcloisterzone/figure/Barn.java @@ -1,70 +1,70 @@ -package com.jcloisterzone.figure; - -import java.util.HashMap; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; - -public class Barn extends Special { - - private static final long serialVersionUID = -1422237898274679967L; - - public Barn(Game game, Player player) { - super(game, player); - } - - @Override - public boolean canBeEatenByDragon() { - return false; - } - - @Override - protected void checkDeployment(Feature feature) { - if (!(feature instanceof Farm)) { - throw new IllegalArgumentException("The barn must be placed only on a farm."); - } - Farm farm = (Farm) feature; - - FarmScoreContext ctx = farm.getScoreContext(); - ctx.setCityCache(new HashMap()); - farm.walk(ctx); - - if (!farm.getTile().getGame().hasRule(CustomRule.MULTI_BARN_ALLOWED)) { - for (Special m : ctx.getSpecialMeeples()) { - if (m instanceof Barn) { - throw new IllegalArgumentException("Another barn is already placed on the farm."); - } - } - } - - //all ok - score non barn meeples - for (Player owner : ctx.getMajorOwners()) { - int points = ctx.getPoints(owner); - game.scoreFeature(points, ctx, owner); - } - for (Meeple m : ctx.getMeeples()) { - m.undeploy(false); - } - - super.checkDeployment(feature); - } - - @Override - public Feature getPieceForDeploy(Tile tile, Location loc) { - Farm farmPiece = (Farm) tile.getFeaturePartOf(loc); - if (farmPiece == null) { - throw new IllegalArgumentException("No such farm"); - } - return farmPiece; - } - - -} +package com.jcloisterzone.figure; + +import java.util.HashMap; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; + +public class Barn extends Special { + + private static final long serialVersionUID = -1422237898274679967L; + + public Barn(Game game, Player player) { + super(game, player); + } + + @Override + public boolean canBeEatenByDragon() { + return false; + } + + @Override + protected void checkDeployment(Feature feature) { + if (!(feature instanceof Farm)) { + throw new IllegalArgumentException("The barn must be placed only on a farm."); + } + Farm farm = (Farm) feature; + + FarmScoreContext ctx = farm.getScoreContext(); + ctx.setCityCache(new HashMap()); + farm.walk(ctx); + + if (!farm.getTile().getGame().hasRule(CustomRule.MULTI_BARN_ALLOWED)) { + for (Special m : ctx.getSpecialMeeples()) { + if (m instanceof Barn) { + throw new IllegalArgumentException("Another barn is already placed on the farm."); + } + } + } + + //all ok - score non barn meeples + for (Player owner : ctx.getMajorOwners()) { + int points = ctx.getPoints(owner); + game.scoreFeature(points, ctx, owner); + } + for (Meeple m : ctx.getMeeples()) { + m.undeploy(false); + } + + super.checkDeployment(feature); + } + + @Override + public Feature getPieceForDeploy(Tile tile, Location loc) { + Farm farmPiece = (Farm) tile.getFeaturePartOf(loc); + if (farmPiece == null) { + throw new IllegalArgumentException("No such farm"); + } + return farmPiece; + } + + +} diff --git a/src/main/java/com/jcloisterzone/figure/BigFollower.java b/src/main/java/com/jcloisterzone/figure/BigFollower.java index 994e939b1..30291d06a 100644 --- a/src/main/java/com/jcloisterzone/figure/BigFollower.java +++ b/src/main/java/com/jcloisterzone/figure/BigFollower.java @@ -1,19 +1,19 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.game.Game; - -public class BigFollower extends Follower { - - private static final long serialVersionUID = -5506815500027084904L; - - public BigFollower(Game game, Player player) { - super(game, player); - } - - @Override - public int getPower() { - return 2; - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.game.Game; + +public class BigFollower extends Follower { + + private static final long serialVersionUID = -5506815500027084904L; + + public BigFollower(Game game, Player player) { + super(game, player); + } + + @Override + public int getPower() { + return 2; + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Builder.java b/src/main/java/com/jcloisterzone/figure/Builder.java index 2e4b82bbe..c0408c4d5 100644 --- a/src/main/java/com/jcloisterzone/figure/Builder.java +++ b/src/main/java/com/jcloisterzone/figure/Builder.java @@ -1,30 +1,30 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.visitor.IsOccupied; -import com.jcloisterzone.game.Game; - -public class Builder extends Special { - - private static final long serialVersionUID = 1189566966196473830L; - - public Builder(Game game, Player player) { - super(game, player); - } - - @Override - protected void checkDeployment(Feature f) { - if (!(f instanceof City || f instanceof Road) ) { - throw new IllegalArgumentException("Builder must be placed in city or on road only."); - } - if (!f.walk(new IsOccupied().with(Follower.class))) { - throw new IllegalArgumentException("Feature is not occupied by follower."); - } - super.checkDeployment(f); - - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.visitor.IsOccupied; +import com.jcloisterzone.game.Game; + +public class Builder extends Special { + + private static final long serialVersionUID = 1189566966196473830L; + + public Builder(Game game, Player player) { + super(game, player); + } + + @Override + protected void checkDeployment(Feature f) { + if (!(f instanceof City || f instanceof Road) ) { + throw new IllegalArgumentException("Builder must be placed in city or on road only."); + } + if (!f.walk(new IsOccupied().with(Follower.class))) { + throw new IllegalArgumentException("Feature is not occupied by follower."); + } + super.checkDeployment(f); + + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Figure.java b/src/main/java/com/jcloisterzone/figure/Figure.java index c31f39b62..5a4e761fb 100644 --- a/src/main/java/com/jcloisterzone/figure/Figure.java +++ b/src/main/java/com/jcloisterzone/figure/Figure.java @@ -1,64 +1,64 @@ -package com.jcloisterzone.figure; - -import java.io.Serializable; - -import com.google.common.base.Objects; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.game.Game; - -public abstract class Figure implements Serializable, Cloneable { - - private static final long serialVersionUID = 3264248810294656662L; - - protected final Game game; - private Position position; - - public Figure(Game game) { - assert game != null; - this.game = game; - } - - public Position getPosition() { - return position; - } - - public void setPosition(Position position) { - this.position = position; - } - - public boolean at(Position p) { - if (position == null) return false; - return position.equals(p); - } - - @Override - public String toString() { - if (position == null) { - return getClass().getSimpleName(); - } else { - return getClass().getSimpleName() + position.toString(); - } - } - - @Override - public int hashCode() { - return getClass().hashCode() + (position == null ? 1 : position.hashCode()); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Figure)) return false; - return Objects.equal(position, ((Figure) obj).position); - } - - @Override - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - throw new IllegalStateException(e); - } - } - -} +package com.jcloisterzone.figure; + +import java.io.Serializable; + +import com.google.common.base.Objects; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.game.Game; + +public abstract class Figure implements Serializable, Cloneable { + + private static final long serialVersionUID = 3264248810294656662L; + + protected final Game game; + private Position position; + + public Figure(Game game) { + assert game != null; + this.game = game; + } + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + + public boolean at(Position p) { + if (position == null) return false; + return position.equals(p); + } + + @Override + public String toString() { + if (position == null) { + return getClass().getSimpleName(); + } else { + return getClass().getSimpleName() + position.toString(); + } + } + + @Override + public int hashCode() { + return getClass().hashCode() + (position == null ? 1 : position.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Figure)) return false; + return Objects.equal(position, ((Figure) obj).position); + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new IllegalStateException(e); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Follower.java b/src/main/java/com/jcloisterzone/figure/Follower.java index 9aa3e6d9f..1427f4471 100644 --- a/src/main/java/com/jcloisterzone/figure/Follower.java +++ b/src/main/java/com/jcloisterzone/figure/Follower.java @@ -1,59 +1,59 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.visitor.IsOccupied; -import com.jcloisterzone.feature.visitor.RemoveLonelyBuilderAndPig; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.BuilderCapability; -import com.jcloisterzone.game.capability.PigCapability; - -public abstract class Follower extends Meeple { - - private static final long serialVersionUID = -659337195197201811L; - - public Follower(Game game, Player player) { - super(game, player); - } - - public int getPower() { - return 1; - } - - @Override - public boolean canBeEatenByDragon() { - return !(getFeature() instanceof Castle); - } - - @Override - protected void checkDeployment(Feature f) { - if (f.walk(new IsOccupied())) { - throw new IllegalArgumentException("Feature is occupied."); - } - super.checkDeployment(f); - } - - - //TODO ??? can be this in score visitor instead of here ??? - public void undeploy(boolean checkForLonelyBuilderOrPig) { - //store ref which is lost be super call - Feature piece = getFeature(); - super.undeploy(checkForLonelyBuilderOrPig); //clear piece - if (checkForLonelyBuilderOrPig) { - boolean builder = game.hasCapability(BuilderCapability.class) && (piece instanceof City || piece instanceof Road); - boolean pig = game.hasCapability(PigCapability.class) && piece instanceof Farm; - if (builder || pig) { - Special toRemove = piece.walk(new RemoveLonelyBuilderAndPig(getPlayer())); - if (toRemove != null) { - toRemove.undeploy(false); - } - } - } - } - - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.visitor.IsOccupied; +import com.jcloisterzone.feature.visitor.RemoveLonelyBuilderAndPig; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.BuilderCapability; +import com.jcloisterzone.game.capability.PigCapability; + +public abstract class Follower extends Meeple { + + private static final long serialVersionUID = -659337195197201811L; + + public Follower(Game game, Player player) { + super(game, player); + } + + public int getPower() { + return 1; + } + + @Override + public boolean canBeEatenByDragon() { + return !(getFeature() instanceof Castle); + } + + @Override + protected void checkDeployment(Feature f) { + if (f.walk(new IsOccupied())) { + throw new IllegalArgumentException("Feature is occupied."); + } + super.checkDeployment(f); + } + + + //TODO ??? can be this in score visitor instead of here ??? + public void undeploy(boolean checkForLonelyBuilderOrPig) { + //store ref which is lost be super call + Feature piece = getFeature(); + super.undeploy(checkForLonelyBuilderOrPig); //clear piece + if (checkForLonelyBuilderOrPig) { + boolean builder = game.hasCapability(BuilderCapability.class) && (piece instanceof City || piece instanceof Road); + boolean pig = game.hasCapability(PigCapability.class) && piece instanceof Farm; + if (builder || pig) { + Special toRemove = piece.walk(new RemoveLonelyBuilderAndPig(getPlayer())); + if (toRemove != null) { + toRemove.undeploy(false); + } + } + } + } + + +} diff --git a/src/main/java/com/jcloisterzone/figure/Mayor.java b/src/main/java/com/jcloisterzone/figure/Mayor.java index 029ef263f..0dd7ac8f8 100644 --- a/src/main/java/com/jcloisterzone/figure/Mayor.java +++ b/src/main/java/com/jcloisterzone/figure/Mayor.java @@ -1,47 +1,47 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.game.Game; - -public class Mayor extends Follower { - - private static final long serialVersionUID = -7602411772187519451L; - - public Mayor(Game game, Player player) { - super(game, player); - } - - static class PennatsCountingVisitor implements FeatureVisitor { - int pennats = 0; - - @Override - public boolean visit(Feature feature) { - City c = (City) feature; - pennats += c.getPennants(); - return true; - } - - @Override - public Integer getResult() { - return pennats; - } - } - - @Override - public int getPower() { - //TODO not effective - city is walked twice during scoring - return getFeature().walk(new PennatsCountingVisitor()); - } - - @Override - protected void checkDeployment(Feature f) { - if (!(f instanceof City)) { - throw new IllegalArgumentException("Mayor must be placed in city only."); - } - super.checkDeployment(f); - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.game.Game; + +public class Mayor extends Follower { + + private static final long serialVersionUID = -7602411772187519451L; + + public Mayor(Game game, Player player) { + super(game, player); + } + + static class PennatsCountingVisitor implements FeatureVisitor { + int pennats = 0; + + @Override + public boolean visit(Feature feature) { + City c = (City) feature; + pennats += c.getPennants(); + return true; + } + + @Override + public Integer getResult() { + return pennats; + } + } + + @Override + public int getPower() { + //TODO not effective - city is walked twice during scoring + return getFeature().walk(new PennatsCountingVisitor()); + } + + @Override + protected void checkDeployment(Feature f) { + if (!(f instanceof City)) { + throw new IllegalArgumentException("Mayor must be placed in city only."); + } + super.checkDeployment(f); + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Meeple.java b/src/main/java/com/jcloisterzone/figure/Meeple.java index 82b12a40e..cce2cc643 100644 --- a/src/main/java/com/jcloisterzone/figure/Meeple.java +++ b/src/main/java/com/jcloisterzone/figure/Meeple.java @@ -1,152 +1,152 @@ -package com.jcloisterzone.figure; - -import java.util.List; -import java.util.Map.Entry; - -import com.google.common.base.Objects; -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.TowerCapability; - -public abstract class Meeple extends Figure { - - private static final long serialVersionUID = 251811435063355665L; - - private transient final Player player; - private transient Feature feature; - private transient Integer index; //index distinguish meeples on same feature - private Location location; - - public Meeple(Game game, Player player) { - super(game); - this.player = player; - } - - public boolean canBeEatenByDragon() { - return true; - } - - /** true if meeple is deploayed on board */ - public boolean isDeployed() { - return location != null && location != Location.PRISON ; - } - - public boolean isInSupply() { - return location == null; - } - - public void clearDeployment() { - setPosition(null); - setLocation(null); - setFeature(null); - } - - protected void checkDeployment(Feature piece) { - //empty - } - - public Feature getPieceForDeploy(Tile tile, Location loc) { - Feature piece = tile.getFeature(loc); - if (piece == null) { - throw new IllegalArgumentException("No such feature"); - } - return piece; - } - - public void deploy(Tile tile, Location loc) { - Feature feature = getPieceForDeploy(tile, loc); - checkDeployment(feature); - deployUnchecked(tile, loc, feature); - game.fireGameEvent().deployed(this); - } - - public void deployUnchecked(Tile tile, Location loc, Feature feature) { - assert location == null; - feature.addMeeple(this); - setPosition(tile.getPosition()); - setLocation(loc); - setFeature(feature); - } - - public final void undeploy() { - undeploy(true); - } - - public void undeploy(boolean checkForLonelyBuilderOrPig) { - assert location != null && location != Location.PRISON; - game.fireGameEvent().undeployed(this); - feature.removeMeeple(this); - clearDeployment(); - } - - - public Feature getFeature() { - return feature; - } - - public void setFeature(Feature piece) { - this.feature = piece; - } - - public Player getPlayer() { - return player; - } - - public Location getLocation() { - return location; - } - - public void setLocation(Location location) { - // DBG TO DEL -// if (location != Location.PRISON) { -// TowerCapability tc = game.getCapability(TowerCapability.class); -// for (List l : tc.getPrisoners().values()) { -// for (Follower f : l) { -// if (f == this) { -// System.err.print("IN PRISON"); -// } -// } -// } -// } - - this.location = location; - } - - public Integer getIndex() { - return index; - } - - public void setIndex(Integer index) { - this.index = index; - } - - @Override - public int hashCode() { - return java.util.Objects.hash(index, location); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (!(obj instanceof Meeple)) return false; - if (!super.equals(obj)) return false; - Meeple o = (Meeple) obj; - if (!Objects.equal(index, o.index)) return false; - if (!Objects.equal(location, o.location)) return false; - //do not compare feature - location is enough - feature is changing during time - return true; - } - - @Override - public String toString() { - if (location == Location.PRISON) { - return getClass().getSimpleName() + " " + location.toString(); - } else { - return super.toString(); - } - } - -} +package com.jcloisterzone.figure; + +import java.util.List; +import java.util.Map.Entry; + +import com.google.common.base.Objects; +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.TowerCapability; + +public abstract class Meeple extends Figure { + + private static final long serialVersionUID = 251811435063355665L; + + private transient final Player player; + private transient Feature feature; + private transient Integer index; //index distinguish meeples on same feature + private Location location; + + public Meeple(Game game, Player player) { + super(game); + this.player = player; + } + + public boolean canBeEatenByDragon() { + return true; + } + + /** true if meeple is deploayed on board */ + public boolean isDeployed() { + return location != null && location != Location.PRISON ; + } + + public boolean isInSupply() { + return location == null; + } + + public void clearDeployment() { + setPosition(null); + setLocation(null); + setFeature(null); + } + + protected void checkDeployment(Feature piece) { + //empty + } + + public Feature getPieceForDeploy(Tile tile, Location loc) { + Feature piece = tile.getFeature(loc); + if (piece == null) { + throw new IllegalArgumentException("No such feature"); + } + return piece; + } + + public void deploy(Tile tile, Location loc) { + Feature feature = getPieceForDeploy(tile, loc); + checkDeployment(feature); + deployUnchecked(tile, loc, feature); + game.fireGameEvent().deployed(this); + } + + public void deployUnchecked(Tile tile, Location loc, Feature feature) { + assert location == null; + feature.addMeeple(this); + setPosition(tile.getPosition()); + setLocation(loc); + setFeature(feature); + } + + public final void undeploy() { + undeploy(true); + } + + public void undeploy(boolean checkForLonelyBuilderOrPig) { + assert location != null && location != Location.PRISON; + game.fireGameEvent().undeployed(this); + feature.removeMeeple(this); + clearDeployment(); + } + + + public Feature getFeature() { + return feature; + } + + public void setFeature(Feature piece) { + this.feature = piece; + } + + public Player getPlayer() { + return player; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + // DBG TO DEL +// if (location != Location.PRISON) { +// TowerCapability tc = game.getCapability(TowerCapability.class); +// for (List l : tc.getPrisoners().values()) { +// for (Follower f : l) { +// if (f == this) { +// System.err.print("IN PRISON"); +// } +// } +// } +// } + + this.location = location; + } + + public Integer getIndex() { + return index; + } + + public void setIndex(Integer index) { + this.index = index; + } + + @Override + public int hashCode() { + return java.util.Objects.hash(index, location); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (!(obj instanceof Meeple)) return false; + if (!super.equals(obj)) return false; + Meeple o = (Meeple) obj; + if (!Objects.equal(index, o.index)) return false; + if (!Objects.equal(location, o.location)) return false; + //do not compare feature - location is enough - feature is changing during time + return true; + } + + @Override + public String toString() { + if (location == Location.PRISON) { + return getClass().getSimpleName() + " " + location.toString(); + } else { + return super.toString(); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Phantom.java b/src/main/java/com/jcloisterzone/figure/Phantom.java index 416809097..76745607d 100644 --- a/src/main/java/com/jcloisterzone/figure/Phantom.java +++ b/src/main/java/com/jcloisterzone/figure/Phantom.java @@ -1,12 +1,12 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.game.Game; - -public class Phantom extends SmallFollower { - - public Phantom(Game game, Player player) { - super(game, player); - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.game.Game; + +public class Phantom extends SmallFollower { + + public Phantom(Game game, Player player) { + super(game, player); + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Pig.java b/src/main/java/com/jcloisterzone/figure/Pig.java index ceb2a548f..0ecd6e606 100644 --- a/src/main/java/com/jcloisterzone/figure/Pig.java +++ b/src/main/java/com/jcloisterzone/figure/Pig.java @@ -1,27 +1,27 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.IsOccupied; -import com.jcloisterzone.game.Game; - -public class Pig extends Special { - - private static final long serialVersionUID = -6315956811639409025L; - - public Pig(Game game, Player player) { - super(game, player); - } - - @Override - protected void checkDeployment(Feature farm) { - if (!(farm instanceof Farm)) { - throw new IllegalArgumentException("Pig must be placed on a farm only."); - } - if (!farm.walk(new IsOccupied().with(Follower.class))) { - throw new IllegalArgumentException("Feature is not occupied by follower."); - } - super.checkDeployment(farm); - } -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.IsOccupied; +import com.jcloisterzone.game.Game; + +public class Pig extends Special { + + private static final long serialVersionUID = -6315956811639409025L; + + public Pig(Game game, Player player) { + super(game, player); + } + + @Override + protected void checkDeployment(Feature farm) { + if (!(farm instanceof Farm)) { + throw new IllegalArgumentException("Pig must be placed on a farm only."); + } + if (!farm.walk(new IsOccupied().with(Follower.class))) { + throw new IllegalArgumentException("Feature is not occupied by follower."); + } + super.checkDeployment(farm); + } +} diff --git a/src/main/java/com/jcloisterzone/figure/SmallFollower.java b/src/main/java/com/jcloisterzone/figure/SmallFollower.java index ad6f3055c..3f57c509a 100644 --- a/src/main/java/com/jcloisterzone/figure/SmallFollower.java +++ b/src/main/java/com/jcloisterzone/figure/SmallFollower.java @@ -1,16 +1,16 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.game.Game; - -public class SmallFollower extends Follower { - - private static final long serialVersionUID = 9167040308990588349L; - - public static final int QUANTITY = 7; - - public SmallFollower(Game game, Player player) { - super(game, player); - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.game.Game; + +public class SmallFollower extends Follower { + + private static final long serialVersionUID = 9167040308990588349L; + + public static final int QUANTITY = 7; + + public SmallFollower(Game game, Player player) { + super(game, player); + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Special.java b/src/main/java/com/jcloisterzone/figure/Special.java index dfa20ae90..54b638218 100644 --- a/src/main/java/com/jcloisterzone/figure/Special.java +++ b/src/main/java/com/jcloisterzone/figure/Special.java @@ -1,12 +1,12 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.game.Game; - -public abstract class Special extends Meeple { - - public Special(Game game, Player player) { - super(game, player); - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.game.Game; + +public abstract class Special extends Meeple { + + public Special(Game game, Player player) { + super(game, player); + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/Wagon.java b/src/main/java/com/jcloisterzone/figure/Wagon.java index 9527e757c..8123f8b12 100644 --- a/src/main/java/com/jcloisterzone/figure/Wagon.java +++ b/src/main/java/com/jcloisterzone/figure/Wagon.java @@ -1,28 +1,28 @@ -package com.jcloisterzone.figure; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.game.Game; - -public class Wagon extends Follower { - - private static final long serialVersionUID = 2585914429763599776L; - - public Wagon(Game game, Player player) { - super(game, player); - } - - @Override - protected void checkDeployment(Feature f) { - if (f instanceof Tower) { - throw new IllegalArgumentException("Cannot place wagon on the tower."); - } - if (f instanceof Farm) { - throw new IllegalArgumentException("Cannot place wagon on the farm."); - } - super.checkDeployment(f); - } - -} +package com.jcloisterzone.figure; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.game.Game; + +public class Wagon extends Follower { + + private static final long serialVersionUID = 2585914429763599776L; + + public Wagon(Game game, Player player) { + super(game, player); + } + + @Override + protected void checkDeployment(Feature f) { + if (f instanceof Tower) { + throw new IllegalArgumentException("Cannot place wagon on the tower."); + } + if (f instanceof Farm) { + throw new IllegalArgumentException("Cannot place wagon on the farm."); + } + super.checkDeployment(f); + } + +} diff --git a/src/main/java/com/jcloisterzone/figure/predicate/MeeplePredicates.java b/src/main/java/com/jcloisterzone/figure/predicate/MeeplePredicates.java index afa51fa6c..abd96992b 100644 --- a/src/main/java/com/jcloisterzone/figure/predicate/MeeplePredicates.java +++ b/src/main/java/com/jcloisterzone/figure/predicate/MeeplePredicates.java @@ -1,65 +1,65 @@ -package com.jcloisterzone.figure.predicate; - -import com.google.common.base.Predicate; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Meeple; - -public final class MeeplePredicates { - - private static final Predicate DEPLOYED = new Predicate() { - @Override - public boolean apply(Meeple m) { - return m.isDeployed(); - } - }; - private static final Predicate IN_SUPPLY = new Predicate() { - @Override - public boolean apply(Meeple m) { - return m.isInSupply(); - } - }; - - public static Predicate deployed() { - return DEPLOYED; - } - - public static Predicate inSupply() { - return IN_SUPPLY; - } - - public static Predicate at(final Position p) { - return new Predicate() { - @Override - public boolean apply(Meeple m) { - return m.at(p); - } - }; - } - - public static Predicate type(final Class clazz) { - return new Predicate() { - @Override - public boolean apply(Meeple m) { - return clazz.equals(m.getClass()); - } - }; - } - - public static Predicate type(final Class clazz1, final Class clazz2) { - return new Predicate() { - @Override - public boolean apply(Meeple m) { - return clazz1.equals(m.getClass()) || clazz2.equals(m.getClass()); - } - }; - } - - public static Predicate instanceOf(final Class clazz1, final Class clazz2) { - return new Predicate() { - @Override - public boolean apply(Meeple m) { - return clazz1.isInstance(m) || clazz2.isInstance(m); - } - }; - } -} +package com.jcloisterzone.figure.predicate; + +import com.google.common.base.Predicate; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Meeple; + +public final class MeeplePredicates { + + private static final Predicate DEPLOYED = new Predicate() { + @Override + public boolean apply(Meeple m) { + return m.isDeployed(); + } + }; + private static final Predicate IN_SUPPLY = new Predicate() { + @Override + public boolean apply(Meeple m) { + return m.isInSupply(); + } + }; + + public static Predicate deployed() { + return DEPLOYED; + } + + public static Predicate inSupply() { + return IN_SUPPLY; + } + + public static Predicate at(final Position p) { + return new Predicate() { + @Override + public boolean apply(Meeple m) { + return m.at(p); + } + }; + } + + public static Predicate type(final Class clazz) { + return new Predicate() { + @Override + public boolean apply(Meeple m) { + return clazz.equals(m.getClass()); + } + }; + } + + public static Predicate type(final Class clazz1, final Class clazz2) { + return new Predicate() { + @Override + public boolean apply(Meeple m) { + return clazz1.equals(m.getClass()) || clazz2.equals(m.getClass()); + } + }; + } + + public static Predicate instanceOf(final Class clazz1, final Class clazz2) { + return new Predicate() { + @Override + public boolean apply(Meeple m) { + return clazz1.isInstance(m) || clazz2.isInstance(m); + } + }; + } +} diff --git a/src/main/java/com/jcloisterzone/game/AdditionalInfo.java b/src/main/java/com/jcloisterzone/game/AdditionalInfo.java index aa83902ce..784abfe3e 100644 --- a/src/main/java/com/jcloisterzone/game/AdditionalInfo.java +++ b/src/main/java/com/jcloisterzone/game/AdditionalInfo.java @@ -1,49 +1,49 @@ -package com.jcloisterzone.game; - -import java.io.Serializable; - -/** - * Useful information for client about game - * - */ -@Deprecated -public class AdditionalInfo implements Serializable { - - private static final long serialVersionUID = 5454689251221437899L; - - protected int completedCities, biggestCitySize; - protected int completedRoads, longestRoadLength; - - public int getCompletedCities() { - return completedCities; - } - - public int getBiggestCitySize() { - return biggestCitySize; - } - - public int getCompletedRoads() { - return completedRoads; - } - - public int getLongestRoadLength() { - return longestRoadLength; - } - - public void setCompletedCities(int completedCities) { - this.completedCities = completedCities; - } - - public void setBiggestCitySize(int biggestCitySize) { - this.biggestCitySize = biggestCitySize; - } - - public void setCompletedRoads(int completedRoads) { - this.completedRoads = completedRoads; - } - - public void setLongestRoadLength(int longestRoadLength) { - this.longestRoadLength = longestRoadLength; - } - -} +package com.jcloisterzone.game; + +import java.io.Serializable; + +/** + * Useful information for client about game + * + */ +@Deprecated +public class AdditionalInfo implements Serializable { + + private static final long serialVersionUID = 5454689251221437899L; + + protected int completedCities, biggestCitySize; + protected int completedRoads, longestRoadLength; + + public int getCompletedCities() { + return completedCities; + } + + public int getBiggestCitySize() { + return biggestCitySize; + } + + public int getCompletedRoads() { + return completedRoads; + } + + public int getLongestRoadLength() { + return longestRoadLength; + } + + public void setCompletedCities(int completedCities) { + this.completedCities = completedCities; + } + + public void setBiggestCitySize(int biggestCitySize) { + this.biggestCitySize = biggestCitySize; + } + + public void setCompletedRoads(int completedRoads) { + this.completedRoads = completedRoads; + } + + public void setLongestRoadLength(int longestRoadLength) { + this.longestRoadLength = longestRoadLength; + } + +} diff --git a/src/main/java/com/jcloisterzone/game/Capability.java b/src/main/java/com/jcloisterzone/game/Capability.java index e53446791..65f649055 100644 --- a/src/main/java/com/jcloisterzone/game/Capability.java +++ b/src/main/java/com/jcloisterzone/game/Capability.java @@ -1,106 +1,106 @@ -package com.jcloisterzone.game; - -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Board; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.event.GameEventAdapter; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Meeple; - - -public abstract class Capability extends GameEventAdapter { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - protected final Game game; - - public Capability(Game game) { - this.game = game; - } - - public Object backup() { - return null; - } - public void restore(Object data) { - //unpack data created by backup and fill itself - } - - protected TilePack getTilePack() { - return game.getTilePack(); - } - protected Board getBoard() { - return game.getBoard(); - } - protected Tile getTile() { - return game.getCurrentTile(); - } - - public void saveToSnapshot(Document doc, Element node) { - } - - public void saveTileToSnapshot(Tile tile, Document doc, Element tileNode) { - } - - public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { - } - - public void loadTileFromSnapshot(Tile tile, Element tileNode) { - } - - public void initTile(Tile tile, Element xml) { - } - - public void initFeature(Tile tile, Feature feature, Element xml) { - } - - public String getTileGroup(Tile tile) { - return null; - } - - public void initPlayer(Player player) { - } - - public void begin() { - } - - public void prepareActions(List actions, LocationsMap followerLocMap) { - } - - public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { - } - - public boolean isDeployAllowed(Tile tile, Class meepleType) { - return true; - } - - public void scoreCompleted(CompletableScoreContext ctx) { - } - - public void turnCleanUp() { - } - - public void finalScoring() { - } - - public boolean isTilePlacementAllowed(Tile tile, Position p) { - return true; - } - - @Override - public String toString() { - return getClass().getSimpleName().replace("Capability", ""); - } - -} +package com.jcloisterzone.game; + +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Board; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.event.GameEventAdapter; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Meeple; + + +public abstract class Capability extends GameEventAdapter { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + protected final Game game; + + public Capability(Game game) { + this.game = game; + } + + public Object backup() { + return null; + } + public void restore(Object data) { + //unpack data created by backup and fill itself + } + + protected TilePack getTilePack() { + return game.getTilePack(); + } + protected Board getBoard() { + return game.getBoard(); + } + protected Tile getTile() { + return game.getCurrentTile(); + } + + public void saveToSnapshot(Document doc, Element node) { + } + + public void saveTileToSnapshot(Tile tile, Document doc, Element tileNode) { + } + + public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { + } + + public void loadTileFromSnapshot(Tile tile, Element tileNode) { + } + + public void initTile(Tile tile, Element xml) { + } + + public void initFeature(Tile tile, Feature feature, Element xml) { + } + + public String getTileGroup(Tile tile) { + return null; + } + + public void initPlayer(Player player) { + } + + public void begin() { + } + + public void prepareActions(List actions, LocationsMap followerLocMap) { + } + + public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { + } + + public boolean isDeployAllowed(Tile tile, Class meepleType) { + return true; + } + + public void scoreCompleted(CompletableScoreContext ctx) { + } + + public void turnCleanUp() { + } + + public void finalScoring() { + } + + public boolean isTilePlacementAllowed(Tile tile, Position p) { + return true; + } + + @Override + public String toString() { + return getClass().getSimpleName().replace("Capability", ""); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/CustomRule.java b/src/main/java/com/jcloisterzone/game/CustomRule.java index bf4a473c2..1178f3bb7 100644 --- a/src/main/java/com/jcloisterzone/game/CustomRule.java +++ b/src/main/java/com/jcloisterzone/game/CustomRule.java @@ -1,46 +1,46 @@ -package com.jcloisterzone.game; - -import static com.jcloisterzone.ui.I18nUtils._; - -import com.jcloisterzone.Expansion; - - - -public enum CustomRule { - TINY_CITY_2_POINTS(Expansion.BASIC, _("Tiny city is scored only for 2 points.")), - FARM_CITY_SCORED_ONCE(Expansion.BASIC, _("Each city is scored with one farm only.")), //each city can be scored only once - - CANNOT_PLACE_BUILDER_ON_VOLCANO(Expansion.PRINCESS_AND_DRAGON, _("The Builder and the pig cannot be placed on a volcano.")), - PRINCESS_MUST_REMOVE_KNIGHT(Expansion.PRINCESS_AND_DRAGON, _("Princess MUST remove a knight from city.")), - //DRAGON_MOVE_AFTER_SCORING(Expansion.PRINCESS_AND_DRAGON, _("Dragon movement after scoring.")), - - PIG_HERD_ON_GQ_FARM(Expansion.GQ11, _("The Pig herd is present on the farm tile.")), - - MULTI_BARN_ALLOWED(Expansion.ABBEY_AND_MAYOR, _("Allow direct barn placement on a farm where another barn is already placed.")), - - TUNNELIZE_ALL_EXPANSIONS(Expansion.TUNNEL, _("Apply tunnel rule on tunnel from other expansions.")), - - BAZAAR_NO_AUCTION(Expansion.BRIDGES_CASTLES_AND_BAZAARS, _("No bidding on bazaar tile. Each players just choose one tile.")); - - String label; - Expansion expansion; - - private CustomRule(Expansion expansion, String label) { - this.expansion = expansion; - this.label = label; - } - - public String getLabel() { - return label; - } - - public Expansion getExpansion() { - return expansion; - } - - @Override - public String toString() { - return label; - } - +package com.jcloisterzone.game; + +import static com.jcloisterzone.ui.I18nUtils._; + +import com.jcloisterzone.Expansion; + + + +public enum CustomRule { + TINY_CITY_2_POINTS(Expansion.BASIC, _("Tiny city is scored only for 2 points.")), + FARM_CITY_SCORED_ONCE(Expansion.BASIC, _("Each city is scored with one farm only.")), //each city can be scored only once + + CANNOT_PLACE_BUILDER_ON_VOLCANO(Expansion.PRINCESS_AND_DRAGON, _("The Builder and the pig cannot be placed on a volcano.")), + PRINCESS_MUST_REMOVE_KNIGHT(Expansion.PRINCESS_AND_DRAGON, _("Princess MUST remove a knight from city.")), + //DRAGON_MOVE_AFTER_SCORING(Expansion.PRINCESS_AND_DRAGON, _("Dragon movement after scoring.")), + + PIG_HERD_ON_GQ_FARM(Expansion.GQ11, _("The Pig herd is present on the farm tile.")), + + MULTI_BARN_ALLOWED(Expansion.ABBEY_AND_MAYOR, _("Allow direct barn placement on a farm where another barn is already placed.")), + + TUNNELIZE_ALL_EXPANSIONS(Expansion.TUNNEL, _("Apply tunnel rule on tunnel from other expansions.")), + + BAZAAR_NO_AUCTION(Expansion.BRIDGES_CASTLES_AND_BAZAARS, _("No bidding on bazaar tile. Each players just choose one tile.")); + + String label; + Expansion expansion; + + private CustomRule(Expansion expansion, String label) { + this.expansion = expansion; + this.label = label; + } + + public String getLabel() { + return label; + } + + public Expansion getExpansion() { + return expansion; + } + + @Override + public String toString() { + return label; + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/game/Game.java b/src/main/java/com/jcloisterzone/game/Game.java index e0c6d84f6..1d20c45ec 100644 --- a/src/main/java/com/jcloisterzone/game/Game.java +++ b/src/main/java/com/jcloisterzone/game/Game.java @@ -1,387 +1,387 @@ -package com.jcloisterzone.game; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import org.ini4j.Ini; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.google.common.collect.ClassToInstanceMap; -import com.google.common.collect.Iterables; -import com.google.common.collect.MutableClassToInstanceMap; -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Board; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.event.EventMulticaster; -import com.jcloisterzone.event.GameEventAdapter; -import com.jcloisterzone.event.GameEventListener; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.ScoreContext; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.capability.FairyCapability; -import com.jcloisterzone.game.capability.PrincessCapability; -import com.jcloisterzone.game.phase.GameOverPhase; -import com.jcloisterzone.game.phase.Phase; - - -/** - * Other information than board needs in game. Contains players with their - * points, followers ... and game rules of current game. - */ -public class Game extends GameSettings { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - private Ini config; - - /** pack of remaining tiles */ - private TilePack tilePack; - /** pack of remaining tiles */ - private Tile currentTile; - /** game board, contains placed tiles */ - private Board board; - - /** list of players in game */ - private Player[] plist; - /** rules of current game */ - - /** player in turn */ - private Player turnPlayer; - - private final ClassToInstanceMap phases = MutableClassToInstanceMap.create(); - private Phase phase; - - private GameEventListener eventListener = new GameEventAdapter(); - private UserInterface userInterface; - - private List capabilities = new ArrayList<>(); - private FairyCapability fairyCapability; //shortcut - - private int idSequenceCurrVal = 0; - - - public Ini getConfig() { - return config; - } - - public void setConfig(Ini config) { - this.config = config; - } - - public Tile getCurrentTile() { - return currentTile; - } - - public void setCurrentTile(Tile currentTile) { - this.currentTile = currentTile; - } - - public Phase getPhase() { - return phase; - } - - public void setPhase(Phase phase) { - phase.setEntered(false); - this.phase = phase; - } - - public ClassToInstanceMap getPhases() { - return phases; - } - - public GameEventListener fireGameEvent() { - return eventListener; - } - public void addGameListener(GameEventListener listener) { - eventListener = (GameEventListener) EventMulticaster.addListener(eventListener, listener); - } - public void removeGameListener(GameEventListener listener) { - eventListener = (GameEventListener) EventMulticaster.removeListener(eventListener, listener); - } - public UserInterface getUserInterface() { - return userInterface; - } - public void addUserInterface(UserInterface ui) { - userInterface = (UserInterface) EventMulticaster.addListener(userInterface, ui); - } - - public Iterable getDeployedMeeples() { - Iterable iter = Collections.emptyList(); - for (Player player : plist) { - iter = Iterables.concat(iter, player.getFollowers(), player.getSpecialMeeples()); - } - return Iterables.filter(iter, MeeplePredicates.deployed()); - } - - public Player getTurnPlayer() { - return turnPlayer; - } - - public void setTurnPlayer(Player turnPlayer) { - this.turnPlayer = turnPlayer; - fireGameEvent().playerActivated(turnPlayer, turnPlayer); - } - - /** - * Returns player who is allowed to make next action. - * @return - */ - public Player getActivePlayer() { - Phase phase = getPhase(); - return phase == null ? null : phase.getActivePlayer(); - } - - - /** - * Ends turn of current active player and make active the next. - */ - public Player getNextPlayer() { - return getNextPlayer(turnPlayer); - } - - public Player getNextPlayer(Player p) { - int playerIndex = p.getIndex(); - int nextPlayerIndex = playerIndex == (plist.length - 1) ? 0 : playerIndex + 1; - return getPlayer(nextPlayerIndex); - } - - - /** - * Return player with the given index. - * @param i player index - * @return demand player - */ - public Player getPlayer(int i) { - return plist[i]; - } - - /** - * Returns whole player list - * @return player list - */ - public Player[] getAllPlayers() { - return plist; - } - - public TilePack getTilePack() { - return tilePack; - } - - public void setTilePack(TilePack tilePack) { - this.tilePack = tilePack; - } - - public Board getBoard() { - return board; - } - - - public Meeple getMeeple(final Position p, final Location loc, Class meepleType, Player owner) { - for (Meeple m : getDeployedMeeples()) { - if (m.at(p) && m.getLocation().equals(loc)) { - if (m.getClass().equals(meepleType) && m.getPlayer().equals(owner)) { - return m; - } - } - } - return null; - } - - public void setPlayers(List players, int turnPlayer) { - Player[] plist = players.toArray(new Player[players.size()]); - this.plist = plist; - this.turnPlayer = getPlayer(turnPlayer); - } - - private void createCapabilityInstance(Class clazz) { - if (clazz == null) return; - try { - Capability capability = clazz.getConstructor(Game.class).newInstance(this); - capabilities.add(capability); - addGameListener(capability); - } catch (Exception e) { - logger.error(e.getMessage(), e); //should never happen - } - } - - public List getCapabilities() { - return capabilities; - } - - @SuppressWarnings("unchecked") - public T getCapability(Class clazz) { - for (Capability c : capabilities) { - if (c.getClass().equals(clazz)) return (T) c; - } - return null; - } - - public void start() { - for (Class capability: getCapabilityClasses()) { - createCapabilityInstance(capability); - } - board = new Board(this); - } - - - public LocationsMap prepareFollowerLocations() { - LocationsMap sites = new LocationsMap(); - Set locations = prepareFollowerLocations(currentTile, false); - if (!locations.isEmpty()) { - sites.put(currentTile.getPosition(), locations); - } - return sites; - } - - public Set prepareFollowerLocations(Tile tile, boolean excludeFinished) { - if (!isDeployAllowed(tile, Follower.class)) return Collections.emptySet(); - Set locations = tile.getUnoccupiedScoreables(excludeFinished); - if (hasCapability(PrincessCapability.class) && hasRule(CustomRule.PRINCESS_MUST_REMOVE_KNIGHT)) { - City princessCity = tile.getCityWithPrincess(); - if (princessCity != null) { - locations.remove(princessCity.getLocation()); - } - } - return locations; - } - - //scoring helpers - - public void scoreFeature(int points, ScoreContext ctx, Player p) { - p.addPoints(points, ctx.getMasterFeature().getPointCategory()); - Follower follower = ctx.getSampleFollower(p); - boolean isFinalScoring = getPhase() instanceof GameOverPhase; - if (fairyCapability != null && follower.at(fairyCapability.getFairyPosition())) { - p.addPoints(FairyCapability.FAIRY_POINTS_FINISHED_OBJECT, PointCategory.FAIRY); - fireGameEvent().scored(follower.getFeature(), points+FairyCapability.FAIRY_POINTS_FINISHED_OBJECT, - points+" + "+FairyCapability.FAIRY_POINTS_FINISHED_OBJECT, follower, - isFinalScoring); - } else { - fireGameEvent().scored(follower.getFeature(), points, points+"", follower, isFinalScoring); - } - } - - public void scoreCompletableFeature(CompletableScoreContext ctx) { - Set players = ctx.getMajorOwners(); - if (players.isEmpty()) return; - int points = ctx.getPoints(); - for (Player p : players) { - scoreFeature(points, ctx, p); - } - } - - public int idSequnceNextVal() { - return ++idSequenceCurrVal; - } - - // delegation to capabilities - - public void initTile(Tile tile, Element xml) { - for (Capability cap: capabilities) { - cap.initTile(tile, xml); - } - } - - public void initFeature(Tile tile, Feature feature, Element xml) { - for (Capability cap: capabilities) { - cap.initFeature(tile, feature, xml); - } - } - - public void initPlayer(Player player) { - for (Capability cap: capabilities) { - cap.initPlayer(player); - } - } - - public String getTileGroup(Tile tile) { - for (Capability cap: capabilities) { - String group = cap.getTileGroup(tile); - if (group != null) return group; - } - return null; - } - - public void begin() { - fairyCapability = getCapability(FairyCapability.class); - for (Capability cap: capabilities) { - cap.begin(); - } - } - - public void prepareActions(List actions, LocationsMap commonSites) { - for (Capability cap: capabilities) { - cap.prepareActions(actions, commonSites); - } - } - - public void prepareFollowerActions(List actions, LocationsMap commonSites) { - for (Capability cap: capabilities) { - cap.prepareFollowerActions(actions, commonSites); - } - } - - public boolean isDeployAllowed(Tile tile, Class meepleType) { - for (Capability cap: capabilities) { - if (!cap.isDeployAllowed(tile, meepleType)) return false; - } - return true; - } - - public void scoreCompleted(CompletableScoreContext ctx) { - for (Capability cap: capabilities) { - cap.scoreCompleted(ctx); - } - } - - public void turnCleanUp() { - for (Capability cap: capabilities) { - cap.turnCleanUp(); - } - } - - public void finalScoring() { - for (Capability cap: capabilities) { - cap.finalScoring(); - } - } - - public boolean isTilePlacementAllowed(Tile tile, Position p) { - for (Capability cap: capabilities) { - if (!cap.isTilePlacementAllowed(tile, p)) return false; - } - return true; - } - - public void saveTileToSnapshot(Tile tile, Document doc, Element tileNode) { - for (Capability cap: capabilities) { - cap.saveTileToSnapshot(tile, doc, tileNode); - } - } - - public void loadTileFromSnapshot(Tile tile, Element tileNode) { - for (Capability cap: capabilities) { - cap.loadTileFromSnapshot(tile, tileNode); - } - } - - @Override - public String toString() { - return "Game in " + phase.getClass().getSimpleName() + " phase."; - } -} +package com.jcloisterzone.game; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.ini4j.Ini; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.google.common.collect.ClassToInstanceMap; +import com.google.common.collect.Iterables; +import com.google.common.collect.MutableClassToInstanceMap; +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Board; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.event.EventMulticaster; +import com.jcloisterzone.event.GameEventAdapter; +import com.jcloisterzone.event.GameEventListener; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.ScoreContext; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.capability.FairyCapability; +import com.jcloisterzone.game.capability.PrincessCapability; +import com.jcloisterzone.game.phase.GameOverPhase; +import com.jcloisterzone.game.phase.Phase; + + +/** + * Other information than board needs in game. Contains players with their + * points, followers ... and game rules of current game. + */ +public class Game extends GameSettings { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + private Ini config; + + /** pack of remaining tiles */ + private TilePack tilePack; + /** pack of remaining tiles */ + private Tile currentTile; + /** game board, contains placed tiles */ + private Board board; + + /** list of players in game */ + private Player[] plist; + /** rules of current game */ + + /** player in turn */ + private Player turnPlayer; + + private final ClassToInstanceMap phases = MutableClassToInstanceMap.create(); + private Phase phase; + + private GameEventListener eventListener = new GameEventAdapter(); + private UserInterface userInterface; + + private List capabilities = new ArrayList<>(); + private FairyCapability fairyCapability; //shortcut + + private int idSequenceCurrVal = 0; + + + public Ini getConfig() { + return config; + } + + public void setConfig(Ini config) { + this.config = config; + } + + public Tile getCurrentTile() { + return currentTile; + } + + public void setCurrentTile(Tile currentTile) { + this.currentTile = currentTile; + } + + public Phase getPhase() { + return phase; + } + + public void setPhase(Phase phase) { + phase.setEntered(false); + this.phase = phase; + } + + public ClassToInstanceMap getPhases() { + return phases; + } + + public GameEventListener fireGameEvent() { + return eventListener; + } + public void addGameListener(GameEventListener listener) { + eventListener = (GameEventListener) EventMulticaster.addListener(eventListener, listener); + } + public void removeGameListener(GameEventListener listener) { + eventListener = (GameEventListener) EventMulticaster.removeListener(eventListener, listener); + } + public UserInterface getUserInterface() { + return userInterface; + } + public void addUserInterface(UserInterface ui) { + userInterface = (UserInterface) EventMulticaster.addListener(userInterface, ui); + } + + public Iterable getDeployedMeeples() { + Iterable iter = Collections.emptyList(); + for (Player player : plist) { + iter = Iterables.concat(iter, player.getFollowers(), player.getSpecialMeeples()); + } + return Iterables.filter(iter, MeeplePredicates.deployed()); + } + + public Player getTurnPlayer() { + return turnPlayer; + } + + public void setTurnPlayer(Player turnPlayer) { + this.turnPlayer = turnPlayer; + fireGameEvent().playerActivated(turnPlayer, turnPlayer); + } + + /** + * Returns player who is allowed to make next action. + * @return + */ + public Player getActivePlayer() { + Phase phase = getPhase(); + return phase == null ? null : phase.getActivePlayer(); + } + + + /** + * Ends turn of current active player and make active the next. + */ + public Player getNextPlayer() { + return getNextPlayer(turnPlayer); + } + + public Player getNextPlayer(Player p) { + int playerIndex = p.getIndex(); + int nextPlayerIndex = playerIndex == (plist.length - 1) ? 0 : playerIndex + 1; + return getPlayer(nextPlayerIndex); + } + + + /** + * Return player with the given index. + * @param i player index + * @return demand player + */ + public Player getPlayer(int i) { + return plist[i]; + } + + /** + * Returns whole player list + * @return player list + */ + public Player[] getAllPlayers() { + return plist; + } + + public TilePack getTilePack() { + return tilePack; + } + + public void setTilePack(TilePack tilePack) { + this.tilePack = tilePack; + } + + public Board getBoard() { + return board; + } + + + public Meeple getMeeple(final Position p, final Location loc, Class meepleType, Player owner) { + for (Meeple m : getDeployedMeeples()) { + if (m.at(p) && m.getLocation().equals(loc)) { + if (m.getClass().equals(meepleType) && m.getPlayer().equals(owner)) { + return m; + } + } + } + return null; + } + + public void setPlayers(List players, int turnPlayer) { + Player[] plist = players.toArray(new Player[players.size()]); + this.plist = plist; + this.turnPlayer = getPlayer(turnPlayer); + } + + private void createCapabilityInstance(Class clazz) { + if (clazz == null) return; + try { + Capability capability = clazz.getConstructor(Game.class).newInstance(this); + capabilities.add(capability); + addGameListener(capability); + } catch (Exception e) { + logger.error(e.getMessage(), e); //should never happen + } + } + + public List getCapabilities() { + return capabilities; + } + + @SuppressWarnings("unchecked") + public T getCapability(Class clazz) { + for (Capability c : capabilities) { + if (c.getClass().equals(clazz)) return (T) c; + } + return null; + } + + public void start() { + for (Class capability: getCapabilityClasses()) { + createCapabilityInstance(capability); + } + board = new Board(this); + } + + + public LocationsMap prepareFollowerLocations() { + LocationsMap sites = new LocationsMap(); + Set locations = prepareFollowerLocations(currentTile, false); + if (!locations.isEmpty()) { + sites.put(currentTile.getPosition(), locations); + } + return sites; + } + + public Set prepareFollowerLocations(Tile tile, boolean excludeFinished) { + if (!isDeployAllowed(tile, Follower.class)) return Collections.emptySet(); + Set locations = tile.getUnoccupiedScoreables(excludeFinished); + if (hasCapability(PrincessCapability.class) && hasRule(CustomRule.PRINCESS_MUST_REMOVE_KNIGHT)) { + City princessCity = tile.getCityWithPrincess(); + if (princessCity != null) { + locations.remove(princessCity.getLocation()); + } + } + return locations; + } + + //scoring helpers + + public void scoreFeature(int points, ScoreContext ctx, Player p) { + p.addPoints(points, ctx.getMasterFeature().getPointCategory()); + Follower follower = ctx.getSampleFollower(p); + boolean isFinalScoring = getPhase() instanceof GameOverPhase; + if (fairyCapability != null && follower.at(fairyCapability.getFairyPosition())) { + p.addPoints(FairyCapability.FAIRY_POINTS_FINISHED_OBJECT, PointCategory.FAIRY); + fireGameEvent().scored(follower.getFeature(), points+FairyCapability.FAIRY_POINTS_FINISHED_OBJECT, + points+" + "+FairyCapability.FAIRY_POINTS_FINISHED_OBJECT, follower, + isFinalScoring); + } else { + fireGameEvent().scored(follower.getFeature(), points, points+"", follower, isFinalScoring); + } + } + + public void scoreCompletableFeature(CompletableScoreContext ctx) { + Set players = ctx.getMajorOwners(); + if (players.isEmpty()) return; + int points = ctx.getPoints(); + for (Player p : players) { + scoreFeature(points, ctx, p); + } + } + + public int idSequnceNextVal() { + return ++idSequenceCurrVal; + } + + // delegation to capabilities + + public void initTile(Tile tile, Element xml) { + for (Capability cap: capabilities) { + cap.initTile(tile, xml); + } + } + + public void initFeature(Tile tile, Feature feature, Element xml) { + for (Capability cap: capabilities) { + cap.initFeature(tile, feature, xml); + } + } + + public void initPlayer(Player player) { + for (Capability cap: capabilities) { + cap.initPlayer(player); + } + } + + public String getTileGroup(Tile tile) { + for (Capability cap: capabilities) { + String group = cap.getTileGroup(tile); + if (group != null) return group; + } + return null; + } + + public void begin() { + fairyCapability = getCapability(FairyCapability.class); + for (Capability cap: capabilities) { + cap.begin(); + } + } + + public void prepareActions(List actions, LocationsMap commonSites) { + for (Capability cap: capabilities) { + cap.prepareActions(actions, commonSites); + } + } + + public void prepareFollowerActions(List actions, LocationsMap commonSites) { + for (Capability cap: capabilities) { + cap.prepareFollowerActions(actions, commonSites); + } + } + + public boolean isDeployAllowed(Tile tile, Class meepleType) { + for (Capability cap: capabilities) { + if (!cap.isDeployAllowed(tile, meepleType)) return false; + } + return true; + } + + public void scoreCompleted(CompletableScoreContext ctx) { + for (Capability cap: capabilities) { + cap.scoreCompleted(ctx); + } + } + + public void turnCleanUp() { + for (Capability cap: capabilities) { + cap.turnCleanUp(); + } + } + + public void finalScoring() { + for (Capability cap: capabilities) { + cap.finalScoring(); + } + } + + public boolean isTilePlacementAllowed(Tile tile, Position p) { + for (Capability cap: capabilities) { + if (!cap.isTilePlacementAllowed(tile, p)) return false; + } + return true; + } + + public void saveTileToSnapshot(Tile tile, Document doc, Element tileNode) { + for (Capability cap: capabilities) { + cap.saveTileToSnapshot(tile, doc, tileNode); + } + } + + public void loadTileFromSnapshot(Tile tile, Element tileNode) { + for (Capability cap: capabilities) { + cap.loadTileFromSnapshot(tile, tileNode); + } + } + + @Override + public String toString() { + return "Game in " + phase.getClass().getSimpleName() + " phase."; + } +} diff --git a/src/main/java/com/jcloisterzone/game/GameDelegation.java b/src/main/java/com/jcloisterzone/game/GameDelegation.java index 6696f86e5..6ee44a5b0 100644 --- a/src/main/java/com/jcloisterzone/game/GameDelegation.java +++ b/src/main/java/com/jcloisterzone/game/GameDelegation.java @@ -1,37 +1,37 @@ -package com.jcloisterzone.game; - -import java.util.List; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; - - -public interface GameDelegation { - - void initTile(Tile tile, Element xml); - void initFeature(Tile tile, Feature feature, Element xml); - void initPlayer(Player player); - String getTileGroup(Tile tile); - - //TODO merge with UI events ??? - asi ne - void begin(); - //void start(); - void prepareActions(List actions, LocationsMap commonSites); - void prepareFollowerActions(List actions, LocationsMap commonSites); - void scoreCompleted(CompletableScoreContext ctx); - void turnCleanUp(); - void finalScoring(); - - boolean isTilePlacementAllowed(Tile tile, Position p); - - void saveTileToSnapshot(Tile tile, Document doc, Element tileNode); - void loadTileFromSnapshot(Tile tile, Element tileNode); -} +package com.jcloisterzone.game; + +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; + + +public interface GameDelegation { + + void initTile(Tile tile, Element xml); + void initFeature(Tile tile, Feature feature, Element xml); + void initPlayer(Player player); + String getTileGroup(Tile tile); + + //TODO merge with UI events ??? - asi ne + void begin(); + //void start(); + void prepareActions(List actions, LocationsMap commonSites); + void prepareFollowerActions(List actions, LocationsMap commonSites); + void scoreCompleted(CompletableScoreContext ctx); + void turnCleanUp(); + void finalScoring(); + + boolean isTilePlacementAllowed(Tile tile, Position p); + + void saveTileToSnapshot(Tile tile, Document doc, Element tileNode); + void loadTileFromSnapshot(Tile tile, Element tileNode); +} diff --git a/src/main/java/com/jcloisterzone/game/GameSettings.java b/src/main/java/com/jcloisterzone/game/GameSettings.java index a7e16fe54..0de3359dc 100644 --- a/src/main/java/com/jcloisterzone/game/GameSettings.java +++ b/src/main/java/com/jcloisterzone/game/GameSettings.java @@ -1,38 +1,38 @@ -package com.jcloisterzone.game; - -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -import com.jcloisterzone.Expansion; - -public class GameSettings { - - private final Set customRules = EnumSet.noneOf(CustomRule.class); - private final Set expansions = EnumSet.noneOf(Expansion.class); - private final Set> capabilityClasses = new HashSet<>(); - - public boolean hasExpansion(Expansion expansion) { - return expansions.contains(expansion); - } - - public boolean hasRule(CustomRule rule) { - return customRules.contains(rule); - } - - public boolean hasCapability(Class c) { - return capabilityClasses.contains(c); - } - - public Set getExpansions() { - return expansions; - } - - public Set getCustomRules() { - return customRules; - } - - public Set> getCapabilityClasses() { - return capabilityClasses; - } -} +package com.jcloisterzone.game; + +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +import com.jcloisterzone.Expansion; + +public class GameSettings { + + private final Set customRules = EnumSet.noneOf(CustomRule.class); + private final Set expansions = EnumSet.noneOf(Expansion.class); + private final Set> capabilityClasses = new HashSet<>(); + + public boolean hasExpansion(Expansion expansion) { + return expansions.contains(expansion); + } + + public boolean hasRule(CustomRule rule) { + return customRules.contains(rule); + } + + public boolean hasCapability(Class c) { + return capabilityClasses.contains(c); + } + + public Set getExpansions() { + return expansions; + } + + public Set getCustomRules() { + return customRules; + } + + public Set> getCapabilityClasses() { + return capabilityClasses; + } +} diff --git a/src/main/java/com/jcloisterzone/game/GuiClientStub.java b/src/main/java/com/jcloisterzone/game/GuiClientStub.java index 5064979b0..0ca356ebf 100644 --- a/src/main/java/com/jcloisterzone/game/GuiClientStub.java +++ b/src/main/java/com/jcloisterzone/game/GuiClientStub.java @@ -1,87 +1,87 @@ -package com.jcloisterzone.game; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.util.List; - -import javax.swing.JOptionPane; -import javax.swing.SwingUtilities; - -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.rmi.ControllMessage; -import com.jcloisterzone.rmi.mina.ClientStub; -import com.jcloisterzone.ui.Client; - - -public class GuiClientStub extends ClientStub { - - private final Client client; - - public GuiClientStub(Client client) { - this.client = client; - } - - @Override - protected Game createGame(ControllMessage msg) { - Game game = super.createGame(msg); - game.setConfig(client.getConfig()); - client.setGame(game); - return game; - } - - @Override - protected void controllMessageReceived(final ControllMessage msg) { - super.controllMessageReceived(msg); - - SwingUtilities.invokeLater(new Runnable() { - public void run() { - client.showCreateGamePanel(msg.getSnapshot() == null, msg.getSlots()); - } - }); - - if (client.getConfig().get("debug", "autostart", boolean.class)) { - client.getConfig().remove("debug", "autostart"); //apply autostart only once - final List players = client.getConfig().get("debug").getAll("autostart_player"); - if (players.isEmpty()) { - players.add("UNDEFINED"); - } - SwingUtilities.invokeLater(new Runnable() { - public void run() { - int i = 0; - for (String name: players) { - PlayerSlot slot; - try { - Class clazz = Class.forName(name); - slot = new PlayerSlot(i, SlotType.AI, "AI-"+i+"-"+clazz.getSimpleName(), getClientId()); - slot.setAiClassName(clazz.getName()); - } catch (ClassNotFoundException e) { - slot = new PlayerSlot(i, SlotType.PLAYER, name, getClientId()); - } - client.getServer().updateSlot(slot, null); - i++; - } - client.getServer().startGame(); - } - }); - } - } - - protected void versionMismatch(int version) { - super.versionMismatch(version); - JOptionPane.showMessageDialog(client, - _("Remote JCloisterZone is not compatible with local application. Please upgrade both applications to same version."), - _("Incompatible versions"), - JOptionPane.ERROR_MESSAGE - ); - } - - @Override - protected void onDisconnect() { - client.getGridPanel().setErrorMessage("Connection lost. Reconnecting..."); - } - - @Override - protected void onReconnect() { - client.getGridPanel().setErrorMessage(null); - } -} +package com.jcloisterzone.game; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.util.List; + +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.rmi.ControllMessage; +import com.jcloisterzone.rmi.mina.ClientStub; +import com.jcloisterzone.ui.Client; + + +public class GuiClientStub extends ClientStub { + + private final Client client; + + public GuiClientStub(Client client) { + this.client = client; + } + + @Override + protected Game createGame(ControllMessage msg) { + Game game = super.createGame(msg); + game.setConfig(client.getConfig()); + client.setGame(game); + return game; + } + + @Override + protected void controllMessageReceived(final ControllMessage msg) { + super.controllMessageReceived(msg); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + client.showCreateGamePanel(msg.getSnapshot() == null, msg.getSlots()); + } + }); + + if (client.getConfig().get("debug", "autostart", boolean.class)) { + client.getConfig().remove("debug", "autostart"); //apply autostart only once + final List players = client.getConfig().get("debug").getAll("autostart_player"); + if (players.isEmpty()) { + players.add("UNDEFINED"); + } + SwingUtilities.invokeLater(new Runnable() { + public void run() { + int i = 0; + for (String name: players) { + PlayerSlot slot; + try { + Class clazz = Class.forName(name); + slot = new PlayerSlot(i, SlotType.AI, "AI-"+i+"-"+clazz.getSimpleName(), getClientId()); + slot.setAiClassName(clazz.getName()); + } catch (ClassNotFoundException e) { + slot = new PlayerSlot(i, SlotType.PLAYER, name, getClientId()); + } + client.getServer().updateSlot(slot, null); + i++; + } + client.getServer().startGame(); + } + }); + } + } + + protected void versionMismatch(int version) { + super.versionMismatch(version); + JOptionPane.showMessageDialog(client, + _("Remote JCloisterZone is not compatible with local application. Please upgrade both applications to same version."), + _("Incompatible versions"), + JOptionPane.ERROR_MESSAGE + ); + } + + @Override + protected void onDisconnect() { + client.getGridPanel().setErrorMessage("Connection lost. Reconnecting..."); + } + + @Override + protected void onReconnect() { + client.getGridPanel().setErrorMessage(null); + } +} diff --git a/src/main/java/com/jcloisterzone/game/PlayerSlot.java b/src/main/java/com/jcloisterzone/game/PlayerSlot.java index 7dad234fa..1e83786ed 100644 --- a/src/main/java/com/jcloisterzone/game/PlayerSlot.java +++ b/src/main/java/com/jcloisterzone/game/PlayerSlot.java @@ -1,77 +1,77 @@ -package com.jcloisterzone.game; - -import java.io.Serializable; - -public class PlayerSlot implements Serializable { - - private static final long serialVersionUID = 6093356973595538191L; - - public static final int COUNT = 6; - - public enum SlotType { PLAYER, AI, OPEN } - - private final int number; - private SlotType type = SlotType.OPEN; - private String nick; - private Long owner; //clientId - private Integer serial; //server assign sequence number when type is occupied - private String aiClassName; - - public PlayerSlot(int number) { - this.number = number; - } - - public PlayerSlot(int number, SlotType type, String nick, Long owner) { - this.number = number; - this.type = type; - this.nick = nick; - this.owner = owner; - } - - public int getNumber() { - return number; - } - public SlotType getType() { - return type; - } - public void setType(SlotType type) { - this.type = type; - } - public String getNick() { - return nick; - } - public void setNick(String nick) { - this.nick = nick; - } - public Long getOwner() { - return owner; - } - public void setOwner(Long owner) { - this.owner = owner; - } - public Integer getSerial() { - return serial; - } - - public void setSerial(Integer serial) { - this.serial = serial; - } - - public boolean isOccupied() { - return type == SlotType.PLAYER || type == SlotType.AI; - } - - public String getAiClassName() { - return aiClassName; - } - - public void setAiClassName(String aiClassName) { - this.aiClassName = aiClassName; - } - - @Override - public String toString() { - return number + "-" + type + "[" + nick + "]"; - } - -} +package com.jcloisterzone.game; + +import java.io.Serializable; + +public class PlayerSlot implements Serializable { + + private static final long serialVersionUID = 6093356973595538191L; + + public static final int COUNT = 6; + + public enum SlotType { PLAYER, AI, OPEN } + + private final int number; + private SlotType type = SlotType.OPEN; + private String nick; + private Long owner; //clientId + private Integer serial; //server assign sequence number when type is occupied + private String aiClassName; + + public PlayerSlot(int number) { + this.number = number; + } + + public PlayerSlot(int number, SlotType type, String nick, Long owner) { + this.number = number; + this.type = type; + this.nick = nick; + this.owner = owner; + } + + public int getNumber() { + return number; + } + public SlotType getType() { + return type; + } + public void setType(SlotType type) { + this.type = type; + } + public String getNick() { + return nick; + } + public void setNick(String nick) { + this.nick = nick; + } + public Long getOwner() { + return owner; + } + public void setOwner(Long owner) { + this.owner = owner; + } + public Integer getSerial() { + return serial; + } + + public void setSerial(Integer serial) { + this.serial = serial; + } + + public boolean isOccupied() { + return type == SlotType.PLAYER || type == SlotType.AI; + } + + public String getAiClassName() { + return aiClassName; + } + + public void setAiClassName(String aiClassName) { + this.aiClassName = aiClassName; + } + + @Override + public String toString() { + return number + "-" + type + "[" + nick + "]"; + } + +} diff --git a/src/main/java/com/jcloisterzone/game/Snapshot.java b/src/main/java/com/jcloisterzone/game/Snapshot.java index e47341a7f..77eea5218 100644 --- a/src/main/java/com/jcloisterzone/game/Snapshot.java +++ b/src/main/java/com/jcloisterzone/game/Snapshot.java @@ -1,402 +1,402 @@ -package com.jcloisterzone.game; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.google.common.base.Objects; -import com.jcloisterzone.Application; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.VersionComparator; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.game.phase.Phase; - - -public class Snapshot implements Serializable { - - protected transient Logger logger = LoggerFactory.getLogger(getClass()); - - public static final String COMPATIBLE_FROM = "2.3"; - - private Document doc; - private Element root; - - private Map tileElemens; //write cache - - private boolean gzipOutput = true; - - - public Snapshot(Game game, long clientId) { - createRootStructure(game); - createRuleElements(game); - createExpansionElements(game); - createCapabilityElements(game); - createPlayerElements(game, clientId); - createTileElements(game); - createMeepleElements(game); - } - - public Snapshot(File savedGame) throws IOException, SAXException { - try { - load(new GZIPInputStream(new FileInputStream(savedGame))); - } catch (IOException e) { - if ("Not in GZIP format".equals(e.getMessage())) { - load(new FileInputStream(savedGame)); - } else { - throw e; - } - } - } - - public boolean isGzipOutput() { - return gzipOutput; - } - - public void setGzipOutput(boolean gzipOutput) { - this.gzipOutput = gzipOutput; - } - - - private void createRootStructure(Game game) { - doc = XmlUtils.newDocument(); - root = doc.createElement("game"); - root.setAttribute("app-version", Application.VERSION); - root.setAttribute("phase", game.getPhase().getClass().getName()); - doc.appendChild(root); - - } - - private void createRuleElements(Game game) { - for (CustomRule cr : game.getCustomRules()) { - Element el = doc.createElement("rule"); - el.setAttribute("name", cr.name()); - root.appendChild(el); - } - } - - private void createExpansionElements(Game game) { - for (Expansion exp : game.getExpansions()) { - Element el = doc.createElement("expansion"); - el.setAttribute("name", exp.name()); - root.appendChild(el); - } - } - - private void createCapabilityElements(Game game) { - for (Capability cap : game.getCapabilities()) { - Element el = doc.createElement("capability"); - el.setAttribute("name", cap.getClass().getName()); - root.appendChild(el); - cap.saveToSnapshot(doc, el); - } - } - - - private void createPlayerElements(Game game, long clientId) { - Element parent = doc.createElement("players"); - parent.setAttribute("turn", "" + game.getTurnPlayer().getIndex()); - root.appendChild(parent); - for (Player p : game.getAllPlayers()) { - Element el = doc.createElement("player"); - el.setAttribute("name", p.getNick()); - el.setAttribute("points", "" + p.getPoints()); - el.setAttribute("slot", "" + p.getSlot().getNumber()); - if (Objects.equal(p.getOwnerId(),clientId)) { - el.setAttribute("local", "true"); - } - if (p.getSlot().getType() == SlotType.AI) { - el.setAttribute("ai-class", p.getSlot().getAiClassName()); - } - parent.appendChild(el); - } - } - - private void createTileElements(Game game) { - tileElemens = new HashMap(); - Element parent = doc.createElement("tiles"); - if (game.getCurrentTile() != null) { - parent.setAttribute("next", game.getCurrentTile().getId()); - } - root.appendChild(parent); - for (String group : game.getTilePack().getGroups()) { - Element el = doc.createElement("group"); - el.setAttribute("name", group); - el.setAttribute("active", "" + game.getTilePack().isGroupActive(group)); - parent.appendChild(el); - } - for (Tile tile : game.getBoard().getAllTiles()) { - Element el = doc.createElement("tile"); - el.setAttribute("name", tile.getId()); - el.setAttribute("rotation", tile.getRotation().name()); - XmlUtils.injectPosition(el, tile.getPosition()); - parent.appendChild(el); - tileElemens.put(tile.getPosition(), el); - game.saveTileToSnapshot(tile, doc, el); - } - for (Tile tile : game.getBoard().getDiscardedTiles()) { - Element el = doc.createElement("discard"); - el.setAttribute("name", tile.getId()); - parent.appendChild(el); - } - } - - private void createMeepleElements(Game game) { - for (Meeple m : game.getDeployedMeeples()) { - Element tileEl = tileElemens.get(m.getPosition()); - Element el = doc.createElement("meeple"); - el.setAttribute("player", "" + m.getPlayer().getIndex()); - el.setAttribute("type", "" + m.getClass().getName()); - el.setAttribute("loc", "" + m.getLocation()); - tileEl.appendChild(el); - } - } - - public void save(File file) throws TransformerException, IOException { - OutputStream os = new FileOutputStream(file); - StreamResult streamResult; - if (gzipOutput) { - streamResult = new StreamResult(new GZIPOutputStream(os)); - } else { - streamResult = new StreamResult(os); - } - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer serializer = tf.newTransformer(); - serializer.setOutputProperty(OutputKeys.INDENT, "yes"); - serializer.setOutputProperty(OutputKeys.STANDALONE, "yes"); - serializer.setOutputProperty(OutputKeys.METHOD, "xml"); - serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - serializer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml"); - serializer.transform(new DOMSource(doc), streamResult); - streamResult.getOutputStream().close(); - } - - - public void load(InputStream is) throws SnapshotCorruptedException { - doc = XmlUtils.parseDocument(is); - root = doc.getDocumentElement(); - String snapshotVersion = root.getAttribute("app-version"); - if (!snapshotVersion.equals(Application.VERSION)) { //first check simple equality (useful for dev version without numbers) - if ((new VersionComparator()).compare(snapshotVersion, Snapshot.COMPATIBLE_FROM) < 0) { - throw new SnapshotVersionException("Saved game is not compatible with current JCloisterZone application. (saved in "+snapshotVersion+")"); - } - } - } - - private NodeList getSecondLevelElelents(String first, String second) { - return ((Element)root.getElementsByTagName(first).item(0)).getElementsByTagName(second); - } - - public Set getExpansions() { - Set result = new HashSet<>(); - NodeList nl = root.getElementsByTagName("expansion"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - Expansion exp = Expansion.valueOf(el.getAttribute("name")); - result.add(exp); - } - return result; - } - - @SuppressWarnings("unchecked") - public void loadCapabilities(Game game) { - NodeList nl = root.getElementsByTagName("capability"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - String capabilityName = el.getAttribute("name"); - try { - //TODO instances should be created here, not in load phase - Class capabilityClass = (Class) Class.forName(capabilityName); - Capability capability = game.getCapability(capabilityClass); - capability.loadFromSnapshot(doc, el); - } catch (Exception e) { - logger.error("Incompatible or corrupted snapshot. Problem with stored expansion: " + capabilityName, e); - game.getUserInterface().showWarning(_("Load error"), _("Saved game is incompatible or file is corrupted. Game couldn't work properly.")); - } - } - } - - public Set getCustomRules() { - Set result = new HashSet<>(); - NodeList nl = root.getElementsByTagName("rule"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - CustomRule rule = CustomRule.valueOf(el.getAttribute("name")); - result.add(rule); - } - return result; - } - - public List getPlayers() { - List players = new ArrayList<>(); - NodeList nl = getSecondLevelElelents("players", "player"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - PlayerSlot slot = new PlayerSlot(Integer.parseInt(el.getAttribute("slot"))); - Player p = new Player(el.getAttribute("name"), i, slot); - p.setPoints(Integer.parseInt(el.getAttribute("points"))); - if (el.hasAttribute("ai-class")) { - slot.setType(SlotType.AI); - String aiClassName = el.getAttribute("ai-class"); - slot.setAiClassName(aiClassName); - } else { - if (el.hasAttribute("local")) { - slot.setType(SlotType.PLAYER); - } - } - players.add(p); - } - return players; - } - - public PlayerSlot[] getPlayerSlots() { - List players = getPlayers(); - int maxSlotNumber = 0; - for (Player player : players) { - int slotNumber = player.getSlot().getNumber(); - if (slotNumber > maxSlotNumber) maxSlotNumber = slotNumber; - } - - PlayerSlot[] slots = new PlayerSlot[maxSlotNumber+1]; - for (int i = 0; i < slots.length; i++) { - for (Player player : players) { - PlayerSlot slot = player.getSlot(); - if (slot.getNumber() == i) { - slot.setNick(player.getNick()); - slots[i] = slot; - break; - } - } - } - return slots; - } - - public int getTurnPlayer() { - Element el = (Element) doc.getElementsByTagName("players").item(0); - return Integer.parseInt(el.getAttribute("turn")); - } - - public List getActiveGroups() { - List result = new ArrayList<>(); - NodeList nl = getSecondLevelElelents("tiles", "group"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - if (Boolean.parseBoolean(el.getAttribute("active"))) { - result.add(el.getAttribute("name")); - } - } - return result; - } - - public List getDiscardedTiles() { - List result = new ArrayList<>(); - NodeList nl = getSecondLevelElelents("tiles", "discard"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - result.add(el.getAttribute("name")); - } - return result; - } - - public Rotation extractTileRotation(Element el) { - return Rotation.valueOf(el.getAttribute("rotation")); - } - - @SuppressWarnings("unchecked") - public List extractTileMeeples(Element tileEl, Game game, Position pos) throws SnapshotCorruptedException { - NodeList nl = tileEl.getElementsByTagName("meeple"); - List result = new ArrayList<>(); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - Location loc = Location.valueOf(el.getAttribute("loc")); - Class mt = (Class) XmlUtils.classForName(el.getAttribute("type")); - int playerIndex = Integer.parseInt(el.getAttribute("player")); - Meeple meeple = game.getPlayer(playerIndex).getMeepleFromSupply(mt); - meeple.setLocation(loc); - meeple.setPosition(pos); - //don't set feature here. Feature must be set after meeple deployment to correct replace ref during merge - result.add(meeple); - } - return result; - } - - public NodeList getTileElements() { - return getSecondLevelElelents("tiles", "tile"); - } - - public String getNextTile() { - Element el = (Element) root.getElementsByTagName("tiles").item(0); - return el.getAttribute("next"); - } - - @SuppressWarnings("unchecked") - public Class getActivePhase() throws SnapshotCorruptedException { - return (Class) XmlUtils.classForName(root.getAttribute("phase")); - } - - public Game asGame() { - Game game = new Game(); - game.getExpansions().addAll(getExpansions()); - game.getCustomRules().addAll(getCustomRules()); - game.setPlayers(getPlayers(), getTurnPlayer()); - return game; - } - - private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { - String xml = (String) stream.readObject(); - InputStream is = new ByteArrayInputStream(xml.getBytes()); - load(is); - logger = LoggerFactory.getLogger(getClass()); - } - - private void writeObject(java.io.ObjectOutputStream stream) throws IOException { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - //StreamResult streamResult = new StreamResult(new ZipOutputStream(os)); - StreamResult streamResult = new StreamResult(os); - TransformerFactory tf = TransformerFactory.newInstance(); - try { - Transformer serializer = tf.newTransformer(); - serializer.transform(new DOMSource(doc), streamResult); - stream.writeObject(os.toString()); - } catch (TransformerException e) { - throw new IOException(e); - } - } - -} +package com.jcloisterzone.game; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import com.google.common.base.Objects; +import com.jcloisterzone.Application; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.VersionComparator; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.game.phase.Phase; + + +public class Snapshot implements Serializable { + + protected transient Logger logger = LoggerFactory.getLogger(getClass()); + + public static final String COMPATIBLE_FROM = "2.3"; + + private Document doc; + private Element root; + + private Map tileElemens; //write cache + + private boolean gzipOutput = true; + + + public Snapshot(Game game, long clientId) { + createRootStructure(game); + createRuleElements(game); + createExpansionElements(game); + createCapabilityElements(game); + createPlayerElements(game, clientId); + createTileElements(game); + createMeepleElements(game); + } + + public Snapshot(File savedGame) throws IOException, SAXException { + try { + load(new GZIPInputStream(new FileInputStream(savedGame))); + } catch (IOException e) { + if ("Not in GZIP format".equals(e.getMessage())) { + load(new FileInputStream(savedGame)); + } else { + throw e; + } + } + } + + public boolean isGzipOutput() { + return gzipOutput; + } + + public void setGzipOutput(boolean gzipOutput) { + this.gzipOutput = gzipOutput; + } + + + private void createRootStructure(Game game) { + doc = XmlUtils.newDocument(); + root = doc.createElement("game"); + root.setAttribute("app-version", Application.VERSION); + root.setAttribute("phase", game.getPhase().getClass().getName()); + doc.appendChild(root); + + } + + private void createRuleElements(Game game) { + for (CustomRule cr : game.getCustomRules()) { + Element el = doc.createElement("rule"); + el.setAttribute("name", cr.name()); + root.appendChild(el); + } + } + + private void createExpansionElements(Game game) { + for (Expansion exp : game.getExpansions()) { + Element el = doc.createElement("expansion"); + el.setAttribute("name", exp.name()); + root.appendChild(el); + } + } + + private void createCapabilityElements(Game game) { + for (Capability cap : game.getCapabilities()) { + Element el = doc.createElement("capability"); + el.setAttribute("name", cap.getClass().getName()); + root.appendChild(el); + cap.saveToSnapshot(doc, el); + } + } + + + private void createPlayerElements(Game game, long clientId) { + Element parent = doc.createElement("players"); + parent.setAttribute("turn", "" + game.getTurnPlayer().getIndex()); + root.appendChild(parent); + for (Player p : game.getAllPlayers()) { + Element el = doc.createElement("player"); + el.setAttribute("name", p.getNick()); + el.setAttribute("points", "" + p.getPoints()); + el.setAttribute("slot", "" + p.getSlot().getNumber()); + if (Objects.equal(p.getOwnerId(),clientId)) { + el.setAttribute("local", "true"); + } + if (p.getSlot().getType() == SlotType.AI) { + el.setAttribute("ai-class", p.getSlot().getAiClassName()); + } + parent.appendChild(el); + } + } + + private void createTileElements(Game game) { + tileElemens = new HashMap(); + Element parent = doc.createElement("tiles"); + if (game.getCurrentTile() != null) { + parent.setAttribute("next", game.getCurrentTile().getId()); + } + root.appendChild(parent); + for (String group : game.getTilePack().getGroups()) { + Element el = doc.createElement("group"); + el.setAttribute("name", group); + el.setAttribute("active", "" + game.getTilePack().isGroupActive(group)); + parent.appendChild(el); + } + for (Tile tile : game.getBoard().getAllTiles()) { + Element el = doc.createElement("tile"); + el.setAttribute("name", tile.getId()); + el.setAttribute("rotation", tile.getRotation().name()); + XmlUtils.injectPosition(el, tile.getPosition()); + parent.appendChild(el); + tileElemens.put(tile.getPosition(), el); + game.saveTileToSnapshot(tile, doc, el); + } + for (Tile tile : game.getBoard().getDiscardedTiles()) { + Element el = doc.createElement("discard"); + el.setAttribute("name", tile.getId()); + parent.appendChild(el); + } + } + + private void createMeepleElements(Game game) { + for (Meeple m : game.getDeployedMeeples()) { + Element tileEl = tileElemens.get(m.getPosition()); + Element el = doc.createElement("meeple"); + el.setAttribute("player", "" + m.getPlayer().getIndex()); + el.setAttribute("type", "" + m.getClass().getName()); + el.setAttribute("loc", "" + m.getLocation()); + tileEl.appendChild(el); + } + } + + public void save(File file) throws TransformerException, IOException { + OutputStream os = new FileOutputStream(file); + StreamResult streamResult; + if (gzipOutput) { + streamResult = new StreamResult(new GZIPOutputStream(os)); + } else { + streamResult = new StreamResult(os); + } + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer serializer = tf.newTransformer(); + serializer.setOutputProperty(OutputKeys.INDENT, "yes"); + serializer.setOutputProperty(OutputKeys.STANDALONE, "yes"); + serializer.setOutputProperty(OutputKeys.METHOD, "xml"); + serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + serializer.setOutputProperty(OutputKeys.MEDIA_TYPE, "text/xml"); + serializer.transform(new DOMSource(doc), streamResult); + streamResult.getOutputStream().close(); + } + + + public void load(InputStream is) throws SnapshotCorruptedException { + doc = XmlUtils.parseDocument(is); + root = doc.getDocumentElement(); + String snapshotVersion = root.getAttribute("app-version"); + if (!snapshotVersion.equals(Application.VERSION)) { //first check simple equality (useful for dev version without numbers) + if ((new VersionComparator()).compare(snapshotVersion, Snapshot.COMPATIBLE_FROM) < 0) { + throw new SnapshotVersionException("Saved game is not compatible with current JCloisterZone application. (saved in "+snapshotVersion+")"); + } + } + } + + private NodeList getSecondLevelElelents(String first, String second) { + return ((Element)root.getElementsByTagName(first).item(0)).getElementsByTagName(second); + } + + public Set getExpansions() { + Set result = new HashSet<>(); + NodeList nl = root.getElementsByTagName("expansion"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + Expansion exp = Expansion.valueOf(el.getAttribute("name")); + result.add(exp); + } + return result; + } + + @SuppressWarnings("unchecked") + public void loadCapabilities(Game game) { + NodeList nl = root.getElementsByTagName("capability"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + String capabilityName = el.getAttribute("name"); + try { + //TODO instances should be created here, not in load phase + Class capabilityClass = (Class) Class.forName(capabilityName); + Capability capability = game.getCapability(capabilityClass); + capability.loadFromSnapshot(doc, el); + } catch (Exception e) { + logger.error("Incompatible or corrupted snapshot. Problem with stored expansion: " + capabilityName, e); + game.getUserInterface().showWarning(_("Load error"), _("Saved game is incompatible or file is corrupted. Game couldn't work properly.")); + } + } + } + + public Set getCustomRules() { + Set result = new HashSet<>(); + NodeList nl = root.getElementsByTagName("rule"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + CustomRule rule = CustomRule.valueOf(el.getAttribute("name")); + result.add(rule); + } + return result; + } + + public List getPlayers() { + List players = new ArrayList<>(); + NodeList nl = getSecondLevelElelents("players", "player"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + PlayerSlot slot = new PlayerSlot(Integer.parseInt(el.getAttribute("slot"))); + Player p = new Player(el.getAttribute("name"), i, slot); + p.setPoints(Integer.parseInt(el.getAttribute("points"))); + if (el.hasAttribute("ai-class")) { + slot.setType(SlotType.AI); + String aiClassName = el.getAttribute("ai-class"); + slot.setAiClassName(aiClassName); + } else { + if (el.hasAttribute("local")) { + slot.setType(SlotType.PLAYER); + } + } + players.add(p); + } + return players; + } + + public PlayerSlot[] getPlayerSlots() { + List players = getPlayers(); + int maxSlotNumber = 0; + for (Player player : players) { + int slotNumber = player.getSlot().getNumber(); + if (slotNumber > maxSlotNumber) maxSlotNumber = slotNumber; + } + + PlayerSlot[] slots = new PlayerSlot[maxSlotNumber+1]; + for (int i = 0; i < slots.length; i++) { + for (Player player : players) { + PlayerSlot slot = player.getSlot(); + if (slot.getNumber() == i) { + slot.setNick(player.getNick()); + slots[i] = slot; + break; + } + } + } + return slots; + } + + public int getTurnPlayer() { + Element el = (Element) doc.getElementsByTagName("players").item(0); + return Integer.parseInt(el.getAttribute("turn")); + } + + public List getActiveGroups() { + List result = new ArrayList<>(); + NodeList nl = getSecondLevelElelents("tiles", "group"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + if (Boolean.parseBoolean(el.getAttribute("active"))) { + result.add(el.getAttribute("name")); + } + } + return result; + } + + public List getDiscardedTiles() { + List result = new ArrayList<>(); + NodeList nl = getSecondLevelElelents("tiles", "discard"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + result.add(el.getAttribute("name")); + } + return result; + } + + public Rotation extractTileRotation(Element el) { + return Rotation.valueOf(el.getAttribute("rotation")); + } + + @SuppressWarnings("unchecked") + public List extractTileMeeples(Element tileEl, Game game, Position pos) throws SnapshotCorruptedException { + NodeList nl = tileEl.getElementsByTagName("meeple"); + List result = new ArrayList<>(); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + Location loc = Location.valueOf(el.getAttribute("loc")); + Class mt = (Class) XmlUtils.classForName(el.getAttribute("type")); + int playerIndex = Integer.parseInt(el.getAttribute("player")); + Meeple meeple = game.getPlayer(playerIndex).getMeepleFromSupply(mt); + meeple.setLocation(loc); + meeple.setPosition(pos); + //don't set feature here. Feature must be set after meeple deployment to correct replace ref during merge + result.add(meeple); + } + return result; + } + + public NodeList getTileElements() { + return getSecondLevelElelents("tiles", "tile"); + } + + public String getNextTile() { + Element el = (Element) root.getElementsByTagName("tiles").item(0); + return el.getAttribute("next"); + } + + @SuppressWarnings("unchecked") + public Class getActivePhase() throws SnapshotCorruptedException { + return (Class) XmlUtils.classForName(root.getAttribute("phase")); + } + + public Game asGame() { + Game game = new Game(); + game.getExpansions().addAll(getExpansions()); + game.getCustomRules().addAll(getCustomRules()); + game.setPlayers(getPlayers(), getTurnPlayer()); + return game; + } + + private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { + String xml = (String) stream.readObject(); + InputStream is = new ByteArrayInputStream(xml.getBytes()); + load(is); + logger = LoggerFactory.getLogger(getClass()); + } + + private void writeObject(java.io.ObjectOutputStream stream) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + //StreamResult streamResult = new StreamResult(new ZipOutputStream(os)); + StreamResult streamResult = new StreamResult(os); + TransformerFactory tf = TransformerFactory.newInstance(); + try { + Transformer serializer = tf.newTransformer(); + serializer.transform(new DOMSource(doc), streamResult); + stream.writeObject(os.toString()); + } catch (TransformerException e) { + throw new IOException(e); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/SnapshotCorruptedException.java b/src/main/java/com/jcloisterzone/game/SnapshotCorruptedException.java index 533fed760..71710fc69 100644 --- a/src/main/java/com/jcloisterzone/game/SnapshotCorruptedException.java +++ b/src/main/java/com/jcloisterzone/game/SnapshotCorruptedException.java @@ -1,21 +1,21 @@ -package com.jcloisterzone.game; - -public class SnapshotCorruptedException extends RuntimeException { - - public SnapshotCorruptedException() { - super(); - } - - public SnapshotCorruptedException(String message, Throwable cause) { - super(message, cause); - } - - public SnapshotCorruptedException(String message) { - super(message); - } - - public SnapshotCorruptedException(Throwable cause) { - super(cause); - } - -} +package com.jcloisterzone.game; + +public class SnapshotCorruptedException extends RuntimeException { + + public SnapshotCorruptedException() { + super(); + } + + public SnapshotCorruptedException(String message, Throwable cause) { + super(message, cause); + } + + public SnapshotCorruptedException(String message) { + super(message); + } + + public SnapshotCorruptedException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/SnapshotVersionException.java b/src/main/java/com/jcloisterzone/game/SnapshotVersionException.java index 61f03e16a..a5beb78e9 100644 --- a/src/main/java/com/jcloisterzone/game/SnapshotVersionException.java +++ b/src/main/java/com/jcloisterzone/game/SnapshotVersionException.java @@ -1,9 +1,9 @@ -package com.jcloisterzone.game; - -public class SnapshotVersionException extends RuntimeException { - - public SnapshotVersionException(String message) { - super(message); - } - -} +package com.jcloisterzone.game; + +public class SnapshotVersionException extends RuntimeException { + + public SnapshotVersionException(String message) { + super(message); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/AbbeyCapability.java b/src/main/java/com/jcloisterzone/game/capability/AbbeyCapability.java index fac9220aa..99e68f834 100644 --- a/src/main/java/com/jcloisterzone/game/capability/AbbeyCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/AbbeyCapability.java @@ -1,79 +1,79 @@ -package com.jcloisterzone.game.capability; - -import java.util.HashSet; -import java.util.Set; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class AbbeyCapability extends Capability { - - private final Set unusedAbbey = new HashSet<>(); - - public AbbeyCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return new HashSet<>(unusedAbbey); - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - unusedAbbey.clear(); - unusedAbbey.addAll((Set) data); - } - - @Override - public void initPlayer(Player player) { - unusedAbbey.add(player); - } - - @Override - public String getTileGroup(Tile tile) { - return tile.getId().equals(Tile.ABBEY_TILE_ID) ? "inactive": null; - } - - public boolean hasUnusedAbbey(Player player) { - return unusedAbbey.contains(player); - } - - public void useAbbey(Player player) { - if (!unusedAbbey.remove(player)) { - throw new IllegalArgumentException("Player alredy used his abbey"); - } - } - - - - @Override - public void saveToSnapshot(Document doc, Element node) { - for (Player player: game.getAllPlayers()) { - Element el = doc.createElement("player"); - node.appendChild(el); - el.setAttribute("index", "" + player.getIndex()); - el.setAttribute("abbey", "" + unusedAbbey.contains(player)); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("player"); - for (int i = 0; i < nl.getLength(); i++) { - Element playerEl = (Element) nl.item(i); - Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); - if (!Boolean.parseBoolean(playerEl.getAttribute("abbey"))) { - useAbbey(player); - } - } - } - -} +package com.jcloisterzone.game.capability; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class AbbeyCapability extends Capability { + + private final Set unusedAbbey = new HashSet<>(); + + public AbbeyCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return new HashSet<>(unusedAbbey); + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + unusedAbbey.clear(); + unusedAbbey.addAll((Set) data); + } + + @Override + public void initPlayer(Player player) { + unusedAbbey.add(player); + } + + @Override + public String getTileGroup(Tile tile) { + return tile.getId().equals(Tile.ABBEY_TILE_ID) ? "inactive": null; + } + + public boolean hasUnusedAbbey(Player player) { + return unusedAbbey.contains(player); + } + + public void useAbbey(Player player) { + if (!unusedAbbey.remove(player)) { + throw new IllegalArgumentException("Player alredy used his abbey"); + } + } + + + + @Override + public void saveToSnapshot(Document doc, Element node) { + for (Player player: game.getAllPlayers()) { + Element el = doc.createElement("player"); + node.appendChild(el); + el.setAttribute("index", "" + player.getIndex()); + el.setAttribute("abbey", "" + unusedAbbey.contains(player)); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("player"); + for (int i = 0; i < nl.getLength(); i++) { + Element playerEl = (Element) nl.item(i); + Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); + if (!Boolean.parseBoolean(playerEl.getAttribute("abbey"))) { + useAbbey(player); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/BarnCapability.java b/src/main/java/com/jcloisterzone/game/capability/BarnCapability.java index 51ab85e57..510353364 100644 --- a/src/main/java/com/jcloisterzone/game/capability/BarnCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/BarnCapability.java @@ -1,75 +1,75 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.BarnAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.visitor.IsOccupied; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; - - -public final class BarnCapability extends Capability { - - public BarnCapability(Game game) { - super(game); - } - - @Override - public void initPlayer(Player player) { - /*if (game.hasCapability(Capability.FARM_PLACEMENT)) { - player.addMeeple(new Barn(game, player)); - }*/ - player.addMeeple(new Barn(game, player)); - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - Position pos = getTile().getPosition(); - - if (game.getActivePlayer().hasSpecialMeeple(Barn.class)) { - BarnAction barnAction = null; - Location corner = Location.WR.union(Location.NL); - Location positionChange = Location.W; - for (int i = 0; i < 4; i++) { - if (isBarnCorner(corner, positionChange)) { - if (barnAction == null) { - barnAction = new BarnAction(); - actions.add(barnAction); - } - barnAction.getOrCreate(pos).add(corner); - } - corner = corner.next(); - positionChange = positionChange.next(); - } - } - } - - private boolean isBarnCorner(Location corner, Location positionChange) { - Farm farm = null; - Position pos = getTile().getPosition(); - for (int i = 0; i < 4; i++) { - Tile tile = getBoard().get(pos); - if (tile == null) return false; - farm = (Farm) tile.getFeaturePartOf(corner); - if (farm == null) return false; - corner = corner.next(); - pos = pos.add(positionChange); - positionChange = positionChange.next(); - } - - if (!game.hasRule(CustomRule.MULTI_BARN_ALLOWED)) { - return !farm.walk(new IsOccupied().with(Barn.class)); - } - - return true; - } +package com.jcloisterzone.game.capability; + +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.BarnAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.visitor.IsOccupied; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; + + +public final class BarnCapability extends Capability { + + public BarnCapability(Game game) { + super(game); + } + + @Override + public void initPlayer(Player player) { + /*if (game.hasCapability(Capability.FARM_PLACEMENT)) { + player.addMeeple(new Barn(game, player)); + }*/ + player.addMeeple(new Barn(game, player)); + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + Position pos = getTile().getPosition(); + + if (game.getActivePlayer().hasSpecialMeeple(Barn.class)) { + BarnAction barnAction = null; + Location corner = Location.WR.union(Location.NL); + Location positionChange = Location.W; + for (int i = 0; i < 4; i++) { + if (isBarnCorner(corner, positionChange)) { + if (barnAction == null) { + barnAction = new BarnAction(); + actions.add(barnAction); + } + barnAction.getOrCreate(pos).add(corner); + } + corner = corner.next(); + positionChange = positionChange.next(); + } + } + } + + private boolean isBarnCorner(Location corner, Location positionChange) { + Farm farm = null; + Position pos = getTile().getPosition(); + for (int i = 0; i < 4; i++) { + Tile tile = getBoard().get(pos); + if (tile == null) return false; + farm = (Farm) tile.getFeaturePartOf(corner); + if (farm == null) return false; + corner = corner.next(); + pos = pos.add(positionChange); + positionChange = positionChange.next(); + } + + if (!game.hasRule(CustomRule.MULTI_BARN_ALLOWED)) { + return !farm.walk(new IsOccupied().with(Barn.class)); + } + + return true; + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/game/capability/BazaarCapability.java b/src/main/java/com/jcloisterzone/game/capability/BazaarCapability.java index 6d88252a8..7c4d4ce11 100644 --- a/src/main/java/com/jcloisterzone/game/capability/BazaarCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/BazaarCapability.java @@ -1,192 +1,192 @@ -package com.jcloisterzone.game.capability; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class BazaarCapability extends Capability { - - private ArrayList bazaarSupply; - private BazaarItem currentBazaarAuction; - private Player bazaarTileSelectingPlayer; - private Player bazaarBiddingPlayer; - - public BazaarCapability(Game game) { - super(game); - } - - @Override - public Object[] backup() { - return new Object[] { - (bazaarSupply == null ? null : new ArrayList<>(bazaarSupply)), - (currentBazaarAuction == null ? null : new BazaarItem(currentBazaarAuction)), - bazaarTileSelectingPlayer, - bazaarBiddingPlayer - }; - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - bazaarSupply = a[0] == null ? null : new ArrayList<>((ArrayList)a[0]); - currentBazaarAuction = a[1] == null ? null : new BazaarItem((BazaarItem)a[1]); - bazaarTileSelectingPlayer = (Player) a[2]; - bazaarBiddingPlayer = (Player) a[3]; - } - - @Override - public void initTile(Tile tile, Element xml) { - if (xml.getElementsByTagName("bazaar").getLength() > 0) { - tile.setTrigger(TileTrigger.BAZAAR); - } - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - if (bazaarSupply != null) { - for (BazaarItem bi : bazaarSupply) { - Element el = doc.createElement("bazaar-supply"); - el.setAttribute("tile", bi.getTile().getId()); - if (bi.getOwner() != null) el.setAttribute("owner", ""+bi.getOwner().getIndex()); - if (bi.getCurrentBidder() != null) el.setAttribute("bidder", ""+bi.getCurrentBidder().getIndex()); - el.setAttribute("price", ""+bi.getCurrentPrice()); - - if (currentBazaarAuction == bi) { - el.setAttribute("selected", "true"); - } - node.appendChild(el); - } - } - if (bazaarTileSelectingPlayer != null) { - Element el = doc.createElement("bazaar-selecting-player"); - el.setAttribute("player", ""+bazaarTileSelectingPlayer.getIndex()); - node.appendChild(el); - } - if (bazaarBiddingPlayer != null) { - Element el = doc.createElement("bazaar-bidding-player"); - el.setAttribute("player", ""+bazaarBiddingPlayer.getIndex()); - node.appendChild(el); - } - } - - - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("bazaar-supply"); - if (nl.getLength() > 0) { - bazaarSupply = new ArrayList(nl.getLength()); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - Tile tile = game.getTilePack().drawTile(el.getAttribute("tile")); - BazaarItem bi = new BazaarItem(tile); - bazaarSupply.add(bi); - if (el.hasAttribute("owner")) bi.setOwner(game.getPlayer(Integer.parseInt(el.getAttribute("owner")))); - if (el.hasAttribute("bidder")) bi.setCurrentBidder(game.getPlayer(Integer.parseInt(el.getAttribute("bidder")))); - bi.setCurrentPrice(XmlUtils.attributeIntValue(el, "price")); - if (XmlUtils.attributeBoolValue(el, "selected")) { - currentBazaarAuction = bi; - } - } - } - - nl = node.getElementsByTagName("bazaar-selecting-player"); - if (nl.getLength() > 0) { - Element el = (Element) nl.item(0); - bazaarTileSelectingPlayer = game.getPlayer(Integer.parseInt(el.getAttribute("player"))); - } - nl = node.getElementsByTagName("bazaar-bidding-player"); - if (nl.getLength() > 0) { - Element el = (Element) nl.item(0); - bazaarBiddingPlayer = game.getPlayer(Integer.parseInt(el.getAttribute("player"))); - } - } - - public ArrayList getBazaarSupply() { - return bazaarSupply; - } - - public void setBazaarSupply(ArrayList bazaarSupply) { - this.bazaarSupply = bazaarSupply; - } - - public Player getBazaarTileSelectingPlayer() { - return bazaarTileSelectingPlayer; - } - - public void setBazaarTileSelectingPlayer(Player bazaarTileSelectingPlayer) { - this.bazaarTileSelectingPlayer = bazaarTileSelectingPlayer; - } - - public Player getBazaarBiddingPlayer() { - return bazaarBiddingPlayer; - } - - public void setBazaarBiddingPlayer(Player bazaarBiddingPlayer) { - this.bazaarBiddingPlayer = bazaarBiddingPlayer; - } - - public BazaarItem getCurrentBazaarAuction() { - return currentBazaarAuction; - } - - public void setCurrentBazaarAuction(BazaarItem currentBazaarAuction) { - this.currentBazaarAuction = currentBazaarAuction; - } - - public boolean hasTileAuctioned(Player p) { - for (BazaarItem bi : bazaarSupply) { - if (bi.getOwner() == p) return true; - } - return false; - } - - public Tile drawNextTile() { - if (bazaarSupply == null) return null; - Player p = game.getActivePlayer(); - Tile tile = null; - BazaarItem currentItem = null; - for (BazaarItem bi : bazaarSupply) { - if (bi.getOwner() == p) { - currentItem = bi; - tile = bi.getTile(); - break; - } - } - bazaarSupply.remove(currentItem); - if (bazaarSupply.isEmpty()) { - bazaarSupply = null; - } - return tile; - } - - public List getDrawQueue() { - if (bazaarSupply == null) return Collections.emptyList(); - List result = new ArrayList<>(); - Player turnPlayer = game.getTurnPlayer(); - Player p = game.getNextPlayer(turnPlayer); - while (p != turnPlayer) { - for (BazaarItem bi : bazaarSupply) { - if (bi.getOwner() == p) { - result.add(bi.getTile()); - break; - } - } - p = game.getNextPlayer(p); - } - return result; - } - +package com.jcloisterzone.game.capability; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class BazaarCapability extends Capability { + + private ArrayList bazaarSupply; + private BazaarItem currentBazaarAuction; + private Player bazaarTileSelectingPlayer; + private Player bazaarBiddingPlayer; + + public BazaarCapability(Game game) { + super(game); + } + + @Override + public Object[] backup() { + return new Object[] { + (bazaarSupply == null ? null : new ArrayList<>(bazaarSupply)), + (currentBazaarAuction == null ? null : new BazaarItem(currentBazaarAuction)), + bazaarTileSelectingPlayer, + bazaarBiddingPlayer + }; + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + bazaarSupply = a[0] == null ? null : new ArrayList<>((ArrayList)a[0]); + currentBazaarAuction = a[1] == null ? null : new BazaarItem((BazaarItem)a[1]); + bazaarTileSelectingPlayer = (Player) a[2]; + bazaarBiddingPlayer = (Player) a[3]; + } + + @Override + public void initTile(Tile tile, Element xml) { + if (xml.getElementsByTagName("bazaar").getLength() > 0) { + tile.setTrigger(TileTrigger.BAZAAR); + } + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + if (bazaarSupply != null) { + for (BazaarItem bi : bazaarSupply) { + Element el = doc.createElement("bazaar-supply"); + el.setAttribute("tile", bi.getTile().getId()); + if (bi.getOwner() != null) el.setAttribute("owner", ""+bi.getOwner().getIndex()); + if (bi.getCurrentBidder() != null) el.setAttribute("bidder", ""+bi.getCurrentBidder().getIndex()); + el.setAttribute("price", ""+bi.getCurrentPrice()); + + if (currentBazaarAuction == bi) { + el.setAttribute("selected", "true"); + } + node.appendChild(el); + } + } + if (bazaarTileSelectingPlayer != null) { + Element el = doc.createElement("bazaar-selecting-player"); + el.setAttribute("player", ""+bazaarTileSelectingPlayer.getIndex()); + node.appendChild(el); + } + if (bazaarBiddingPlayer != null) { + Element el = doc.createElement("bazaar-bidding-player"); + el.setAttribute("player", ""+bazaarBiddingPlayer.getIndex()); + node.appendChild(el); + } + } + + + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("bazaar-supply"); + if (nl.getLength() > 0) { + bazaarSupply = new ArrayList(nl.getLength()); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + Tile tile = game.getTilePack().drawTile(el.getAttribute("tile")); + BazaarItem bi = new BazaarItem(tile); + bazaarSupply.add(bi); + if (el.hasAttribute("owner")) bi.setOwner(game.getPlayer(Integer.parseInt(el.getAttribute("owner")))); + if (el.hasAttribute("bidder")) bi.setCurrentBidder(game.getPlayer(Integer.parseInt(el.getAttribute("bidder")))); + bi.setCurrentPrice(XmlUtils.attributeIntValue(el, "price")); + if (XmlUtils.attributeBoolValue(el, "selected")) { + currentBazaarAuction = bi; + } + } + } + + nl = node.getElementsByTagName("bazaar-selecting-player"); + if (nl.getLength() > 0) { + Element el = (Element) nl.item(0); + bazaarTileSelectingPlayer = game.getPlayer(Integer.parseInt(el.getAttribute("player"))); + } + nl = node.getElementsByTagName("bazaar-bidding-player"); + if (nl.getLength() > 0) { + Element el = (Element) nl.item(0); + bazaarBiddingPlayer = game.getPlayer(Integer.parseInt(el.getAttribute("player"))); + } + } + + public ArrayList getBazaarSupply() { + return bazaarSupply; + } + + public void setBazaarSupply(ArrayList bazaarSupply) { + this.bazaarSupply = bazaarSupply; + } + + public Player getBazaarTileSelectingPlayer() { + return bazaarTileSelectingPlayer; + } + + public void setBazaarTileSelectingPlayer(Player bazaarTileSelectingPlayer) { + this.bazaarTileSelectingPlayer = bazaarTileSelectingPlayer; + } + + public Player getBazaarBiddingPlayer() { + return bazaarBiddingPlayer; + } + + public void setBazaarBiddingPlayer(Player bazaarBiddingPlayer) { + this.bazaarBiddingPlayer = bazaarBiddingPlayer; + } + + public BazaarItem getCurrentBazaarAuction() { + return currentBazaarAuction; + } + + public void setCurrentBazaarAuction(BazaarItem currentBazaarAuction) { + this.currentBazaarAuction = currentBazaarAuction; + } + + public boolean hasTileAuctioned(Player p) { + for (BazaarItem bi : bazaarSupply) { + if (bi.getOwner() == p) return true; + } + return false; + } + + public Tile drawNextTile() { + if (bazaarSupply == null) return null; + Player p = game.getActivePlayer(); + Tile tile = null; + BazaarItem currentItem = null; + for (BazaarItem bi : bazaarSupply) { + if (bi.getOwner() == p) { + currentItem = bi; + tile = bi.getTile(); + break; + } + } + bazaarSupply.remove(currentItem); + if (bazaarSupply.isEmpty()) { + bazaarSupply = null; + } + return tile; + } + + public List getDrawQueue() { + if (bazaarSupply == null) return Collections.emptyList(); + List result = new ArrayList<>(); + Player turnPlayer = game.getTurnPlayer(); + Player p = game.getNextPlayer(turnPlayer); + while (p != turnPlayer) { + for (BazaarItem bi : bazaarSupply) { + if (bi.getOwner() == p) { + result.add(bi.getTile()); + break; + } + } + p = game.getNextPlayer(p); + } + return result; + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/game/capability/BazaarItem.java b/src/main/java/com/jcloisterzone/game/capability/BazaarItem.java index e1a9a29f6..769784690 100644 --- a/src/main/java/com/jcloisterzone/game/capability/BazaarItem.java +++ b/src/main/java/com/jcloisterzone/game/capability/BazaarItem.java @@ -1,61 +1,61 @@ -package com.jcloisterzone.game.capability; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Tile; - -public class BazaarItem { - - private final Tile tile; - private Player owner; - - private int currentPrice; - private Player currentBidder; - - - public BazaarItem(Tile tile) { - this.tile = tile; - } - - public BazaarItem(BazaarItem bi) { - tile = bi.tile; - owner = bi.owner; - currentPrice = bi.currentPrice; - currentBidder = bi.currentBidder; - } - - public Player getOwner() { - return owner; - } - - public void setOwner(Player owner) { - this.owner = owner; - } - - public Tile getTile() { - return tile; - } - - public int getCurrentPrice() { - return currentPrice; - } - - public void setCurrentPrice(int currentPrice) { - this.currentPrice = currentPrice; - } - - public Player getCurrentBidder() { - return currentBidder; - } - - public void setCurrentBidder(Player currentBidder) { - this.currentBidder = currentBidder; - } - - @Override - public String toString() { - return "BazaarItem [tile=" + tile + ", owner=" + owner - + ", currentPrice=" + currentPrice + ", currentBidder=" - + currentBidder + "]"; - } - -} +package com.jcloisterzone.game.capability; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Tile; + +public class BazaarItem { + + private final Tile tile; + private Player owner; + + private int currentPrice; + private Player currentBidder; + + + public BazaarItem(Tile tile) { + this.tile = tile; + } + + public BazaarItem(BazaarItem bi) { + tile = bi.tile; + owner = bi.owner; + currentPrice = bi.currentPrice; + currentBidder = bi.currentBidder; + } + + public Player getOwner() { + return owner; + } + + public void setOwner(Player owner) { + this.owner = owner; + } + + public Tile getTile() { + return tile; + } + + public int getCurrentPrice() { + return currentPrice; + } + + public void setCurrentPrice(int currentPrice) { + this.currentPrice = currentPrice; + } + + public Player getCurrentBidder() { + return currentBidder; + } + + public void setCurrentBidder(Player currentBidder) { + this.currentBidder = currentBidder; + } + + @Override + public String toString() { + return "BazaarItem [tile=" + tile + ", owner=" + owner + + ", currentPrice=" + currentPrice + ", currentBidder=" + + currentBidder + "]"; + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/BigFollowerCapability.java b/src/main/java/com/jcloisterzone/game/capability/BigFollowerCapability.java index 8cc46da53..275a89f03 100644 --- a/src/main/java/com/jcloisterzone/game/capability/BigFollowerCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/BigFollowerCapability.java @@ -1,37 +1,37 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.figure.BigFollower; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class BigFollowerCapability extends Capability { - - public BigFollowerCapability(Game game) { - super(game); - } - - @Override - public void initPlayer(Player player) { - player.addMeeple(new BigFollower(game, player)); - } - - @Override - public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { - if (game.getActivePlayer().hasFollower(BigFollower.class) && !followerLocMap.isEmpty()) { - actions.add(new MeepleAction(BigFollower.class, followerLocMap)); - } - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - prepareFollowerActions(actions, commonSites); - } - - -} +package com.jcloisterzone.game.capability; + +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.figure.BigFollower; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class BigFollowerCapability extends Capability { + + public BigFollowerCapability(Game game) { + super(game); + } + + @Override + public void initPlayer(Player player) { + player.addMeeple(new BigFollower(game, player)); + } + + @Override + public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { + if (game.getActivePlayer().hasFollower(BigFollower.class) && !followerLocMap.isEmpty()) { + actions.add(new MeepleAction(BigFollower.class, followerLocMap)); + } + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + prepareFollowerActions(actions, commonSites); + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/BridgeCapability.java b/src/main/java/com/jcloisterzone/game/capability/BridgeCapability.java index 385d0f49f..bec7ce7ed 100644 --- a/src/main/java/com/jcloisterzone/game/capability/BridgeCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/BridgeCapability.java @@ -1,243 +1,243 @@ -package com.jcloisterzone.game.capability; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.BridgeAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class BridgeCapability extends Capability { - - private boolean bridgeUsed; - private final Map bridges = new HashMap<>(); - - public BridgeCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return new Object[] { - bridgeUsed, - new HashMap<>(bridges) - }; - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - bridgeUsed = (Boolean) a[0]; - bridges.clear(); - bridges.putAll((Map) a[1]); - } - - - @Override - public void initPlayer(Player player) { - int players = game.getAllPlayers().length; - if (players < 5) { - bridges.put(player, 3); - } else { - bridges.put(player, 2); - } - } - - @Override - public void turnCleanUp() { - bridgeUsed = false; - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - if (!bridgeUsed && getPlayerBridges(game.getPhase().getActivePlayer()) > 0) { - BridgeAction action = prepareBridgeAction(); - if (action != null) { - actions.add(action); - } - } - } - - public BridgeAction prepareMandatoryBridgeAction() { - Tile tile = game.getCurrentTile(); - for (Entry entry : getBoard().getAdjacentTilesMap(tile.getPosition()).entrySet()) { - Tile adjacent = entry.getValue(); - Location rel = entry.getKey(); - - char adjacentSide = adjacent.getEdge(rel.rev()); - char tileSide = tile.getEdge(rel); - if (tileSide != adjacentSide) { - Location bridgeLoc = getBridgeLocationForAdjacent(rel); - BridgeAction action = prepareTileBridgeAction(tile, null, bridgeLoc); - if (action != null) return action; - return prepareTileBridgeAction(adjacent, null, bridgeLoc); - } - } - throw new IllegalStateException(); - } - - private Location getBridgeLocationForAdjacent(Location rel) { - if (rel == Location.N || rel == Location.S) { - return Location.NS; - } else { - return Location.WE; - } - } - - private BridgeAction prepareBridgeAction() { - BridgeAction action = null; - Tile tile = game.getCurrentTile(); - action = prepareTileBridgeAction(tile, action, Location.NS); - action = prepareTileBridgeAction(tile, action, Location.WE); - for (Entry entry : getBoard().getAdjacentTilesMap(tile.getPosition()).entrySet()) { - Tile adjacent = entry.getValue(); - Location rel = entry.getKey(); - action = prepareTileBridgeAction(adjacent, action, getBridgeLocationForAdjacent(rel)); - } - return action; - } - - private BridgeAction prepareTileBridgeAction(Tile tile, BridgeAction action, Location bridgeLoc) { - if (isBridgePlacementAllowed(tile, tile.getPosition(), bridgeLoc)) { - if (action == null) action = new BridgeAction(); - action.getLocationsMap().getOrCreate(tile.getPosition()).add(bridgeLoc); - } - return action; - } - - private boolean isBridgePlacementAllowed(Tile tile, Position p, Location bridgeLoc) { - if (!tile.isBridgeAllowed(bridgeLoc)) return false; - for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { - Location rel = e.getKey(); - if (rel.intersect(bridgeLoc) != null) { - Tile adjacent = e.getValue(); - char adjacentSide = adjacent.getEdge(rel.rev()); - if (adjacentSide != 'R') return false; - } - } - return true; - } - - public boolean isTilePlacementWithBridgePossible(Tile tile, Position p) { - if (getPlayerBridges(game.getActivePlayer()) > 0) { - if (isTilePlacementWithBridgeAllowed(tile, p, Location.NS)) return true; - if (isTilePlacementWithBridgeAllowed(tile, p, Location.WE)) return true; - if (isTilePlacementWithOneAdjacentBridgeAllowed(tile, p)) return true; - } - return false; - } - - private boolean isTilePlacementWithBridgeAllowed(Tile tile, Position p, Location bridgeLoc) { - if (!tile.isBridgeAllowed(bridgeLoc)) return false; - - for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { - Tile adjacent = e.getValue(); - Location rel = e.getKey(); - - char adjacentSide = adjacent.getEdge(rel.rev()); - char tileSide = tile.getEdge(rel); - if (rel.intersect(bridgeLoc) != null) { - if (adjacentSide != 'R') return false; - } else { - if (adjacentSide != tileSide) return false; - } - } - return true; - } - - private boolean isTilePlacementWithOneAdjacentBridgeAllowed(Tile tile, Position p) { - boolean bridgeUsed = false; - for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { - Tile adjacent = e.getValue(); - Location rel = e.getKey(); - - char tileSide = tile.getEdge(rel); - char adjacentSide = adjacent.getEdge(rel.rev()); - - if (tileSide != adjacentSide) { - if (bridgeUsed) return false; - if (tileSide != 'R') return false; - - Location bridgeLoc = getBridgeLocationForAdjacent(rel); - if (!isBridgePlacementAllowed(adjacent, adjacent.getPosition(), bridgeLoc)) return false; - bridgeUsed = true; - } - } - return bridgeUsed; //ok if exactly one bridge is used - } - - public int getPlayerBridges(Player pl) { - return bridges.get(pl); - } - - public void decreaseBridges(Player player) { - int n = getPlayerBridges(player); - if (n == 0) throw new IllegalStateException("Player has no bridges"); - bridges.put(player, n-1); - } - - public void deployBridge(Position pos, Location loc) { - Tile tile = getBoard().get(pos); - if (!tile.isBridgeAllowed(loc)) { - throw new IllegalArgumentException("Cannot deploy " + loc + " bridge on " + pos); - } - bridgeUsed = true; - tile.placeBridge(loc); - game.fireGameEvent().bridgeDeployed(pos, loc); - } - - - - @Override - public void saveTileToSnapshot(Tile tile, Document doc, Element tileNode) { - if (tile.getBridge() != null) { - Location realLoc = tile.getBridge().getRawLocation(); - tileNode.setAttribute("bridge", realLoc.toString()); - } - } - - @Override - public void loadTileFromSnapshot(Tile tile, Element tileNode) { - if (tileNode.hasAttribute("bridge")) { - Location loc = Location.valueOf(tileNode.getAttribute("bridge")); - tile.placeBridge(loc); - } - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - node.setAttribute("bridgeUsed", bridgeUsed + ""); - for (Player player: game.getAllPlayers()) { - Element el = doc.createElement("player"); - node.appendChild(el); - el.setAttribute("index", "" + player.getIndex()); - el.setAttribute("bridges", "" + getPlayerBridges(player)); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - bridgeUsed = Boolean.parseBoolean(node.getAttribute("bridgeUsed")); - NodeList nl = node.getElementsByTagName("player"); - for (int i = 0; i < nl.getLength(); i++) { - Element playerEl = (Element) nl.item(i); - Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); - bridges.put(player, Integer.parseInt(playerEl.getAttribute("bridges"))); - } - } - - -} +package com.jcloisterzone.game.capability; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.BridgeAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class BridgeCapability extends Capability { + + private boolean bridgeUsed; + private final Map bridges = new HashMap<>(); + + public BridgeCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return new Object[] { + bridgeUsed, + new HashMap<>(bridges) + }; + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + bridgeUsed = (Boolean) a[0]; + bridges.clear(); + bridges.putAll((Map) a[1]); + } + + + @Override + public void initPlayer(Player player) { + int players = game.getAllPlayers().length; + if (players < 5) { + bridges.put(player, 3); + } else { + bridges.put(player, 2); + } + } + + @Override + public void turnCleanUp() { + bridgeUsed = false; + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + if (!bridgeUsed && getPlayerBridges(game.getPhase().getActivePlayer()) > 0) { + BridgeAction action = prepareBridgeAction(); + if (action != null) { + actions.add(action); + } + } + } + + public BridgeAction prepareMandatoryBridgeAction() { + Tile tile = game.getCurrentTile(); + for (Entry entry : getBoard().getAdjacentTilesMap(tile.getPosition()).entrySet()) { + Tile adjacent = entry.getValue(); + Location rel = entry.getKey(); + + char adjacentSide = adjacent.getEdge(rel.rev()); + char tileSide = tile.getEdge(rel); + if (tileSide != adjacentSide) { + Location bridgeLoc = getBridgeLocationForAdjacent(rel); + BridgeAction action = prepareTileBridgeAction(tile, null, bridgeLoc); + if (action != null) return action; + return prepareTileBridgeAction(adjacent, null, bridgeLoc); + } + } + throw new IllegalStateException(); + } + + private Location getBridgeLocationForAdjacent(Location rel) { + if (rel == Location.N || rel == Location.S) { + return Location.NS; + } else { + return Location.WE; + } + } + + private BridgeAction prepareBridgeAction() { + BridgeAction action = null; + Tile tile = game.getCurrentTile(); + action = prepareTileBridgeAction(tile, action, Location.NS); + action = prepareTileBridgeAction(tile, action, Location.WE); + for (Entry entry : getBoard().getAdjacentTilesMap(tile.getPosition()).entrySet()) { + Tile adjacent = entry.getValue(); + Location rel = entry.getKey(); + action = prepareTileBridgeAction(adjacent, action, getBridgeLocationForAdjacent(rel)); + } + return action; + } + + private BridgeAction prepareTileBridgeAction(Tile tile, BridgeAction action, Location bridgeLoc) { + if (isBridgePlacementAllowed(tile, tile.getPosition(), bridgeLoc)) { + if (action == null) action = new BridgeAction(); + action.getLocationsMap().getOrCreate(tile.getPosition()).add(bridgeLoc); + } + return action; + } + + private boolean isBridgePlacementAllowed(Tile tile, Position p, Location bridgeLoc) { + if (!tile.isBridgeAllowed(bridgeLoc)) return false; + for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { + Location rel = e.getKey(); + if (rel.intersect(bridgeLoc) != null) { + Tile adjacent = e.getValue(); + char adjacentSide = adjacent.getEdge(rel.rev()); + if (adjacentSide != 'R') return false; + } + } + return true; + } + + public boolean isTilePlacementWithBridgePossible(Tile tile, Position p) { + if (getPlayerBridges(game.getActivePlayer()) > 0) { + if (isTilePlacementWithBridgeAllowed(tile, p, Location.NS)) return true; + if (isTilePlacementWithBridgeAllowed(tile, p, Location.WE)) return true; + if (isTilePlacementWithOneAdjacentBridgeAllowed(tile, p)) return true; + } + return false; + } + + private boolean isTilePlacementWithBridgeAllowed(Tile tile, Position p, Location bridgeLoc) { + if (!tile.isBridgeAllowed(bridgeLoc)) return false; + + for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { + Tile adjacent = e.getValue(); + Location rel = e.getKey(); + + char adjacentSide = adjacent.getEdge(rel.rev()); + char tileSide = tile.getEdge(rel); + if (rel.intersect(bridgeLoc) != null) { + if (adjacentSide != 'R') return false; + } else { + if (adjacentSide != tileSide) return false; + } + } + return true; + } + + private boolean isTilePlacementWithOneAdjacentBridgeAllowed(Tile tile, Position p) { + boolean bridgeUsed = false; + for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { + Tile adjacent = e.getValue(); + Location rel = e.getKey(); + + char tileSide = tile.getEdge(rel); + char adjacentSide = adjacent.getEdge(rel.rev()); + + if (tileSide != adjacentSide) { + if (bridgeUsed) return false; + if (tileSide != 'R') return false; + + Location bridgeLoc = getBridgeLocationForAdjacent(rel); + if (!isBridgePlacementAllowed(adjacent, adjacent.getPosition(), bridgeLoc)) return false; + bridgeUsed = true; + } + } + return bridgeUsed; //ok if exactly one bridge is used + } + + public int getPlayerBridges(Player pl) { + return bridges.get(pl); + } + + public void decreaseBridges(Player player) { + int n = getPlayerBridges(player); + if (n == 0) throw new IllegalStateException("Player has no bridges"); + bridges.put(player, n-1); + } + + public void deployBridge(Position pos, Location loc) { + Tile tile = getBoard().get(pos); + if (!tile.isBridgeAllowed(loc)) { + throw new IllegalArgumentException("Cannot deploy " + loc + " bridge on " + pos); + } + bridgeUsed = true; + tile.placeBridge(loc); + game.fireGameEvent().bridgeDeployed(pos, loc); + } + + + + @Override + public void saveTileToSnapshot(Tile tile, Document doc, Element tileNode) { + if (tile.getBridge() != null) { + Location realLoc = tile.getBridge().getRawLocation(); + tileNode.setAttribute("bridge", realLoc.toString()); + } + } + + @Override + public void loadTileFromSnapshot(Tile tile, Element tileNode) { + if (tileNode.hasAttribute("bridge")) { + Location loc = Location.valueOf(tileNode.getAttribute("bridge")); + tile.placeBridge(loc); + } + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + node.setAttribute("bridgeUsed", bridgeUsed + ""); + for (Player player: game.getAllPlayers()) { + Element el = doc.createElement("player"); + node.appendChild(el); + el.setAttribute("index", "" + player.getIndex()); + el.setAttribute("bridges", "" + getPlayerBridges(player)); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + bridgeUsed = Boolean.parseBoolean(node.getAttribute("bridgeUsed")); + NodeList nl = node.getElementsByTagName("player"); + for (int i = 0; i < nl.getLength(); i++) { + Element playerEl = (Element) nl.item(i); + Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); + bridges.put(player, Integer.parseInt(playerEl.getAttribute("bridges"))); + } + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/BuilderCapability.java b/src/main/java/com/jcloisterzone/game/capability/BuilderCapability.java index 7c17e3d19..ba4f42191 100644 --- a/src/main/java/com/jcloisterzone/game/capability/BuilderCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/BuilderCapability.java @@ -1,104 +1,104 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; -import java.util.Set; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.figure.Builder; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class BuilderCapability extends Capability { - - public enum BuilderState { INACTIVE, ACTIVATED, BUILDER_TURN; } - - protected BuilderState builderState = BuilderState.INACTIVE; - - public BuilderCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return builderState; - } - - @Override - public void restore(Object data) { - builderState = (BuilderState) data; - } - - @Override - public void initPlayer(Player player) { - player.addMeeple(new Builder(game, player)); - } - - public BuilderState getBuilderState() { - return builderState; - } - - public void useBuilder() { - if (builderState == BuilderState.INACTIVE) { - builderState = BuilderState.ACTIVATED; - } - } - - public boolean hasPlayerAnotherTurn() { - return builderState == BuilderState.ACTIVATED; - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - Player player = game.getActivePlayer(); - if (!player.hasSpecialMeeple(Builder.class)) return; - - Tile tile = getTile(); - if (!game.isDeployAllowed(tile, Builder.class)) return; - - Set roads = tile.getPlayerFeatures(player, Road.class); - Set cities = tile.getPlayerFeatures(player, City.class); - if (roads.isEmpty() && cities.isEmpty()) return; - - Position pos = tile.getPosition(); - MeepleAction builderAction = new MeepleAction(Builder.class); - - builderAction.getOrCreate(pos).addAll(roads); - builderAction.getOrCreate(pos).addAll(cities); - actions.add(builderAction); - - } - - @Override - public void turnCleanUp() { - switch (builderState) { - case ACTIVATED: - builderState = BuilderState.BUILDER_TURN; - break; - case BUILDER_TURN: - builderState = BuilderState.INACTIVE; - break; - } - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - node.setAttribute("builderState", builderState.name()); - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - builderState = BuilderState.valueOf(node.getAttribute("builderState")); - } - -} +package com.jcloisterzone.game.capability; + +import java.util.List; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.figure.Builder; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class BuilderCapability extends Capability { + + public enum BuilderState { INACTIVE, ACTIVATED, BUILDER_TURN; } + + protected BuilderState builderState = BuilderState.INACTIVE; + + public BuilderCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return builderState; + } + + @Override + public void restore(Object data) { + builderState = (BuilderState) data; + } + + @Override + public void initPlayer(Player player) { + player.addMeeple(new Builder(game, player)); + } + + public BuilderState getBuilderState() { + return builderState; + } + + public void useBuilder() { + if (builderState == BuilderState.INACTIVE) { + builderState = BuilderState.ACTIVATED; + } + } + + public boolean hasPlayerAnotherTurn() { + return builderState == BuilderState.ACTIVATED; + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + Player player = game.getActivePlayer(); + if (!player.hasSpecialMeeple(Builder.class)) return; + + Tile tile = getTile(); + if (!game.isDeployAllowed(tile, Builder.class)) return; + + Set roads = tile.getPlayerFeatures(player, Road.class); + Set cities = tile.getPlayerFeatures(player, City.class); + if (roads.isEmpty() && cities.isEmpty()) return; + + Position pos = tile.getPosition(); + MeepleAction builderAction = new MeepleAction(Builder.class); + + builderAction.getOrCreate(pos).addAll(roads); + builderAction.getOrCreate(pos).addAll(cities); + actions.add(builderAction); + + } + + @Override + public void turnCleanUp() { + switch (builderState) { + case ACTIVATED: + builderState = BuilderState.BUILDER_TURN; + break; + case BUILDER_TURN: + builderState = BuilderState.INACTIVE; + break; + } + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + node.setAttribute("builderState", builderState.name()); + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + builderState = BuilderState.valueOf(node.getAttribute("builderState")); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/CastleCapability.java b/src/main/java/com/jcloisterzone/game/capability/CastleCapability.java index f27621ed2..e3561177b 100644 --- a/src/main/java/com/jcloisterzone/game/capability/CastleCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/CastleCapability.java @@ -1,272 +1,272 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.attributeBoolValue; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class CastleCapability extends Capability { - - private final Map castles = new HashMap<>(); - - private Player castlePlayer; - private Map> currentTileCastleBases = null; - - /** castles deployed this turn - cannot be scored - refs to master feature */ - private final List newCastles = new ArrayList<>(); - /** empty castles, already scored, keeping ref for game save */ - private final List emptyCastles = new ArrayList<>(); - /** castles from previous turns, can be scored - castle -> vinicity area */ - private final Map scoreableCastleVicinity = new HashMap<>(); - private final Map castleScore = new HashMap<>(); - - public CastleCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - throw new UnsupportedOperationException(); - } - - @Override - public void restore(Object data) { - throw new UnsupportedOperationException(); - } - - @Override - public void castleDeployed(Castle castle1, Castle castle2) { - newCastles.add(castle1.getMaster()); - } - - @Override - public void undeployed(Meeple meeple) { - if (meeple.getFeature() instanceof Castle) { - Castle castle = (Castle) meeple.getFeature().getMaster(); - scoreableCastleVicinity.remove(castle); - emptyCastles.add(castle); - } - } - - - - @Override - public void initPlayer(Player player) { - int players = game.getAllPlayers().length; - if (players < 5) { - castles.put(player, 3); - } else { - castles.put(player, 2); - } - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof City) { - ((City) feature).setCastleBase(attributeBoolValue(xml, "castle-base")); - } - } - - private void checkCastleVicinity(Iterable triggerPositions, int score) { - for (Position p : triggerPositions) { - for (Entry entry : scoreableCastleVicinity.entrySet()) { - Position[] vicinity = entry.getValue(); - for (int i = 0; i < vicinity.length; i++) { - if (vicinity[i].equals(p)) { - Castle master = entry.getKey(); - Integer currentCastleScore = castleScore.get(master); - if (currentCastleScore == null || currentCastleScore < score) { - castleScore.put(master, score); - //chain reaction, one completed castle triggers another - checkCastleVicinity(Arrays.asList(master.getCastleBase()), score); - } - break; - } - } - } - } - } - - private Castle replaceCityWithCastle(Tile tile, Location loc) { - ListIterator iter = tile.getFeatures().listIterator(); - City city = null; - while(iter.hasNext()) { - Feature feature = iter.next(); - if (feature.getLocation() == loc) { - city = (City) feature; - break; - } - } - List meeples = city.getMeeples(); - for (Meeple m : meeples) { - m.undeploy(false); - } - Castle castle = new Castle(); - castle.setTile(tile); - castle.setId(game.idSequnceNextVal()); - castle.setLocation(loc.rotateCCW(tile.getRotation())); - iter.set(castle); - - for (Feature f : tile.getFeatures()) { //replace also city references - if (f instanceof Farm) { - Farm farm = (Farm) f; - Feature[] adjoining = farm.getAdjoiningCities(); - if (adjoining != null) { - for (int i = 0; i < adjoining.length; i++) { - if (adjoining[i] == city) { - adjoining[i] = castle; - break; - } - } - } - } - } - - for (Meeple m : meeples) { - m.deploy(tile, loc); - } - return castle; - } - - public Castle convertCityToCastle(Position pos, Location loc) { - Castle castle1 = replaceCityWithCastle(getBoard().get(pos), loc); - Castle castle2 = replaceCityWithCastle(getBoard().get(pos.add(loc)), loc.rev()); - castle1.getEdges()[0] = castle2; - castle2.getEdges()[0] = castle1; - game.fireGameEvent().castleDeployed(castle1, castle2); - return castle1.getMaster(); - } - - @Override - public void scoreCompleted(CompletableScoreContext ctx) { - checkCastleVicinity(ctx.getPositions(), ctx.getPoints()); - } - - public Map getCastleScore() { - return castleScore; - } - - @Override - public void turnCleanUp() { - for (Castle castle: newCastles) { - scoreableCastleVicinity.put(castle, castle.getVicinity()); - } - newCastles.clear(); - castleScore.clear(); - } - - public Player getCastlePlayer() { - return castlePlayer; - } - - public void setCastlePlayer(Player castlePlayer) { - this.castlePlayer = castlePlayer; - } - - public Map> getCurrentTileCastleBases() { - return currentTileCastleBases; - } - - public void setCurrentTileCastleBases(Map> currentTileCastleBases) { - this.currentTileCastleBases = currentTileCastleBases; - } - - - public int getPlayerCastles(Player pl) { - return castles.get(pl); - } - - - public void decreaseCastles(Player player) { - int n = getPlayerCastles(player); - if (n == 0) throw new IllegalStateException("Player has no castles"); - castles.put(player, n-1); - } - - - - private Element createCastleXmlElement(Document doc, Castle castle) { - Element el = doc.createElement("castle"); - el.setAttribute("location", castle.getLocation().toString()); - XmlUtils.injectPosition(el, castle.getTile().getPosition()); - return el; - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - for (Player player: game.getAllPlayers()) { - Element el = doc.createElement("player"); - node.appendChild(el); - el.setAttribute("index", "" + player.getIndex()); - el.setAttribute("castles", "" + getPlayerCastles(player)); - } - - for (Castle castle : scoreableCastleVicinity.keySet()) { - node.appendChild(createCastleXmlElement(doc, castle)); - } - for (Castle castle : newCastles) { - Element el = createCastleXmlElement(doc, castle); - el.setAttribute("new", "true"); - node.appendChild(el); - } - for (Castle castle : emptyCastles) { - Element el = createCastleXmlElement(doc, castle); - el.setAttribute("completed", "true"); - node.appendChild(el); - } - } - - - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("player"); - for (int i = 0; i < nl.getLength(); i++) { - Element playerEl = (Element) nl.item(i); - Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); - castles.put(player, Integer.parseInt(playerEl.getAttribute("castles"))); - } - - nl = node.getElementsByTagName("castle"); - for (int i = 0; i < nl.getLength(); i++) { - Element castleEl = (Element) nl.item(i); - Position pos = XmlUtils.extractPosition(castleEl); - Location loc = Location.valueOf(castleEl.getAttribute("location")); - Castle castle = convertCityToCastle(pos, loc); - boolean isNew = XmlUtils.attributeBoolValue(castleEl, "new"); - boolean isCompleted = XmlUtils.attributeBoolValue(castleEl, "completed"); - if (isNew) { - newCastles.add(castle); - } else if (isCompleted) { - emptyCastles.add(castle); - } else { - scoreableCastleVicinity.put(castle, castle.getVicinity()); - } - } - } - -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.attributeBoolValue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class CastleCapability extends Capability { + + private final Map castles = new HashMap<>(); + + private Player castlePlayer; + private Map> currentTileCastleBases = null; + + /** castles deployed this turn - cannot be scored - refs to master feature */ + private final List newCastles = new ArrayList<>(); + /** empty castles, already scored, keeping ref for game save */ + private final List emptyCastles = new ArrayList<>(); + /** castles from previous turns, can be scored - castle -> vinicity area */ + private final Map scoreableCastleVicinity = new HashMap<>(); + private final Map castleScore = new HashMap<>(); + + public CastleCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + throw new UnsupportedOperationException(); + } + + @Override + public void restore(Object data) { + throw new UnsupportedOperationException(); + } + + @Override + public void castleDeployed(Castle castle1, Castle castle2) { + newCastles.add(castle1.getMaster()); + } + + @Override + public void undeployed(Meeple meeple) { + if (meeple.getFeature() instanceof Castle) { + Castle castle = (Castle) meeple.getFeature().getMaster(); + scoreableCastleVicinity.remove(castle); + emptyCastles.add(castle); + } + } + + + + @Override + public void initPlayer(Player player) { + int players = game.getAllPlayers().length; + if (players < 5) { + castles.put(player, 3); + } else { + castles.put(player, 2); + } + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof City) { + ((City) feature).setCastleBase(attributeBoolValue(xml, "castle-base")); + } + } + + private void checkCastleVicinity(Iterable triggerPositions, int score) { + for (Position p : triggerPositions) { + for (Entry entry : scoreableCastleVicinity.entrySet()) { + Position[] vicinity = entry.getValue(); + for (int i = 0; i < vicinity.length; i++) { + if (vicinity[i].equals(p)) { + Castle master = entry.getKey(); + Integer currentCastleScore = castleScore.get(master); + if (currentCastleScore == null || currentCastleScore < score) { + castleScore.put(master, score); + //chain reaction, one completed castle triggers another + checkCastleVicinity(Arrays.asList(master.getCastleBase()), score); + } + break; + } + } + } + } + } + + private Castle replaceCityWithCastle(Tile tile, Location loc) { + ListIterator iter = tile.getFeatures().listIterator(); + City city = null; + while(iter.hasNext()) { + Feature feature = iter.next(); + if (feature.getLocation() == loc) { + city = (City) feature; + break; + } + } + List meeples = city.getMeeples(); + for (Meeple m : meeples) { + m.undeploy(false); + } + Castle castle = new Castle(); + castle.setTile(tile); + castle.setId(game.idSequnceNextVal()); + castle.setLocation(loc.rotateCCW(tile.getRotation())); + iter.set(castle); + + for (Feature f : tile.getFeatures()) { //replace also city references + if (f instanceof Farm) { + Farm farm = (Farm) f; + Feature[] adjoining = farm.getAdjoiningCities(); + if (adjoining != null) { + for (int i = 0; i < adjoining.length; i++) { + if (adjoining[i] == city) { + adjoining[i] = castle; + break; + } + } + } + } + } + + for (Meeple m : meeples) { + m.deploy(tile, loc); + } + return castle; + } + + public Castle convertCityToCastle(Position pos, Location loc) { + Castle castle1 = replaceCityWithCastle(getBoard().get(pos), loc); + Castle castle2 = replaceCityWithCastle(getBoard().get(pos.add(loc)), loc.rev()); + castle1.getEdges()[0] = castle2; + castle2.getEdges()[0] = castle1; + game.fireGameEvent().castleDeployed(castle1, castle2); + return castle1.getMaster(); + } + + @Override + public void scoreCompleted(CompletableScoreContext ctx) { + checkCastleVicinity(ctx.getPositions(), ctx.getPoints()); + } + + public Map getCastleScore() { + return castleScore; + } + + @Override + public void turnCleanUp() { + for (Castle castle: newCastles) { + scoreableCastleVicinity.put(castle, castle.getVicinity()); + } + newCastles.clear(); + castleScore.clear(); + } + + public Player getCastlePlayer() { + return castlePlayer; + } + + public void setCastlePlayer(Player castlePlayer) { + this.castlePlayer = castlePlayer; + } + + public Map> getCurrentTileCastleBases() { + return currentTileCastleBases; + } + + public void setCurrentTileCastleBases(Map> currentTileCastleBases) { + this.currentTileCastleBases = currentTileCastleBases; + } + + + public int getPlayerCastles(Player pl) { + return castles.get(pl); + } + + + public void decreaseCastles(Player player) { + int n = getPlayerCastles(player); + if (n == 0) throw new IllegalStateException("Player has no castles"); + castles.put(player, n-1); + } + + + + private Element createCastleXmlElement(Document doc, Castle castle) { + Element el = doc.createElement("castle"); + el.setAttribute("location", castle.getLocation().toString()); + XmlUtils.injectPosition(el, castle.getTile().getPosition()); + return el; + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + for (Player player: game.getAllPlayers()) { + Element el = doc.createElement("player"); + node.appendChild(el); + el.setAttribute("index", "" + player.getIndex()); + el.setAttribute("castles", "" + getPlayerCastles(player)); + } + + for (Castle castle : scoreableCastleVicinity.keySet()) { + node.appendChild(createCastleXmlElement(doc, castle)); + } + for (Castle castle : newCastles) { + Element el = createCastleXmlElement(doc, castle); + el.setAttribute("new", "true"); + node.appendChild(el); + } + for (Castle castle : emptyCastles) { + Element el = createCastleXmlElement(doc, castle); + el.setAttribute("completed", "true"); + node.appendChild(el); + } + } + + + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("player"); + for (int i = 0; i < nl.getLength(); i++) { + Element playerEl = (Element) nl.item(i); + Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); + castles.put(player, Integer.parseInt(playerEl.getAttribute("castles"))); + } + + nl = node.getElementsByTagName("castle"); + for (int i = 0; i < nl.getLength(); i++) { + Element castleEl = (Element) nl.item(i); + Position pos = XmlUtils.extractPosition(castleEl); + Location loc = Location.valueOf(castleEl.getAttribute("location")); + Castle castle = convertCityToCastle(pos, loc); + boolean isNew = XmlUtils.attributeBoolValue(castleEl, "new"); + boolean isCompleted = XmlUtils.attributeBoolValue(castleEl, "completed"); + if (isNew) { + newCastles.add(castle); + } else if (isCompleted) { + emptyCastles.add(castle); + } else { + scoreableCastleVicinity.put(castle, castle.getVicinity()); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/CathedralCapability.java b/src/main/java/com/jcloisterzone/game/capability/CathedralCapability.java index f310dc820..6120297c2 100644 --- a/src/main/java/com/jcloisterzone/game/capability/CathedralCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/CathedralCapability.java @@ -1,28 +1,28 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.attributeBoolValue; - -import org.w3c.dom.Element; - -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class CathedralCapability extends Capability { - - public CathedralCapability(Game game) { - super(game); - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof City) { - ((City) feature).setCathedral(attributeBoolValue(xml, "cathedral")); - } - } - - - -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.attributeBoolValue; + +import org.w3c.dom.Element; + +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class CathedralCapability extends Capability { + + public CathedralCapability(Game game) { + super(game); + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof City) { + ((City) feature).setCathedral(attributeBoolValue(xml, "cathedral")); + } + } + + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/ClothWineGrainCapability.java b/src/main/java/com/jcloisterzone/game/capability/ClothWineGrainCapability.java index 45db64b1b..63e998fd3 100644 --- a/src/main/java/com/jcloisterzone/game/capability/ClothWineGrainCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/ClothWineGrainCapability.java @@ -1,123 +1,123 @@ -package com.jcloisterzone.game.capability; - -import java.util.HashMap; -import java.util.Map; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.TradeResource; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class ClothWineGrainCapability extends Capability { - - private final Map tradeResources = new HashMap<>(); - - public ClothWineGrainCapability(final Game game) { - super(game); - } - - @Override - public void completed(Completable feature, CompletableScoreContext ctx) { - if (feature instanceof City) { - int cityTradeResources[] = ((CityScoreContext)ctx).getCityTradeResources(); - if (cityTradeResources != null) { - int playersTradeResources[] = tradeResources.get(game.getActivePlayer()); - for (int i = 0; i < cityTradeResources.length; i++) { - playersTradeResources[i] += cityTradeResources[i]; - } - } - } - } - - @Override - public Object backup() { - return new HashMap<>(tradeResources); - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - tradeResources.clear(); - tradeResources.putAll((Map) data); - } - - @Override - public void initPlayer(Player player) { - tradeResources.put(player, new int[TradeResource.values().length]); - } - - public void addTradeResources(Player p, TradeResource res, int n) { - tradeResources.get(p)[res.ordinal()] += n; - } - - public int getTradeResources(Player p, TradeResource res) { - return tradeResources.get(p)[res.ordinal()]; - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof City && xml.hasAttribute("resource")) { - City city = (City) feature; - String val = xml.getAttribute("resource"); - city.setTradeResource(TradeResource.valueOf(val.toUpperCase())); - } - } - - - @Override - public void finalScoring() { - for (TradeResource tr : TradeResource.values()) { - int hiVal = 1; - for (Player player: game.getAllPlayers()) { - int playerValue = getTradeResources(player, tr); - if (playerValue > hiVal) { - hiVal = playerValue; - } - } - for (Player player: game.getAllPlayers()) { - int playerValue = getTradeResources(player, tr); - if (playerValue == hiVal) { - player.addPoints(10, PointCategory.TRADE_GOODS); - } - } - - } - } - - - - @Override - public void saveToSnapshot(Document doc, Element node) { - for (Player player: game.getAllPlayers()) { - Element el = doc.createElement("player"); - node.appendChild(el); - el.setAttribute("index", "" + player.getIndex()); - el.setAttribute("grain", "" + getTradeResources(player, TradeResource.GRAIN)); - el.setAttribute("wine", "" + getTradeResources(player, TradeResource.WINE)); - el.setAttribute("cloth", "" + getTradeResources(player, TradeResource.CLOTH)); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("player"); - for (int i = 0; i < nl.getLength(); i++) { - Element playerEl = (Element) nl.item(i); - Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); - addTradeResources(player, TradeResource.GRAIN, Integer.parseInt(playerEl.getAttribute("grain"))); - addTradeResources(player, TradeResource.WINE, Integer.parseInt(playerEl.getAttribute("wine"))); - addTradeResources(player, TradeResource.CLOTH, Integer.parseInt(playerEl.getAttribute("cloth"))); - } - } -} +package com.jcloisterzone.game.capability; + +import java.util.HashMap; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.TradeResource; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class ClothWineGrainCapability extends Capability { + + private final Map tradeResources = new HashMap<>(); + + public ClothWineGrainCapability(final Game game) { + super(game); + } + + @Override + public void completed(Completable feature, CompletableScoreContext ctx) { + if (feature instanceof City) { + int cityTradeResources[] = ((CityScoreContext)ctx).getCityTradeResources(); + if (cityTradeResources != null) { + int playersTradeResources[] = tradeResources.get(game.getActivePlayer()); + for (int i = 0; i < cityTradeResources.length; i++) { + playersTradeResources[i] += cityTradeResources[i]; + } + } + } + } + + @Override + public Object backup() { + return new HashMap<>(tradeResources); + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + tradeResources.clear(); + tradeResources.putAll((Map) data); + } + + @Override + public void initPlayer(Player player) { + tradeResources.put(player, new int[TradeResource.values().length]); + } + + public void addTradeResources(Player p, TradeResource res, int n) { + tradeResources.get(p)[res.ordinal()] += n; + } + + public int getTradeResources(Player p, TradeResource res) { + return tradeResources.get(p)[res.ordinal()]; + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof City && xml.hasAttribute("resource")) { + City city = (City) feature; + String val = xml.getAttribute("resource"); + city.setTradeResource(TradeResource.valueOf(val.toUpperCase())); + } + } + + + @Override + public void finalScoring() { + for (TradeResource tr : TradeResource.values()) { + int hiVal = 1; + for (Player player: game.getAllPlayers()) { + int playerValue = getTradeResources(player, tr); + if (playerValue > hiVal) { + hiVal = playerValue; + } + } + for (Player player: game.getAllPlayers()) { + int playerValue = getTradeResources(player, tr); + if (playerValue == hiVal) { + player.addPoints(10, PointCategory.TRADE_GOODS); + } + } + + } + } + + + + @Override + public void saveToSnapshot(Document doc, Element node) { + for (Player player: game.getAllPlayers()) { + Element el = doc.createElement("player"); + node.appendChild(el); + el.setAttribute("index", "" + player.getIndex()); + el.setAttribute("grain", "" + getTradeResources(player, TradeResource.GRAIN)); + el.setAttribute("wine", "" + getTradeResources(player, TradeResource.WINE)); + el.setAttribute("cloth", "" + getTradeResources(player, TradeResource.CLOTH)); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("player"); + for (int i = 0; i < nl.getLength(); i++) { + Element playerEl = (Element) nl.item(i); + Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); + addTradeResources(player, TradeResource.GRAIN, Integer.parseInt(playerEl.getAttribute("grain"))); + addTradeResources(player, TradeResource.WINE, Integer.parseInt(playerEl.getAttribute("wine"))); + addTradeResources(player, TradeResource.CLOTH, Integer.parseInt(playerEl.getAttribute("cloth"))); + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/capability/CornCircleCapability.java b/src/main/java/com/jcloisterzone/game/capability/CornCircleCapability.java index 10493e0dc..04bad0e23 100644 --- a/src/main/java/com/jcloisterzone/game/capability/CornCircleCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/CornCircleCapability.java @@ -1,93 +1,93 @@ -package com.jcloisterzone.game.capability; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class CornCircleCapability extends Capability { - - public static enum CornCicleOption { - DEPLOYMENT, - REMOVAL; - } - - private Player cornCirclePlayer; - private CornCicleOption cornCircleOption; - - public CornCircleCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return new Object[] { cornCirclePlayer, cornCircleOption }; - } - - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - cornCirclePlayer = (Player) a[0]; - cornCircleOption = (CornCicleOption) a[1]; - } - - - @Override - public void initTile(Tile tile, Element xml) { - NodeList nl = xml.getElementsByTagName("corn-circle"); - if (nl.getLength() > 0) { - String type = ((Element)nl.item(0)).getAttribute("type"); - Class cornCircleType = null; - if ("Road".equals(type)) cornCircleType = Road.class; - if ("City".equals(type)) cornCircleType = City.class; - if ("Farm".equals(type)) cornCircleType = Farm.class; - if (cornCircleType == null) throw new IllegalArgumentException("Invalid corn cicle type."); - tile.setCornCircle(cornCircleType); - } - } - - public Player getCornCirclePlayer() { - return cornCirclePlayer; - } - - public void setCornCirclePlayer(Player cornCirclePlayer) { - this.cornCirclePlayer = cornCirclePlayer; - } - - public CornCicleOption getCornCircleOption() { - return cornCircleOption; - } - - public void setCornCircleOption(CornCicleOption cornCircleOption) { - this.cornCircleOption = cornCircleOption; - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - if (cornCircleOption != null) { - node.setAttribute("selectedOption", cornCircleOption.name()); - } - if (cornCirclePlayer != null) { - node.setAttribute("cornPlayer", "" + cornCirclePlayer.getIndex()); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - if (node.hasAttribute("selectedOption")) { - cornCircleOption = CornCicleOption.valueOf(node.getAttribute("selectedOption")); - } - if (node.hasAttribute("cornPlayer")) { - Player player = game.getPlayer(Integer.parseInt(node.getAttribute("cornPlayer"))); - cornCirclePlayer = player; - } - } -} +package com.jcloisterzone.game.capability; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class CornCircleCapability extends Capability { + + public static enum CornCicleOption { + DEPLOYMENT, + REMOVAL; + } + + private Player cornCirclePlayer; + private CornCicleOption cornCircleOption; + + public CornCircleCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return new Object[] { cornCirclePlayer, cornCircleOption }; + } + + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + cornCirclePlayer = (Player) a[0]; + cornCircleOption = (CornCicleOption) a[1]; + } + + + @Override + public void initTile(Tile tile, Element xml) { + NodeList nl = xml.getElementsByTagName("corn-circle"); + if (nl.getLength() > 0) { + String type = ((Element)nl.item(0)).getAttribute("type"); + Class cornCircleType = null; + if ("Road".equals(type)) cornCircleType = Road.class; + if ("City".equals(type)) cornCircleType = City.class; + if ("Farm".equals(type)) cornCircleType = Farm.class; + if (cornCircleType == null) throw new IllegalArgumentException("Invalid corn cicle type."); + tile.setCornCircle(cornCircleType); + } + } + + public Player getCornCirclePlayer() { + return cornCirclePlayer; + } + + public void setCornCirclePlayer(Player cornCirclePlayer) { + this.cornCirclePlayer = cornCirclePlayer; + } + + public CornCicleOption getCornCircleOption() { + return cornCircleOption; + } + + public void setCornCircleOption(CornCicleOption cornCircleOption) { + this.cornCircleOption = cornCircleOption; + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + if (cornCircleOption != null) { + node.setAttribute("selectedOption", cornCircleOption.name()); + } + if (cornCirclePlayer != null) { + node.setAttribute("cornPlayer", "" + cornCirclePlayer.getIndex()); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + if (node.hasAttribute("selectedOption")) { + cornCircleOption = CornCicleOption.valueOf(node.getAttribute("selectedOption")); + } + if (node.hasAttribute("cornPlayer")) { + Player player = game.getPlayer(Integer.parseInt(node.getAttribute("cornPlayer"))); + cornCirclePlayer = player; + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/capability/CountCapability.java b/src/main/java/com/jcloisterzone/game/capability/CountCapability.java index c0b9a3263..4d97bd3be 100644 --- a/src/main/java/com/jcloisterzone/game/capability/CountCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/CountCapability.java @@ -1,22 +1,22 @@ -package com.jcloisterzone.game.capability; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class CountCapability extends Capability { - - public CountCapability(Game game) { - super(game); - } - - @Override - public boolean isDeployAllowed(Tile tile, Class meepleType) { - return tile.getOrigin() != Expansion.COUNT; - } - - - -} +package com.jcloisterzone.game.capability; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class CountCapability extends Capability { + + public CountCapability(Game game) { + super(game); + } + + @Override + public boolean isDeployAllowed(Tile tile, Class meepleType) { + return tile.getOrigin() != Expansion.COUNT; + } + + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/DragonCapability.java b/src/main/java/com/jcloisterzone/game/capability/DragonCapability.java index 0a8b298e5..ce1c394a4 100644 --- a/src/main/java/com/jcloisterzone/game/capability/DragonCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/DragonCapability.java @@ -1,186 +1,186 @@ -package com.jcloisterzone.game.capability; - -import java.util.HashSet; -import java.util.Set; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Special; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; - -public class DragonCapability extends Capability { - - public static final int DRAGON_MOVES = 6; - - public Position dragonPosition; - public int dragonMovesLeft; - public Player dragonPlayer; - public Set dragonVisitedTiles; - - public DragonCapability(final Game game) { - super(game); - } - - @Override - public void tilePlaced(Tile tile) { - if (tile.hasTrigger(TileTrigger.VOLCANO)) { - setDragonPosition(tile.getPosition()); - getTilePack().activateGroup("dragon"); - game.fireGameEvent().dragonMoved(tile.getPosition()); - } - } - - @Override - public Object backup() { - return new Object[] { - dragonPosition, - dragonMovesLeft, - dragonPlayer, - dragonVisitedTiles == null ? null : new HashSet<>(dragonVisitedTiles) - }; - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - dragonPosition = (Position) a[0]; - dragonMovesLeft = (Integer) a[1]; - dragonPlayer = (Player) a[2]; - dragonVisitedTiles = a[3] == null ? null : new HashSet<>((Set) a[3]); - } - - - @Override - public String getTileGroup(Tile tile) { - return tile.hasTrigger(TileTrigger.DRAGON) ? "dragon" : null; - } - - @Override - public void initTile(Tile tile, Element xml) { - if (xml.getElementsByTagName("volcano").getLength() > 0) { - tile.setTrigger(TileTrigger.VOLCANO); - } - if (xml.getElementsByTagName("dragon").getLength() > 0) { - tile.setTrigger(TileTrigger.DRAGON); - } - } - - @Override - public boolean isDeployAllowed(Tile tile, Class meepleType) { - if (!tile.getPosition().equals(dragonPosition)) return true; - if (game.hasRule(CustomRule.CANNOT_PLACE_BUILDER_ON_VOLCANO)) return false; - return Special.class.isAssignableFrom(meepleType); - } - - public Position getDragonPosition() { - return dragonPosition; - } - - public void setDragonPosition(Position dragonPosition) { - this.dragonPosition = dragonPosition; - } - - public Player getDragonPlayer() { - return dragonPlayer; - } - public void setDragonPlayer(Player dragonPlayer) { - this.dragonPlayer = dragonPlayer; - } - - public int getDragonMovesLeft() { - return dragonMovesLeft; - } - - public Set getDragonVisitedTiles() { - return dragonVisitedTiles; - } - - public void triggerDragonMove() { - dragonMovesLeft = DRAGON_MOVES; - dragonPlayer = game.getTurnPlayer(); - dragonVisitedTiles = new HashSet<>(); - dragonVisitedTiles.add(dragonPosition); - } - - public void endDragonMove() { - dragonMovesLeft = 0; - dragonVisitedTiles = null; - dragonPlayer = null; - } - - public void moveDragon(Position p) { - dragonVisitedTiles.add(p); - dragonPosition = p; - dragonPlayer = game.getNextPlayer(dragonPlayer); - dragonMovesLeft--; - } - - public Set getAvailDragonMoves() { - Set result = new HashSet<>(); - FairyCapability fairyCap = game.getCapability(FairyCapability.class); - for (Position offset: Position.ADJACENT.values()) { - Position position = dragonPosition.add(offset); - Tile tile = getBoard().get(position); - if (tile == null || tile.getOrigin() == Expansion.COUNT) continue; - if (dragonVisitedTiles != null && dragonVisitedTiles.contains(position)) { continue; } - if (fairyCap != null && position.equals(fairyCap.getFairyPosition())) { continue; } - result.add(position); - } - return result; - } - - - - @Override - public void saveToSnapshot(Document doc, Element node) { - if (dragonPosition != null) { - Element dragon = doc.createElement("dragon"); - XmlUtils.injectPosition(dragon, dragonPosition); - if (dragonMovesLeft > 0) { - dragon.setAttribute("moves", "" + dragonMovesLeft); - dragon.setAttribute("movingPlayer", "" + dragonPlayer.getIndex()); - if (dragonVisitedTiles != null) { - for (Position visited : dragonVisitedTiles) { - Element ve = doc.createElement("visited"); - XmlUtils.injectPosition(ve, visited); - dragon.appendChild(ve); - } - } - } - node.appendChild(dragon); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("dragon"); - if (nl.getLength() > 0) { - Element dragon = (Element) nl.item(0); - dragonPosition = XmlUtils.extractPosition(dragon); - game.fireGameEvent().dragonMoved(dragonPosition); - if (dragon.hasAttribute("moves")) { - dragonMovesLeft = Integer.parseInt(dragon.getAttribute("moves")); - dragonPlayer = game.getPlayer(Integer.parseInt(dragon.getAttribute("movingPlayer"))); - dragonVisitedTiles = new HashSet<>(); - NodeList vl = dragon.getElementsByTagName("visited"); - for (int i = 0; i < vl.getLength(); i++) { - dragonVisitedTiles.add(XmlUtils.extractPosition((Element) vl.item(i))); - } - } - } - } - - -} +package com.jcloisterzone.game.capability; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Special; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; + +public class DragonCapability extends Capability { + + public static final int DRAGON_MOVES = 6; + + public Position dragonPosition; + public int dragonMovesLeft; + public Player dragonPlayer; + public Set dragonVisitedTiles; + + public DragonCapability(final Game game) { + super(game); + } + + @Override + public void tilePlaced(Tile tile) { + if (tile.hasTrigger(TileTrigger.VOLCANO)) { + setDragonPosition(tile.getPosition()); + getTilePack().activateGroup("dragon"); + game.fireGameEvent().dragonMoved(tile.getPosition()); + } + } + + @Override + public Object backup() { + return new Object[] { + dragonPosition, + dragonMovesLeft, + dragonPlayer, + dragonVisitedTiles == null ? null : new HashSet<>(dragonVisitedTiles) + }; + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + dragonPosition = (Position) a[0]; + dragonMovesLeft = (Integer) a[1]; + dragonPlayer = (Player) a[2]; + dragonVisitedTiles = a[3] == null ? null : new HashSet<>((Set) a[3]); + } + + + @Override + public String getTileGroup(Tile tile) { + return tile.hasTrigger(TileTrigger.DRAGON) ? "dragon" : null; + } + + @Override + public void initTile(Tile tile, Element xml) { + if (xml.getElementsByTagName("volcano").getLength() > 0) { + tile.setTrigger(TileTrigger.VOLCANO); + } + if (xml.getElementsByTagName("dragon").getLength() > 0) { + tile.setTrigger(TileTrigger.DRAGON); + } + } + + @Override + public boolean isDeployAllowed(Tile tile, Class meepleType) { + if (!tile.getPosition().equals(dragonPosition)) return true; + if (game.hasRule(CustomRule.CANNOT_PLACE_BUILDER_ON_VOLCANO)) return false; + return Special.class.isAssignableFrom(meepleType); + } + + public Position getDragonPosition() { + return dragonPosition; + } + + public void setDragonPosition(Position dragonPosition) { + this.dragonPosition = dragonPosition; + } + + public Player getDragonPlayer() { + return dragonPlayer; + } + public void setDragonPlayer(Player dragonPlayer) { + this.dragonPlayer = dragonPlayer; + } + + public int getDragonMovesLeft() { + return dragonMovesLeft; + } + + public Set getDragonVisitedTiles() { + return dragonVisitedTiles; + } + + public void triggerDragonMove() { + dragonMovesLeft = DRAGON_MOVES; + dragonPlayer = game.getTurnPlayer(); + dragonVisitedTiles = new HashSet<>(); + dragonVisitedTiles.add(dragonPosition); + } + + public void endDragonMove() { + dragonMovesLeft = 0; + dragonVisitedTiles = null; + dragonPlayer = null; + } + + public void moveDragon(Position p) { + dragonVisitedTiles.add(p); + dragonPosition = p; + dragonPlayer = game.getNextPlayer(dragonPlayer); + dragonMovesLeft--; + } + + public Set getAvailDragonMoves() { + Set result = new HashSet<>(); + FairyCapability fairyCap = game.getCapability(FairyCapability.class); + for (Position offset: Position.ADJACENT.values()) { + Position position = dragonPosition.add(offset); + Tile tile = getBoard().get(position); + if (tile == null || tile.getOrigin() == Expansion.COUNT) continue; + if (dragonVisitedTiles != null && dragonVisitedTiles.contains(position)) { continue; } + if (fairyCap != null && position.equals(fairyCap.getFairyPosition())) { continue; } + result.add(position); + } + return result; + } + + + + @Override + public void saveToSnapshot(Document doc, Element node) { + if (dragonPosition != null) { + Element dragon = doc.createElement("dragon"); + XmlUtils.injectPosition(dragon, dragonPosition); + if (dragonMovesLeft > 0) { + dragon.setAttribute("moves", "" + dragonMovesLeft); + dragon.setAttribute("movingPlayer", "" + dragonPlayer.getIndex()); + if (dragonVisitedTiles != null) { + for (Position visited : dragonVisitedTiles) { + Element ve = doc.createElement("visited"); + XmlUtils.injectPosition(ve, visited); + dragon.appendChild(ve); + } + } + } + node.appendChild(dragon); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("dragon"); + if (nl.getLength() > 0) { + Element dragon = (Element) nl.item(0); + dragonPosition = XmlUtils.extractPosition(dragon); + game.fireGameEvent().dragonMoved(dragonPosition); + if (dragon.hasAttribute("moves")) { + dragonMovesLeft = Integer.parseInt(dragon.getAttribute("moves")); + dragonPlayer = game.getPlayer(Integer.parseInt(dragon.getAttribute("movingPlayer"))); + dragonVisitedTiles = new HashSet<>(); + NodeList vl = dragon.getElementsByTagName("visited"); + for (int i = 0; i < vl.getLength(); i++) { + dragonVisitedTiles.add(XmlUtils.extractPosition((Element) vl.item(i))); + } + } + } + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/FairyCapability.java b/src/main/java/com/jcloisterzone/game/capability/FairyCapability.java index 6e6067de9..6af8b1b34 100644 --- a/src/main/java/com/jcloisterzone/game/capability/FairyCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/FairyCapability.java @@ -1,81 +1,81 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.google.common.collect.Iterables; -import com.jcloisterzone.Player; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.action.FairyAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class FairyCapability extends Capability { - - public static final int FAIRY_POINTS_FINISHED_OBJECT = 3; - - public Position fairyPosition; - - public FairyCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return fairyPosition; - } - - @Override - public void restore(Object data) { - fairyPosition = (Position) data; - } - - public Position getFairyPosition() { - return fairyPosition; - } - - public void setFairyPosition(Position fairyPosition) { - this.fairyPosition = fairyPosition; - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - FairyAction fairyAction = new FairyAction(); - Player activePlayer = game.getActivePlayer(); - for (Follower m : Iterables.filter(activePlayer.getFollowers(), MeeplePredicates.deployed())) { - if (!m.at(fairyPosition)) { - fairyAction.getSites().add(m.getPosition()); - } - } - if (!fairyAction.getSites().isEmpty()) { - actions.add(fairyAction); - } - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - if (fairyPosition != null) { - Element fairy = doc.createElement("fairy"); - XmlUtils.injectPosition(fairy, fairyPosition); - node.appendChild(fairy); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("fairy"); - if (nl.getLength() > 0) { - Element fairy = (Element) nl.item(0); - fairyPosition = XmlUtils.extractPosition(fairy); - game.fireGameEvent().fairyMoved(fairyPosition); - } - } -} +package com.jcloisterzone.game.capability; + +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.google.common.collect.Iterables; +import com.jcloisterzone.Player; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.action.FairyAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class FairyCapability extends Capability { + + public static final int FAIRY_POINTS_FINISHED_OBJECT = 3; + + public Position fairyPosition; + + public FairyCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return fairyPosition; + } + + @Override + public void restore(Object data) { + fairyPosition = (Position) data; + } + + public Position getFairyPosition() { + return fairyPosition; + } + + public void setFairyPosition(Position fairyPosition) { + this.fairyPosition = fairyPosition; + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + FairyAction fairyAction = new FairyAction(); + Player activePlayer = game.getActivePlayer(); + for (Follower m : Iterables.filter(activePlayer.getFollowers(), MeeplePredicates.deployed())) { + if (!m.at(fairyPosition)) { + fairyAction.getSites().add(m.getPosition()); + } + } + if (!fairyAction.getSites().isEmpty()) { + actions.add(fairyAction); + } + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + if (fairyPosition != null) { + Element fairy = doc.createElement("fairy"); + XmlUtils.injectPosition(fairy, fairyPosition); + node.appendChild(fairy); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("fairy"); + if (nl.getLength() > 0) { + Element fairy = (Element) nl.item(0); + fairyPosition = XmlUtils.extractPosition(fairy); + game.fireGameEvent().fairyMoved(fairyPosition); + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/capability/FestivalCapability.java b/src/main/java/com/jcloisterzone/game/capability/FestivalCapability.java index 60abdc688..4fcbae302 100644 --- a/src/main/java/com/jcloisterzone/game/capability/FestivalCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/FestivalCapability.java @@ -1,50 +1,50 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; - -import org.w3c.dom.Element; - -import com.google.common.collect.Iterables; -import com.jcloisterzone.Player; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.UndeployAction; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class FestivalCapability extends Capability { - - public FestivalCapability(Game game) { - super(game); - } - - @Override - public void initTile(Tile tile, Element xml) { - if (xml.getElementsByTagName("festival").getLength() > 0) { - tile.setTrigger(TileTrigger.FESTIVAL); - } - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - if (!getTile().hasTrigger(TileTrigger.FESTIVAL)) return; - - Player activePlayer = game.getActivePlayer(); - UndeployAction action = new UndeployAction("festival", PlayerRestriction.only(activePlayer)); - - for (Meeple m : Iterables.filter(activePlayer.getMeeples(), MeeplePredicates.deployed())) { - action.getOrCreate(m.getPosition()).add(m.getLocation()); - } - if (!action.getLocationsMap().isEmpty()) { - actions.add(action); - } - } - - - -} +package com.jcloisterzone.game.capability; + +import java.util.List; + +import org.w3c.dom.Element; + +import com.google.common.collect.Iterables; +import com.jcloisterzone.Player; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.UndeployAction; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class FestivalCapability extends Capability { + + public FestivalCapability(Game game) { + super(game); + } + + @Override + public void initTile(Tile tile, Element xml) { + if (xml.getElementsByTagName("festival").getLength() > 0) { + tile.setTrigger(TileTrigger.FESTIVAL); + } + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + if (!getTile().hasTrigger(TileTrigger.FESTIVAL)) return; + + Player activePlayer = game.getActivePlayer(); + UndeployAction action = new UndeployAction("festival", PlayerRestriction.only(activePlayer)); + + for (Meeple m : Iterables.filter(activePlayer.getMeeples(), MeeplePredicates.deployed())) { + action.getOrCreate(m.getPosition()).add(m.getLocation()); + } + if (!action.getLocationsMap().isEmpty()) { + actions.add(action); + } + } + + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/FlierCapability.java b/src/main/java/com/jcloisterzone/game/capability/FlierCapability.java index 9b832086d..7a8075ed3 100644 --- a/src/main/java/com/jcloisterzone/game/capability/FlierCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/FlierCapability.java @@ -1,74 +1,74 @@ -package com.jcloisterzone.game.capability; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.SnapshotCorruptedException; -import com.jcloisterzone.game.phase.ActionPhase; -import com.jcloisterzone.game.phase.Phase; - -public class FlierCapability extends Capability { - - private int flierDistance; - - public FlierCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return flierDistance; - } - - @Override - public void restore(Object data) { - flierDistance = (Integer) data; - } - - public int getFlierDistance() { - return flierDistance; - } - - public void setFlierDistance(int flierDistance) { - this.flierDistance = flierDistance; - } - - @Override - public void initTile(Tile tile, Element xml) { - NodeList nl = xml.getElementsByTagName("flier"); - assert nl.getLength() <= 1; - if (nl.getLength() == 1) { - Location flier = XmlUtils.union(XmlUtils.asLocation((Element) nl.item(0))); - tile.setFlier(flier); - } - } - - public boolean isFlierRollAllowed() { - Phase phase = game.getPhase(); - if (phase instanceof ActionPhase && game.getActivePlayer().hasFollower()) { - return game.getCurrentTile().getFlier() != null; - } - return false; - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - if (flierDistance > 0) { - node.setAttribute("flierDistance", ""+flierDistance); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { - if (node.hasAttribute("flierDistance")) { - flierDistance = Integer.parseInt(node.getAttribute("flierDistance")); - } - } - -} +package com.jcloisterzone.game.capability; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.SnapshotCorruptedException; +import com.jcloisterzone.game.phase.ActionPhase; +import com.jcloisterzone.game.phase.Phase; + +public class FlierCapability extends Capability { + + private int flierDistance; + + public FlierCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return flierDistance; + } + + @Override + public void restore(Object data) { + flierDistance = (Integer) data; + } + + public int getFlierDistance() { + return flierDistance; + } + + public void setFlierDistance(int flierDistance) { + this.flierDistance = flierDistance; + } + + @Override + public void initTile(Tile tile, Element xml) { + NodeList nl = xml.getElementsByTagName("flier"); + assert nl.getLength() <= 1; + if (nl.getLength() == 1) { + Location flier = XmlUtils.union(XmlUtils.asLocation((Element) nl.item(0))); + tile.setFlier(flier); + } + } + + public boolean isFlierRollAllowed() { + Phase phase = game.getPhase(); + if (phase instanceof ActionPhase && game.getActivePlayer().hasFollower()) { + return game.getCurrentTile().getFlier() != null; + } + return false; + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + if (flierDistance > 0) { + node.setAttribute("flierDistance", ""+flierDistance); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { + if (node.hasAttribute("flierDistance")) { + flierDistance = Integer.parseInt(node.getAttribute("flierDistance")); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/InnCapability.java b/src/main/java/com/jcloisterzone/game/capability/InnCapability.java index a9145d183..2c7aeff95 100644 --- a/src/main/java/com/jcloisterzone/game/capability/InnCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/InnCapability.java @@ -1,25 +1,25 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.attributeBoolValue; - -import org.w3c.dom.Element; - -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class InnCapability extends Capability { - - public InnCapability(Game game) { - super(game); - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof Road) { - ((Road) feature).setInn(attributeBoolValue(xml, "inn")); - } - } -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.attributeBoolValue; + +import org.w3c.dom.Element; + +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class InnCapability extends Capability { + + public InnCapability(Game game) { + super(game); + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof Road) { + ((Road) feature).setInn(attributeBoolValue(xml, "inn")); + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/capability/KingScoutCapability.java b/src/main/java/com/jcloisterzone/game/capability/KingScoutCapability.java index a2fad8db3..a6451f4ef 100644 --- a/src/main/java/com/jcloisterzone/game/capability/KingScoutCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/KingScoutCapability.java @@ -1,143 +1,143 @@ -package com.jcloisterzone.game.capability; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.PositionCollectingScoreContext; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.SnapshotCorruptedException; - -public final class KingScoutCapability extends Capability { - - protected int completedCities, biggestCitySize; - protected int completedRoads, longestRoadLength; - - private Player king, robberBaron; - - public KingScoutCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return new Object[] { - new int[] { completedCities, biggestCitySize, completedRoads, longestRoadLength }, - king, - robberBaron - }; - } - - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - int[] i = (int[]) a[0]; - completedCities = i[0]; - biggestCitySize = i[1]; - completedRoads = i[2]; - longestRoadLength = i[3]; - king = (Player) a[1]; - robberBaron = (Player) a[2]; - } - - @Override - public void completed(Completable feature, CompletableScoreContext ctx) { - if (feature instanceof City) { - cityCompleted((City) feature, (PositionCollectingScoreContext) ctx); - } - if (feature instanceof Road) { - roadCompleted((Road) feature, (PositionCollectingScoreContext) ctx); - } - } - - private void cityCompleted(City c, PositionCollectingScoreContext ctx) { - completedCities++; - int size = ctx.getSize(); - if (size > biggestCitySize) { - biggestCitySize = size; - king = game.getActivePlayer(); - } - } - - private void roadCompleted(Road r, PositionCollectingScoreContext ctx) { - completedRoads++; - int size = ctx.getSize(); - if (size > longestRoadLength) { - longestRoadLength = size; - robberBaron = game.getActivePlayer(); - } - } - - @Override - public void finalScoring() { - if (king != null) { - king.addPoints(completedCities, PointCategory.BIGGEST_CITY); - } - if (robberBaron != null) { - robberBaron.addPoints(completedRoads, PointCategory.LONGEST_ROAD); - } - } - - public int getCompletedCities() { - return completedCities; - } - - public int getBiggestCitySize() { - return biggestCitySize; - } - - public int getCompletedRoads() { - return completedRoads; - } - - public int getLongestRoadLength() { - return longestRoadLength; - } - - public Player getKing() { - return king; - } - - public Player getRobberBaron() { - return robberBaron; - } - - - - @Override - public void saveToSnapshot(Document doc, Element node) { - if (king != null) { - node.setAttribute("king", king.getIndex() + ""); - } - if (robberBaron != null) { - node.setAttribute("robber", robberBaron.getIndex() + ""); - } - node.setAttribute("completedCities", "" + completedCities); - node.setAttribute("biggestCitySize", "" + biggestCitySize); - node.setAttribute("completedRoads", "" + completedRoads); - node.setAttribute("longestRoadLength", "" + longestRoadLength); - } - - @Override - public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { - if (node.hasAttribute("king")) { - king = game.getPlayer(Integer.parseInt(node.getAttribute("king"))); - } - if (node.hasAttribute("robber")) { - robberBaron = game.getPlayer(Integer.parseInt(node.getAttribute("robber"))); - } - completedCities = Integer.parseInt(node.getAttribute("completedCities")); - biggestCitySize = Integer.parseInt(node.getAttribute("biggestCitySize")); - completedRoads = Integer.parseInt(node.getAttribute("completedRoads")); - longestRoadLength = Integer.parseInt(node.getAttribute("longestRoadLength")); - } - - -} - +package com.jcloisterzone.game.capability; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.PositionCollectingScoreContext; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.SnapshotCorruptedException; + +public final class KingScoutCapability extends Capability { + + protected int completedCities, biggestCitySize; + protected int completedRoads, longestRoadLength; + + private Player king, robberBaron; + + public KingScoutCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return new Object[] { + new int[] { completedCities, biggestCitySize, completedRoads, longestRoadLength }, + king, + robberBaron + }; + } + + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + int[] i = (int[]) a[0]; + completedCities = i[0]; + biggestCitySize = i[1]; + completedRoads = i[2]; + longestRoadLength = i[3]; + king = (Player) a[1]; + robberBaron = (Player) a[2]; + } + + @Override + public void completed(Completable feature, CompletableScoreContext ctx) { + if (feature instanceof City) { + cityCompleted((City) feature, (PositionCollectingScoreContext) ctx); + } + if (feature instanceof Road) { + roadCompleted((Road) feature, (PositionCollectingScoreContext) ctx); + } + } + + private void cityCompleted(City c, PositionCollectingScoreContext ctx) { + completedCities++; + int size = ctx.getSize(); + if (size > biggestCitySize) { + biggestCitySize = size; + king = game.getActivePlayer(); + } + } + + private void roadCompleted(Road r, PositionCollectingScoreContext ctx) { + completedRoads++; + int size = ctx.getSize(); + if (size > longestRoadLength) { + longestRoadLength = size; + robberBaron = game.getActivePlayer(); + } + } + + @Override + public void finalScoring() { + if (king != null) { + king.addPoints(completedCities, PointCategory.BIGGEST_CITY); + } + if (robberBaron != null) { + robberBaron.addPoints(completedRoads, PointCategory.LONGEST_ROAD); + } + } + + public int getCompletedCities() { + return completedCities; + } + + public int getBiggestCitySize() { + return biggestCitySize; + } + + public int getCompletedRoads() { + return completedRoads; + } + + public int getLongestRoadLength() { + return longestRoadLength; + } + + public Player getKing() { + return king; + } + + public Player getRobberBaron() { + return robberBaron; + } + + + + @Override + public void saveToSnapshot(Document doc, Element node) { + if (king != null) { + node.setAttribute("king", king.getIndex() + ""); + } + if (robberBaron != null) { + node.setAttribute("robber", robberBaron.getIndex() + ""); + } + node.setAttribute("completedCities", "" + completedCities); + node.setAttribute("biggestCitySize", "" + biggestCitySize); + node.setAttribute("completedRoads", "" + completedRoads); + node.setAttribute("longestRoadLength", "" + longestRoadLength); + } + + @Override + public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { + if (node.hasAttribute("king")) { + king = game.getPlayer(Integer.parseInt(node.getAttribute("king"))); + } + if (node.hasAttribute("robber")) { + robberBaron = game.getPlayer(Integer.parseInt(node.getAttribute("robber"))); + } + completedCities = Integer.parseInt(node.getAttribute("completedCities")); + biggestCitySize = Integer.parseInt(node.getAttribute("biggestCitySize")); + completedRoads = Integer.parseInt(node.getAttribute("completedRoads")); + longestRoadLength = Integer.parseInt(node.getAttribute("longestRoadLength")); + } + + +} + diff --git a/src/main/java/com/jcloisterzone/game/capability/MayorCapability.java b/src/main/java/com/jcloisterzone/game/capability/MayorCapability.java index 05cd5f54b..c1e4443d2 100644 --- a/src/main/java/com/jcloisterzone/game/capability/MayorCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/MayorCapability.java @@ -1,61 +1,61 @@ -package com.jcloisterzone.game.capability; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Mayor; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class MayorCapability extends Capability { - - public MayorCapability(Game game) { - super(game); - } - - @Override - public void initPlayer(Player player) { - player.addMeeple(new Mayor(game, player)); - } - - private Set copyMayorLocations(Set locations) { - Set result = new HashSet<>(); - for (Feature piece : getTile().getFeatures()) { - Location loc = piece.getLocation(); - if (piece instanceof City && locations.contains(loc)) { - result.add(loc); - } - - } - return result; - } - - @Override - public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { - Position pos = getTile().getPosition(); - Set tileLocations = followerLocMap.get(pos); - if (game.getActivePlayer().hasFollower(Mayor.class)) { - if (tileLocations != null) { - Set mayorLocations = copyMayorLocations(tileLocations); - if (!mayorLocations.isEmpty()) { - actions.add(new MeepleAction(Mayor.class, pos, mayorLocations)); - } - } - } - } - - @Override - public void prepareActions(List actions, LocationsMap followerLocMap) { - prepareFollowerActions(actions, followerLocMap); - } - -} +package com.jcloisterzone.game.capability; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Mayor; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class MayorCapability extends Capability { + + public MayorCapability(Game game) { + super(game); + } + + @Override + public void initPlayer(Player player) { + player.addMeeple(new Mayor(game, player)); + } + + private Set copyMayorLocations(Set locations) { + Set result = new HashSet<>(); + for (Feature piece : getTile().getFeatures()) { + Location loc = piece.getLocation(); + if (piece instanceof City && locations.contains(loc)) { + result.add(loc); + } + + } + return result; + } + + @Override + public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { + Position pos = getTile().getPosition(); + Set tileLocations = followerLocMap.get(pos); + if (game.getActivePlayer().hasFollower(Mayor.class)) { + if (tileLocations != null) { + Set mayorLocations = copyMayorLocations(tileLocations); + if (!mayorLocations.isEmpty()) { + actions.add(new MeepleAction(Mayor.class, pos, mayorLocations)); + } + } + } + } + + @Override + public void prepareActions(List actions, LocationsMap followerLocMap) { + prepareFollowerActions(actions, followerLocMap); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/PhantomCapability.java b/src/main/java/com/jcloisterzone/game/capability/PhantomCapability.java index cc1dd286d..e808fcdd2 100644 --- a/src/main/java/com/jcloisterzone/game/capability/PhantomCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/PhantomCapability.java @@ -1,37 +1,37 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.figure.Phantom; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class PhantomCapability extends Capability { - - public PhantomCapability(Game game) { - super(game); - } - - @Override - public void initPlayer(Player player) { - player.addMeeple(new Phantom(game, player)); - } - - @Override - public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { - if (game.getActivePlayer().hasFollower(Phantom.class) && !followerLocMap.isEmpty()) { - actions.add(new MeepleAction(Phantom.class, followerLocMap)); - } - } - - @Override - public void prepareActions(List actions, LocationsMap followerLocMap) { - prepareFollowerActions(actions, followerLocMap); - } - - -} +package com.jcloisterzone.game.capability; + +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.figure.Phantom; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class PhantomCapability extends Capability { + + public PhantomCapability(Game game) { + super(game); + } + + @Override + public void initPlayer(Player player) { + player.addMeeple(new Phantom(game, player)); + } + + @Override + public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { + if (game.getActivePlayer().hasFollower(Phantom.class) && !followerLocMap.isEmpty()) { + actions.add(new MeepleAction(Phantom.class, followerLocMap)); + } + } + + @Override + public void prepareActions(List actions, LocationsMap followerLocMap) { + prepareFollowerActions(actions, followerLocMap); + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/PigCapability.java b/src/main/java/com/jcloisterzone/game/capability/PigCapability.java index b53ce9cf4..9e1124938 100644 --- a/src/main/java/com/jcloisterzone/game/capability/PigCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/PigCapability.java @@ -1,46 +1,46 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.figure.Pig; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class PigCapability extends Capability { - - public PigCapability(Game game) { - super(game); - } - - @Override - public void initPlayer(Player player) { - player.addMeeple(new Pig(game, player)); - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - Player player = game.getActivePlayer(); - if (!player.hasSpecialMeeple(Pig.class)) return; - - Tile tile = getTile(); - if (!game.isDeployAllowed(tile, Pig.class)) return; - - Position pos = tile.getPosition(); - Set locations = tile.getPlayerFeatures(player, Farm.class); - if (!locations.isEmpty()) { - MeepleAction pigAction = new MeepleAction(Pig.class); - pigAction.getOrCreate(pos).addAll(locations); - actions.add(pigAction); - } - } - -} +package com.jcloisterzone.game.capability; + +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.figure.Pig; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class PigCapability extends Capability { + + public PigCapability(Game game) { + super(game); + } + + @Override + public void initPlayer(Player player) { + player.addMeeple(new Pig(game, player)); + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + Player player = game.getActivePlayer(); + if (!player.hasSpecialMeeple(Pig.class)) return; + + Tile tile = getTile(); + if (!game.isDeployAllowed(tile, Pig.class)) return; + + Position pos = tile.getPosition(); + Set locations = tile.getPlayerFeatures(player, Farm.class); + if (!locations.isEmpty()) { + MeepleAction pigAction = new MeepleAction(Pig.class); + pigAction.getOrCreate(pos).addAll(locations); + actions.add(pigAction); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/PlagueCapability.java b/src/main/java/com/jcloisterzone/game/capability/PlagueCapability.java index cdda021b6..d0663d00b 100644 --- a/src/main/java/com/jcloisterzone/game/capability/PlagueCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/PlagueCapability.java @@ -1,82 +1,82 @@ -package com.jcloisterzone.game.capability; - -import java.util.ArrayList; -import java.util.List; - -import org.w3c.dom.Element; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class PlagueCapability extends Capability { - - private final List plagueSources = new ArrayList<>(6); - - public PlagueCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - throw new UnsupportedOperationException(); - } - - @Override - public void restore(Object data) { - throw new UnsupportedOperationException(); - } - - @Override - public void initTile(Tile tile, Element xml) { - if (xml.getElementsByTagName("plague").getLength() > 0) { - tile.setTrigger(TileTrigger.PLAGUE); - } - } - - @Override - public String getTileGroup(Tile tile) { - return tile.hasTrigger(TileTrigger.PLAGUE) ? "plague" : null; - } - - @Override - public void begin() { - //TODO replace with activation ofter 17th tile - getTilePack().activateGroup("plague"); - } - - @Override - public boolean isDeployAllowed(Tile tile, Class meepleType) { - for (PlagueSource ps : plagueSources) { - if (ps.active && ps.pos.equals(tile.getPosition())) return false; - } - //TODO check flea locations - return true; - } - - public List getPlagueSources() { - return plagueSources; - } - - public List getActiveSources() { - List result = new ArrayList<>(6); - for (PlagueSource source : plagueSources) { - if (source.active) { - result.add(source.pos); - } - } - return result; - } - - public static class PlagueSource { - public Position pos; - public boolean active = true; - - public PlagueSource(Position pos) { - this.pos = pos; - } - } -} +package com.jcloisterzone.game.capability; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Element; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class PlagueCapability extends Capability { + + private final List plagueSources = new ArrayList<>(6); + + public PlagueCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + throw new UnsupportedOperationException(); + } + + @Override + public void restore(Object data) { + throw new UnsupportedOperationException(); + } + + @Override + public void initTile(Tile tile, Element xml) { + if (xml.getElementsByTagName("plague").getLength() > 0) { + tile.setTrigger(TileTrigger.PLAGUE); + } + } + + @Override + public String getTileGroup(Tile tile) { + return tile.hasTrigger(TileTrigger.PLAGUE) ? "plague" : null; + } + + @Override + public void begin() { + //TODO replace with activation ofter 17th tile + getTilePack().activateGroup("plague"); + } + + @Override + public boolean isDeployAllowed(Tile tile, Class meepleType) { + for (PlagueSource ps : plagueSources) { + if (ps.active && ps.pos.equals(tile.getPosition())) return false; + } + //TODO check flea locations + return true; + } + + public List getPlagueSources() { + return plagueSources; + } + + public List getActiveSources() { + List result = new ArrayList<>(6); + for (PlagueSource source : plagueSources) { + if (source.active) { + result.add(source.pos); + } + } + return result; + } + + public static class PlagueSource { + public Position pos; + public boolean active = true; + + public PlagueSource(Position pos) { + this.pos = pos; + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/capability/PortalCapability.java b/src/main/java/com/jcloisterzone/game/capability/PortalCapability.java index 9e2ef8ae8..d70d4c585 100644 --- a/src/main/java/com/jcloisterzone/game/capability/PortalCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/PortalCapability.java @@ -1,47 +1,47 @@ -package com.jcloisterzone.game.capability; - -import java.util.List; -import java.util.Set; - -import org.w3c.dom.Element; - -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class PortalCapability extends Capability { - - public PortalCapability(Game game) { - super(game); - } - - @Override - public void initTile(Tile tile, Element xml) { - if (xml.getElementsByTagName("portal").getLength() > 0) { - tile.setTrigger(TileTrigger.PORTAL); - } - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - if (getTile().hasTrigger(TileTrigger.PORTAL)) { - if (game.getActivePlayer().hasFollower()) { - prepareMagicPortal(commonSites); - } - } - } - - private void prepareMagicPortal(LocationsMap commonSites) { - for (Tile tile : getBoard().getAllTiles()) { - if (tile == getTile()) continue; //prepared by basic common - Set locations = game.prepareFollowerLocations(tile, true); - if (locations.isEmpty()) continue; - commonSites.put(tile.getPosition(), locations); - } - } - -} +package com.jcloisterzone.game.capability; + +import java.util.List; +import java.util.Set; + +import org.w3c.dom.Element; + +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class PortalCapability extends Capability { + + public PortalCapability(Game game) { + super(game); + } + + @Override + public void initTile(Tile tile, Element xml) { + if (xml.getElementsByTagName("portal").getLength() > 0) { + tile.setTrigger(TileTrigger.PORTAL); + } + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + if (getTile().hasTrigger(TileTrigger.PORTAL)) { + if (game.getActivePlayer().hasFollower()) { + prepareMagicPortal(commonSites); + } + } + } + + private void prepareMagicPortal(LocationsMap commonSites) { + for (Tile tile : getBoard().getAllTiles()) { + if (tile == getTile()) continue; //prepared by basic common + Set locations = game.prepareFollowerLocations(tile, true); + if (locations.isEmpty()) continue; + commonSites.put(tile.getPosition(), locations); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/PrincessCapability.java b/src/main/java/com/jcloisterzone/game/capability/PrincessCapability.java index 8f5e903e2..68b72b1e2 100644 --- a/src/main/java/com/jcloisterzone/game/capability/PrincessCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/PrincessCapability.java @@ -1,52 +1,52 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.attributeBoolValue; - -import java.util.List; - -import org.w3c.dom.Element; - -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.PrincessAction; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.IsOccupied; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - -public class PrincessCapability extends Capability { - - public PrincessCapability(Game game) { - super(game); - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof City && attributeBoolValue(xml, "princess")) { - ((City)feature).setPricenss(true); - } - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - City c = getTile().getCityWithPrincess(); - if (c == null || ! c.walk(new IsOccupied().with(Follower.class))) return; - Feature cityRepresentative = c.getMaster(); - - PrincessAction princessAction = new PrincessAction(); - for (Meeple m : game.getDeployedMeeples()) { - if (!(m.getFeature() instanceof City)) continue; - if (m.getFeature().getMaster().equals(cityRepresentative) && m instanceof Follower) { - princessAction.getOrCreate(m.getPosition()).add(m.getLocation()); - } - } - if (!princessAction.getLocationsMap().isEmpty()) { - actions.add(princessAction); - } - } - -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.attributeBoolValue; + +import java.util.List; + +import org.w3c.dom.Element; + +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.PrincessAction; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.IsOccupied; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + +public class PrincessCapability extends Capability { + + public PrincessCapability(Game game) { + super(game); + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof City && attributeBoolValue(xml, "princess")) { + ((City)feature).setPricenss(true); + } + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + City c = getTile().getCityWithPrincess(); + if (c == null || ! c.walk(new IsOccupied().with(Follower.class))) return; + Feature cityRepresentative = c.getMaster(); + + PrincessAction princessAction = new PrincessAction(); + for (Meeple m : game.getDeployedMeeples()) { + if (!(m.getFeature() instanceof City)) continue; + if (m.getFeature().getMaster().equals(cityRepresentative) && m instanceof Follower) { + princessAction.getOrCreate(m.getPosition()).add(m.getLocation()); + } + } + if (!princessAction.getLocationsMap().isEmpty()) { + actions.add(princessAction); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/RiverCapability.java b/src/main/java/com/jcloisterzone/game/capability/RiverCapability.java index dface235a..ad97c2ef5 100644 --- a/src/main/java/com/jcloisterzone/game/capability/RiverCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/RiverCapability.java @@ -1,121 +1,121 @@ -package com.jcloisterzone.game.capability; - -import java.util.Map.Entry; -import java.util.Set; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.board.TileSymmetry; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - - -public class RiverCapability extends Capability { - - private static final String R1_LAKE_ID = "R1.I.e"; - private static final String R2_LAKE_ID = "R2.I.v"; - - public RiverCapability(Game game) { - super(game); - } - - @Override - public void initTile(Tile tile, Element xml) { - NodeList nl; - nl = xml.getElementsByTagName("river"); - assert nl.getLength() <= 1; - if (nl.getLength() == 1) { - Location river = XmlUtils.union(XmlUtils.asLocation((Element) nl.item(0))); - tile.setRiver(river); - if (tile.getSymmetry() != TileSymmetry.NONE) { - if (tile.getRiver().isRotationOf(Location.WE)) { - tile.setSymmetry(TileSymmetry.S2); - } else { - tile.setSymmetry(TileSymmetry.NONE); - } - } - } - }; - - private String getLakeId() { - return game.hasExpansion(Expansion.RIVER_II) ? R2_LAKE_ID : R1_LAKE_ID; - } - - @Override - public void begin() { - getTilePack().deactivateGroup("default"); - getTilePack().activateGroup("river-start"); - if (!game.hasExpansion(Expansion.RIVER_II)) { - getTilePack().activateGroup("river"); - } - } - - public void activateNonRiverTiles() { - getTilePack().activateGroup("default"); - getTilePack().deactivateGroup("river"); - Tile lake = getTilePack().drawTile(TilePack.INACTIVE_GROUP, getLakeId()); - getBoard().refreshAvailablePlacements(lake); - Entry> entry = getBoard().getAvailablePlacements().entrySet().iterator().next(); - lake.setRotation(entry.getValue().iterator().next()); - getBoard().add(lake, entry.getKey()); - getBoard().mergeFeatures(lake); - game.fireGameEvent().tilePlaced(lake); - } - - @Override - public void turnCleanUp() { - if (getTile().getRiver() == null) return; - if (getTilePack().isEmpty()) { - if (getTilePack().isGroupActive("river")) { - activateNonRiverTiles(); - } else { - getTilePack().deactivateGroup("river-start"); - getTilePack().activateGroup("river"); - } - } - } - - @Override - public boolean isTilePlacementAllowed(Tile tile, Position p) { - if (tile.getRiver() == null) return true; - for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { - - //check river connection - Location tileRelativePosition = e.getKey(); - Tile placedTile = e.getValue(); - if (placedTile.getRiver() == null) return false; //e.g. count of carcassone preplaced tiles - boolean r1 = tileRelativePosition.rotateCCW(tile.getRotation()).isPartOf(tile.getRiver()); - boolean r2 = tileRelativePosition.rotateCCW(placedTile.getRotation()).rev().isPartOf(placedTile.getRiver()); - if (!(r1 & r2)) return false; - - //check U-turn - Location continueRiver = tile.getRiver().rotateCW(tile.getRotation()).substract(tileRelativePosition); - if (continueRiver == Location.INNER_FARM) return true; //lake - for (Location continueSide: Location.sides()) { //split beacuse of river fork - if (continueRiver.intersect(continueSide) == null) continue; - Position pCheck = p.add(continueSide).add(continueSide.rotateCW(Rotation.R90)); - if (getBoard().get(pCheck) != null) return false; - pCheck = p.add(continueSide).add(continueSide.rotateCCW(Rotation.R90)); - if (getBoard().get(pCheck) != null) return false; - pCheck = p.add(continueSide).add(continueSide); - if (getBoard().get(pCheck) != null) return false; - //also forbid fork "parallel river" - Tile next = getBoard().get(p.add(continueSide.rotateCW(Rotation.R90))); - if (next != null && next.getRiver().rotateCW(next.getRotation()).intersect(continueSide) == continueSide) return false; - next = getBoard().get(p.add(continueSide.rotateCCW(Rotation.R90))); - if (next != null && next.getRiver().rotateCW(next.getRotation()).intersect(continueSide) == continueSide) return false; - - } - } - return true; - } - +package com.jcloisterzone.game.capability; + +import java.util.Map.Entry; +import java.util.Set; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.board.TileSymmetry; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + + +public class RiverCapability extends Capability { + + private static final String R1_LAKE_ID = "R1.I.e"; + private static final String R2_LAKE_ID = "R2.I.v"; + + public RiverCapability(Game game) { + super(game); + } + + @Override + public void initTile(Tile tile, Element xml) { + NodeList nl; + nl = xml.getElementsByTagName("river"); + assert nl.getLength() <= 1; + if (nl.getLength() == 1) { + Location river = XmlUtils.union(XmlUtils.asLocation((Element) nl.item(0))); + tile.setRiver(river); + if (tile.getSymmetry() != TileSymmetry.NONE) { + if (tile.getRiver().isRotationOf(Location.WE)) { + tile.setSymmetry(TileSymmetry.S2); + } else { + tile.setSymmetry(TileSymmetry.NONE); + } + } + } + }; + + private String getLakeId() { + return game.hasExpansion(Expansion.RIVER_II) ? R2_LAKE_ID : R1_LAKE_ID; + } + + @Override + public void begin() { + getTilePack().deactivateGroup("default"); + getTilePack().activateGroup("river-start"); + if (!game.hasExpansion(Expansion.RIVER_II)) { + getTilePack().activateGroup("river"); + } + } + + public void activateNonRiverTiles() { + getTilePack().activateGroup("default"); + getTilePack().deactivateGroup("river"); + Tile lake = getTilePack().drawTile(TilePack.INACTIVE_GROUP, getLakeId()); + getBoard().refreshAvailablePlacements(lake); + Entry> entry = getBoard().getAvailablePlacements().entrySet().iterator().next(); + lake.setRotation(entry.getValue().iterator().next()); + getBoard().add(lake, entry.getKey()); + getBoard().mergeFeatures(lake); + game.fireGameEvent().tilePlaced(lake); + } + + @Override + public void turnCleanUp() { + if (getTile().getRiver() == null) return; + if (getTilePack().isEmpty()) { + if (getTilePack().isGroupActive("river")) { + activateNonRiverTiles(); + } else { + getTilePack().deactivateGroup("river-start"); + getTilePack().activateGroup("river"); + } + } + } + + @Override + public boolean isTilePlacementAllowed(Tile tile, Position p) { + if (tile.getRiver() == null) return true; + for (Entry e : getBoard().getAdjacentTilesMap(p).entrySet()) { + + //check river connection + Location tileRelativePosition = e.getKey(); + Tile placedTile = e.getValue(); + if (placedTile.getRiver() == null) return false; //e.g. count of carcassone preplaced tiles + boolean r1 = tileRelativePosition.rotateCCW(tile.getRotation()).isPartOf(tile.getRiver()); + boolean r2 = tileRelativePosition.rotateCCW(placedTile.getRotation()).rev().isPartOf(placedTile.getRiver()); + if (!(r1 & r2)) return false; + + //check U-turn + Location continueRiver = tile.getRiver().rotateCW(tile.getRotation()).substract(tileRelativePosition); + if (continueRiver == Location.INNER_FARM) return true; //lake + for (Location continueSide: Location.sides()) { //split beacuse of river fork + if (continueRiver.intersect(continueSide) == null) continue; + Position pCheck = p.add(continueSide).add(continueSide.rotateCW(Rotation.R90)); + if (getBoard().get(pCheck) != null) return false; + pCheck = p.add(continueSide).add(continueSide.rotateCCW(Rotation.R90)); + if (getBoard().get(pCheck) != null) return false; + pCheck = p.add(continueSide).add(continueSide); + if (getBoard().get(pCheck) != null) return false; + //also forbid fork "parallel river" + Tile next = getBoard().get(p.add(continueSide.rotateCW(Rotation.R90))); + if (next != null && next.getRiver().rotateCW(next.getRotation()).intersect(continueSide) == continueSide) return false; + next = getBoard().get(p.add(continueSide.rotateCCW(Rotation.R90))); + if (next != null && next.getRiver().rotateCW(next.getRotation()).intersect(continueSide) == continueSide) return false; + + } + } + return true; + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/game/capability/ShrineCapability.java b/src/main/java/com/jcloisterzone/game/capability/ShrineCapability.java index aef154a98..4201dc42c 100644 --- a/src/main/java/com/jcloisterzone/game/capability/ShrineCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/ShrineCapability.java @@ -1,85 +1,85 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.attributeBoolValue; - -import org.w3c.dom.Element; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - - -public final class ShrineCapability extends Capability { - - public ShrineCapability(Game game) { - super(game); - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof Cloister) { - ((Cloister)feature).setShrine(attributeBoolValue(xml, "shrine")); - } - } - - public void makeCloisterChallenged(Cloister cloister) { - boolean first = true; - for (Meeple m : cloister.getMeeples()) { - if (first) { - game.fireGameEvent().scored(cloister, 0, "0", m, false); - first = false; - } - m.undeploy(); - } - } - - - public void resolveChallengedCloisters(Cloister cloister) { - Position p = cloister.getTile().getPosition(); - for (Tile nt : game.getBoard().getAdjacentAndDiagonalTiles(p)) { - if (nt.hasCloister()) { - Cloister nextCloister = nt.getCloister(); - if (cloister.isShrine() ^ nextCloister.isShrine()) { - //opposite cloisters - if (nextCloister.isOpen()) { - makeCloisterChallenged(nextCloister); - } - } - } - } - } - - @Override - public void scoreCompleted(CompletableScoreContext ctx) { - if (ctx.getMasterFeature() instanceof Cloister) { - resolveChallengedCloisters((Cloister) ctx.getMasterFeature()); - } - } - - @Override - public boolean isTilePlacementAllowed(Tile tile, Position p) { - if (tile.hasCloister()) { - int opositeCount = 0; - int sameCount = 0; - for (Tile nt: getBoard().getAdjacentAndDiagonalTiles(p)) { - if (nt.hasCloister()) { - if (tile.getCloister().isShrine() ^ nt.getCloister().isShrine()) { - opositeCount++; - } else { - sameCount++; - } - } - } - if (opositeCount > 1 || (opositeCount == 1 && sameCount > 0)) { - return false; - } - } - return true; - } - -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.attributeBoolValue; + +import org.w3c.dom.Element; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + + +public final class ShrineCapability extends Capability { + + public ShrineCapability(Game game) { + super(game); + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof Cloister) { + ((Cloister)feature).setShrine(attributeBoolValue(xml, "shrine")); + } + } + + public void makeCloisterChallenged(Cloister cloister) { + boolean first = true; + for (Meeple m : cloister.getMeeples()) { + if (first) { + game.fireGameEvent().scored(cloister, 0, "0", m, false); + first = false; + } + m.undeploy(); + } + } + + + public void resolveChallengedCloisters(Cloister cloister) { + Position p = cloister.getTile().getPosition(); + for (Tile nt : game.getBoard().getAdjacentAndDiagonalTiles(p)) { + if (nt.hasCloister()) { + Cloister nextCloister = nt.getCloister(); + if (cloister.isShrine() ^ nextCloister.isShrine()) { + //opposite cloisters + if (nextCloister.isOpen()) { + makeCloisterChallenged(nextCloister); + } + } + } + } + } + + @Override + public void scoreCompleted(CompletableScoreContext ctx) { + if (ctx.getMasterFeature() instanceof Cloister) { + resolveChallengedCloisters((Cloister) ctx.getMasterFeature()); + } + } + + @Override + public boolean isTilePlacementAllowed(Tile tile, Position p) { + if (tile.hasCloister()) { + int opositeCount = 0; + int sameCount = 0; + for (Tile nt: getBoard().getAdjacentAndDiagonalTiles(p)) { + if (nt.hasCloister()) { + if (tile.getCloister().isShrine() ^ nt.getCloister().isShrine()) { + opositeCount++; + } else { + sameCount++; + } + } + } + if (opositeCount > 1 || (opositeCount == 1 && sameCount > 0)) { + return false; + } + } + return true; + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/SiegeCapability.java b/src/main/java/com/jcloisterzone/game/capability/SiegeCapability.java index c26e4841a..c7f6923b5 100644 --- a/src/main/java/com/jcloisterzone/game/capability/SiegeCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/SiegeCapability.java @@ -1,31 +1,31 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.attributeBoolValue; - -import org.w3c.dom.Element; - -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - - -public final class SiegeCapability extends Capability { - - public SiegeCapability(Game game) { - super(game); - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (feature instanceof City && attributeBoolValue(xml, "besieged")) { - City city = (City) feature; - city.setBesieged(true); - tile.setTrigger(TileTrigger.BESIEGED); - } - } - - -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.attributeBoolValue; + +import org.w3c.dom.Element; + +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + + +public final class SiegeCapability extends Capability { + + public SiegeCapability(Game game) { + super(game); + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (feature instanceof City && attributeBoolValue(xml, "besieged")) { + City city = (City) feature; + city.setBesieged(true); + tile.setTrigger(TileTrigger.BESIEGED); + } + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/TowerCapability.java b/src/main/java/com/jcloisterzone/game/capability/TowerCapability.java index 00c1770da..b316868a0 100644 --- a/src/main/java/com/jcloisterzone/game/capability/TowerCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/TowerCapability.java @@ -1,273 +1,273 @@ -package com.jcloisterzone.game.capability; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.TowerPieceAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.figure.BigFollower; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - - -public final class TowerCapability extends Capability { - - private static final int RANSOM_POINTS = 3; - - private final Set towers = new HashSet<>(); - private final Map towerPieces = new HashMap<>(); - private boolean ransomPaidThisTurn; - - //key is Player who keeps follower imprisoned - //synchronized because of GUI is looking inside - //TODO fix gui hack - private final Map> prisoners = Collections.synchronizedMap(new HashMap>()); - - public TowerCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - Map> prisonersCopy = new HashMap<>(); - for (Entry> entry : prisoners.entrySet()) { - prisonersCopy.put(entry.getKey(), new ArrayList<>(entry.getValue())); - } - - return new Object[] { - ransomPaidThisTurn, - new HashSet<>(towers), - new HashMap<>(towerPieces), - prisonersCopy - }; - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - ransomPaidThisTurn = (Boolean) a[0]; - towers.clear(); - towers.addAll((Set) a[1]); - towerPieces.clear(); - towerPieces.putAll((Map) a[2]); - for (Entry> entry : ((Map>)a[3]).entrySet()) { - List value = prisoners.get(entry.getKey()); - value.clear(); - value.addAll(entry.getValue()); - } - } - - public void registerTower(Position p) { - towers.add(p); - } - - public Set getTowers() { - return towers; - } - - public boolean isRansomPaidThisTurn() { - return ransomPaidThisTurn; - } - - public void setRansomPaidThisTurn(boolean ransomPayedThisTurn) { - this.ransomPaidThisTurn = ransomPayedThisTurn; - } - - @Override - public void initPlayer(Player player) { - int pieces = 0; - switch(game.getAllPlayers().length) { - case 1: - case 2: pieces = 10; break; - case 3: pieces = 9; break; - case 4: pieces = 7; break; - case 5: pieces = 6; break; - case 6: pieces = 5; break; - } - towerPieces.put(player, pieces); - prisoners.put(player, Collections.synchronizedList(new ArrayList())); - } - - public int getTowerPieces(Player player) { - return towerPieces.get(player); - } - - public void decreaseTowerPieces(Player player) { - int pieces = getTowerPieces(player); - if (pieces == 0) throw new IllegalStateException("Player has no tower pieces"); - towerPieces.put(player, pieces-1); - } - - private boolean hasSmallOrBigFollower(Player p) { - return Iterables.any(p.getFollowers(), Predicates.and( - MeeplePredicates.inSupply(), MeeplePredicates.instanceOf(SmallFollower.class, BigFollower.class))); - } - - @Override - public void prepareActions(List actions, LocationsMap followerLocMap) { - if (hasSmallOrBigFollower(game.getActivePlayer())) { - prepareTowerFollowerDeploy(followerLocMap); - } - if (getTowerPieces(game.getActivePlayer()) > 0) { - Set availTowers = getOpenTowers(0); - if (!availTowers.isEmpty()) { - actions.add(new TowerPieceAction(availTowers)); - } - } - } - - public void prepareTowerFollowerDeploy(LocationsMap followerLocMap) { - Set availableTowers = getOpenTowers(1); - if (!availableTowers.isEmpty()) { - for (Position p : availableTowers) { - if (game.isDeployAllowed(getBoard().get(p), Follower.class)) { - followerLocMap.getOrCreate(p).add(Location.TOWER); - } - } - } - } - - protected Set getOpenTowers(int minHeight) { - Set availTower = new HashSet<>(); - for (Position p : getTowers()) { - Tower t = getBoard().get(p).getTower(); - if (t.getMeeple() == null && t.getHeight() >= minHeight) { - availTower.add(p); - } - } - return availTower; - } - - public Map> getPrisoners() { - return prisoners; - } - - public boolean hasImprisonedFollower(Player followerOwner) { - for (Follower m : followerOwner.getFollowers()) { - if (m.getLocation() == Location.PRISON) return true; - } - return false; - } - - public boolean hasImprisonedFollower(Player followerOwner, Class followerClass) { - for (Follower m : followerOwner.getFollowers()) { - if (m.getLocation() == Location.PRISON && m.getClass().equals(followerClass)) return true; - } - return false; - } - - public void inprison(Meeple m, Player player) { - assert m.getLocation() == null; - prisoners.get(player).add((Follower) m); - m.setLocation(Location.PRISON); - } - - public void payRansom(Integer playerIndexToPay, Class meepleType) { - if (ransomPaidThisTurn) { - throw new IllegalStateException("Ransom alreasy paid this turn"); - } - Player opponent = game.getAllPlayers()[playerIndexToPay]; - - Iterator i = prisoners.get(opponent).iterator(); - while (i.hasNext()) { - Follower meeple = i.next(); - if (meepleType.isInstance(meeple)) { - i.remove(); - game.fireGameEvent().undeployed(meeple); - meeple.clearDeployment(); - opponent.addPoints(RANSOM_POINTS, PointCategory.TOWER_RANSOM); - ransomPaidThisTurn = true; - game.getActivePlayer().addPoints(-RANSOM_POINTS, PointCategory.TOWER_RANSOM); - game.fireGameEvent().ransomPaid(game.getActivePlayer(), opponent, meeple); - game.getPhase().notifyRansomPaid(); - return; - } - } - throw new IllegalStateException("Opponent has no figure to exchage"); - } - - @Override - public void turnCleanUp() { - ransomPaidThisTurn = false; - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - node.setAttribute("ransomPaid", ransomPaidThisTurn + ""); - for (Position towerPos : towers) { - Tower tower = getBoard().get(towerPos).getTower(); - Element el = doc.createElement("tower"); - node.appendChild(el); - XmlUtils.injectPosition(el, towerPos); - el.setAttribute("height", "" + tower.getHeight()); - } - for (Player player: game.getAllPlayers()) { - Element el = doc.createElement("player"); - node.appendChild(el); - el.setAttribute("index", "" + player.getIndex()); - el.setAttribute("pieces", "" + getTowerPieces(player)); - for (Follower follower : prisoners.get(player)) { - Element prisoner = doc.createElement("prisoner"); - el.appendChild(prisoner); - prisoner.setAttribute("player", "" + follower.getPlayer().getIndex()); - prisoner.setAttribute("type", "" + follower.getClass().getName()); - } - } - } - - @SuppressWarnings("unchecked") - @Override - public void loadFromSnapshot(Document doc, Element node) { - ransomPaidThisTurn = Boolean.parseBoolean(node.getAttribute("ransomPaid")); - NodeList nl = node.getElementsByTagName("tower"); - for (int i = 0; i < nl.getLength(); i++) { - Element te = (Element) nl.item(i); - Position towerPos = XmlUtils.extractPosition(te); - Tower tower = getBoard().get(towerPos).getTower(); - tower.setHeight(Integer.parseInt(te.getAttribute("height"))); - towers.add(towerPos); - if (tower.getHeight() > 0) { - game.fireGameEvent().towerIncreased(towerPos, tower.getHeight()); - } - } - nl = node.getElementsByTagName("player"); - for (int i = 0; i < nl.getLength(); i++) { - Element playerEl = (Element) nl.item(i); - Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); - towerPieces.put(player, Integer.parseInt(playerEl.getAttribute("pieces"))); - NodeList priosonerNl = playerEl.getElementsByTagName("prisoner"); - for (int j = 0; j < priosonerNl.getLength(); j++) { - Element prisonerEl = (Element) priosonerNl.item(j); - int ownerIndex = XmlUtils.attributeIntValue(prisonerEl, "player"); - Class meepleClass = (Class) XmlUtils.classForName(prisonerEl.getAttribute("type")); - Meeple m = game.getPlayer(ownerIndex).getMeepleFromSupply(meepleClass); - inprison(m, player); - } - } - } -} +package com.jcloisterzone.game.capability; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.google.common.base.Predicates; +import com.google.common.collect.Iterables; +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.TowerPieceAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.figure.BigFollower; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + + +public final class TowerCapability extends Capability { + + private static final int RANSOM_POINTS = 3; + + private final Set towers = new HashSet<>(); + private final Map towerPieces = new HashMap<>(); + private boolean ransomPaidThisTurn; + + //key is Player who keeps follower imprisoned + //synchronized because of GUI is looking inside + //TODO fix gui hack + private final Map> prisoners = Collections.synchronizedMap(new HashMap>()); + + public TowerCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + Map> prisonersCopy = new HashMap<>(); + for (Entry> entry : prisoners.entrySet()) { + prisonersCopy.put(entry.getKey(), new ArrayList<>(entry.getValue())); + } + + return new Object[] { + ransomPaidThisTurn, + new HashSet<>(towers), + new HashMap<>(towerPieces), + prisonersCopy + }; + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + ransomPaidThisTurn = (Boolean) a[0]; + towers.clear(); + towers.addAll((Set) a[1]); + towerPieces.clear(); + towerPieces.putAll((Map) a[2]); + for (Entry> entry : ((Map>)a[3]).entrySet()) { + List value = prisoners.get(entry.getKey()); + value.clear(); + value.addAll(entry.getValue()); + } + } + + public void registerTower(Position p) { + towers.add(p); + } + + public Set getTowers() { + return towers; + } + + public boolean isRansomPaidThisTurn() { + return ransomPaidThisTurn; + } + + public void setRansomPaidThisTurn(boolean ransomPayedThisTurn) { + this.ransomPaidThisTurn = ransomPayedThisTurn; + } + + @Override + public void initPlayer(Player player) { + int pieces = 0; + switch(game.getAllPlayers().length) { + case 1: + case 2: pieces = 10; break; + case 3: pieces = 9; break; + case 4: pieces = 7; break; + case 5: pieces = 6; break; + case 6: pieces = 5; break; + } + towerPieces.put(player, pieces); + prisoners.put(player, Collections.synchronizedList(new ArrayList())); + } + + public int getTowerPieces(Player player) { + return towerPieces.get(player); + } + + public void decreaseTowerPieces(Player player) { + int pieces = getTowerPieces(player); + if (pieces == 0) throw new IllegalStateException("Player has no tower pieces"); + towerPieces.put(player, pieces-1); + } + + private boolean hasSmallOrBigFollower(Player p) { + return Iterables.any(p.getFollowers(), Predicates.and( + MeeplePredicates.inSupply(), MeeplePredicates.instanceOf(SmallFollower.class, BigFollower.class))); + } + + @Override + public void prepareActions(List actions, LocationsMap followerLocMap) { + if (hasSmallOrBigFollower(game.getActivePlayer())) { + prepareTowerFollowerDeploy(followerLocMap); + } + if (getTowerPieces(game.getActivePlayer()) > 0) { + Set availTowers = getOpenTowers(0); + if (!availTowers.isEmpty()) { + actions.add(new TowerPieceAction(availTowers)); + } + } + } + + public void prepareTowerFollowerDeploy(LocationsMap followerLocMap) { + Set availableTowers = getOpenTowers(1); + if (!availableTowers.isEmpty()) { + for (Position p : availableTowers) { + if (game.isDeployAllowed(getBoard().get(p), Follower.class)) { + followerLocMap.getOrCreate(p).add(Location.TOWER); + } + } + } + } + + protected Set getOpenTowers(int minHeight) { + Set availTower = new HashSet<>(); + for (Position p : getTowers()) { + Tower t = getBoard().get(p).getTower(); + if (t.getMeeple() == null && t.getHeight() >= minHeight) { + availTower.add(p); + } + } + return availTower; + } + + public Map> getPrisoners() { + return prisoners; + } + + public boolean hasImprisonedFollower(Player followerOwner) { + for (Follower m : followerOwner.getFollowers()) { + if (m.getLocation() == Location.PRISON) return true; + } + return false; + } + + public boolean hasImprisonedFollower(Player followerOwner, Class followerClass) { + for (Follower m : followerOwner.getFollowers()) { + if (m.getLocation() == Location.PRISON && m.getClass().equals(followerClass)) return true; + } + return false; + } + + public void inprison(Meeple m, Player player) { + assert m.getLocation() == null; + prisoners.get(player).add((Follower) m); + m.setLocation(Location.PRISON); + } + + public void payRansom(Integer playerIndexToPay, Class meepleType) { + if (ransomPaidThisTurn) { + throw new IllegalStateException("Ransom alreasy paid this turn"); + } + Player opponent = game.getAllPlayers()[playerIndexToPay]; + + Iterator i = prisoners.get(opponent).iterator(); + while (i.hasNext()) { + Follower meeple = i.next(); + if (meepleType.isInstance(meeple)) { + i.remove(); + game.fireGameEvent().undeployed(meeple); + meeple.clearDeployment(); + opponent.addPoints(RANSOM_POINTS, PointCategory.TOWER_RANSOM); + ransomPaidThisTurn = true; + game.getActivePlayer().addPoints(-RANSOM_POINTS, PointCategory.TOWER_RANSOM); + game.fireGameEvent().ransomPaid(game.getActivePlayer(), opponent, meeple); + game.getPhase().notifyRansomPaid(); + return; + } + } + throw new IllegalStateException("Opponent has no figure to exchage"); + } + + @Override + public void turnCleanUp() { + ransomPaidThisTurn = false; + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + node.setAttribute("ransomPaid", ransomPaidThisTurn + ""); + for (Position towerPos : towers) { + Tower tower = getBoard().get(towerPos).getTower(); + Element el = doc.createElement("tower"); + node.appendChild(el); + XmlUtils.injectPosition(el, towerPos); + el.setAttribute("height", "" + tower.getHeight()); + } + for (Player player: game.getAllPlayers()) { + Element el = doc.createElement("player"); + node.appendChild(el); + el.setAttribute("index", "" + player.getIndex()); + el.setAttribute("pieces", "" + getTowerPieces(player)); + for (Follower follower : prisoners.get(player)) { + Element prisoner = doc.createElement("prisoner"); + el.appendChild(prisoner); + prisoner.setAttribute("player", "" + follower.getPlayer().getIndex()); + prisoner.setAttribute("type", "" + follower.getClass().getName()); + } + } + } + + @SuppressWarnings("unchecked") + @Override + public void loadFromSnapshot(Document doc, Element node) { + ransomPaidThisTurn = Boolean.parseBoolean(node.getAttribute("ransomPaid")); + NodeList nl = node.getElementsByTagName("tower"); + for (int i = 0; i < nl.getLength(); i++) { + Element te = (Element) nl.item(i); + Position towerPos = XmlUtils.extractPosition(te); + Tower tower = getBoard().get(towerPos).getTower(); + tower.setHeight(Integer.parseInt(te.getAttribute("height"))); + towers.add(towerPos); + if (tower.getHeight() > 0) { + game.fireGameEvent().towerIncreased(towerPos, tower.getHeight()); + } + } + nl = node.getElementsByTagName("player"); + for (int i = 0; i < nl.getLength(); i++) { + Element playerEl = (Element) nl.item(i); + Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index"))); + towerPieces.put(player, Integer.parseInt(playerEl.getAttribute("pieces"))); + NodeList priosonerNl = playerEl.getElementsByTagName("prisoner"); + for (int j = 0; j < priosonerNl.getLength(); j++) { + Element prisonerEl = (Element) priosonerNl.item(j); + int ownerIndex = XmlUtils.attributeIntValue(prisonerEl, "player"); + Class meepleClass = (Class) XmlUtils.classForName(prisonerEl.getAttribute("type")); + Meeple m = game.getPlayer(ownerIndex).getMeepleFromSupply(meepleClass); + inprison(m, player); + } + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/capability/TunnelCapability.java b/src/main/java/com/jcloisterzone/game/capability/TunnelCapability.java index 3aeac63c2..181ef5675 100644 --- a/src/main/java/com/jcloisterzone/game/capability/TunnelCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/TunnelCapability.java @@ -1,192 +1,192 @@ -package com.jcloisterzone.game.capability; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.google.common.base.Predicate; -import com.google.common.collect.Collections2; -import com.jcloisterzone.Player; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.TunnelAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; - - -public final class TunnelCapability extends Capability { - - private Road placedTunnelCurrentTurn; - - private final Map tunnelTokensA = new HashMap<>(); - private final Map tunnelTokensB = new HashMap<>(); - - private final List tunnels = new ArrayList<>(); - - public TunnelCapability(Game game) { - super(game); - } - - @Override - public Object backup() { - return new Object[] { - placedTunnelCurrentTurn, - new HashMap<>(tunnelTokensA), - new HashMap<>(tunnelTokensB) - }; - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - placedTunnelCurrentTurn = (Road) a[0]; - tunnelTokensA.clear(); - tunnelTokensA.putAll((Map)a[1]); - tunnelTokensA.clear(); - tunnelTokensA.putAll((Map)a[2]); - } - - @Override - public void initPlayer(Player player) { - tunnelTokensA.put(player, 2); - tunnelTokensB.put(player, game.getAllPlayers().length <= 2 ? 2 : 0); - } - - @Override - public void initFeature(Tile tile, Feature feature, Element xml) { - if (!(feature instanceof Road)) return; - Road road = (Road) feature; - if (road.isTunnelEnd()) { - tunnels.add(road); - } - } - - public Collection getOpenTunnels() { - return Collections2.filter(tunnels, new Predicate() { - @Override - public boolean apply(Road road) { - if (road.getTile().getPosition() == null) return false; - return road.isTunnelOpen(); - } - }); - } - - public int getTunnelTokens(Player player, boolean isB) { - Map map = isB ? tunnelTokensB : tunnelTokensA; - return map.get(player); - } - - public void decreaseTunnelTokens(Player player, boolean isB) { - Map map = isB ? tunnelTokensB : tunnelTokensA; - int tokens = map.get(player); - if (tokens == 0) throw new IllegalStateException("Player has no tunnel token"); - map.put(player, tokens-1); - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - if (isTunnelUsedThisTurn()) return; - //TODO double iteration over tunnels - if (getOpenTunnels().isEmpty()) return; - TunnelAction tunnelAction = null; - LocationsMap sites = new LocationsMap(); - if (getTunnelTokens(game.getActivePlayer(), false) > 0) { - tunnelAction = new TunnelAction(false, sites); - actions.add(tunnelAction); - } - if (getTunnelTokens(game.getActivePlayer(), true) > 0) { - tunnelAction = new TunnelAction(true, sites); - actions.add(tunnelAction); - } - //tunnel actions share sites object - if (tunnelAction != null) { - for (Road tunnelEnd : getOpenTunnels()) { - tunnelAction.getOrCreate(tunnelEnd.getTile().getPosition()).add(tunnelEnd.getLocation()); - } - } - } - - public boolean isTunnelUsedThisTurn() { - return placedTunnelCurrentTurn != null; - } - public Road getPlacedTunnel() { - return placedTunnelCurrentTurn; - } - - - @Override - public void turnCleanUp() { - placedTunnelCurrentTurn = null; - } - - private int getTunnelId(Player p, boolean isB) { - return p.getIndex() + (isB ? 100 : 0); - } - - public void placeTunnelPiece(Position p, Location d, boolean isB) { - Road road = (Road) getBoard().get(p).getFeature(d); - if (!road.isTunnelOpen()) { - throw new IllegalStateException("No open tunnel here."); - } - Player player = game.getActivePlayer(); - int connectionId = getTunnelId(player, isB); - decreaseTunnelTokens(player, isB); - for (Road r : tunnels) { - if (r.getTunnelEnd() == connectionId) { - r.setTunnelEdge(road); - road.setTunnelEdge(r); - break; - } - } - road.setTunnelEnd(connectionId); - placedTunnelCurrentTurn = road; - game.fireGameEvent().tunnelPiecePlaced(player, p, d, isB); - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - for (Road tunnel : tunnels) { - if (tunnel.getTile().getPosition() != null && tunnel.getTunnelEnd() != Road.OPEN_TUNNEL) { - Element el = doc.createElement("tunnel"); - node.appendChild(el); - XmlUtils.injectPosition(el, tunnel.getTile().getPosition()); - el.setAttribute("location", tunnel.getLocation().toString()); - el.setAttribute("player", "" + (tunnel.getTunnelEnd() % 100)); - el.setAttribute("b", tunnel.getTunnelEnd() > 100 ? "yes" : "no"); - } - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("tunnel"); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - Position pos = XmlUtils.extractPosition(el); - Location loc = Location.valueOf(el.getAttribute("location")); - Road road = (Road) getBoard().get(pos).getFeature(loc); - if (!road.isTunnelEnd()) { - logger.error("Tunnel end does not exist."); - continue; - } - Player player = game.getPlayer(Integer.parseInt(el.getAttribute("player"))); - boolean isB = "yes".equals(el.getAttribute("b")); - road.setTunnelEnd(getTunnelId(player, isB)); - game.fireGameEvent().tunnelPiecePlaced(player, pos, loc, isB); - } - } - -} +package com.jcloisterzone.game.capability; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; +import com.jcloisterzone.Player; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.TunnelAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; + + +public final class TunnelCapability extends Capability { + + private Road placedTunnelCurrentTurn; + + private final Map tunnelTokensA = new HashMap<>(); + private final Map tunnelTokensB = new HashMap<>(); + + private final List tunnels = new ArrayList<>(); + + public TunnelCapability(Game game) { + super(game); + } + + @Override + public Object backup() { + return new Object[] { + placedTunnelCurrentTurn, + new HashMap<>(tunnelTokensA), + new HashMap<>(tunnelTokensB) + }; + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + placedTunnelCurrentTurn = (Road) a[0]; + tunnelTokensA.clear(); + tunnelTokensA.putAll((Map)a[1]); + tunnelTokensA.clear(); + tunnelTokensA.putAll((Map)a[2]); + } + + @Override + public void initPlayer(Player player) { + tunnelTokensA.put(player, 2); + tunnelTokensB.put(player, game.getAllPlayers().length <= 2 ? 2 : 0); + } + + @Override + public void initFeature(Tile tile, Feature feature, Element xml) { + if (!(feature instanceof Road)) return; + Road road = (Road) feature; + if (road.isTunnelEnd()) { + tunnels.add(road); + } + } + + public Collection getOpenTunnels() { + return Collections2.filter(tunnels, new Predicate() { + @Override + public boolean apply(Road road) { + if (road.getTile().getPosition() == null) return false; + return road.isTunnelOpen(); + } + }); + } + + public int getTunnelTokens(Player player, boolean isB) { + Map map = isB ? tunnelTokensB : tunnelTokensA; + return map.get(player); + } + + public void decreaseTunnelTokens(Player player, boolean isB) { + Map map = isB ? tunnelTokensB : tunnelTokensA; + int tokens = map.get(player); + if (tokens == 0) throw new IllegalStateException("Player has no tunnel token"); + map.put(player, tokens-1); + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + if (isTunnelUsedThisTurn()) return; + //TODO double iteration over tunnels + if (getOpenTunnels().isEmpty()) return; + TunnelAction tunnelAction = null; + LocationsMap sites = new LocationsMap(); + if (getTunnelTokens(game.getActivePlayer(), false) > 0) { + tunnelAction = new TunnelAction(false, sites); + actions.add(tunnelAction); + } + if (getTunnelTokens(game.getActivePlayer(), true) > 0) { + tunnelAction = new TunnelAction(true, sites); + actions.add(tunnelAction); + } + //tunnel actions share sites object + if (tunnelAction != null) { + for (Road tunnelEnd : getOpenTunnels()) { + tunnelAction.getOrCreate(tunnelEnd.getTile().getPosition()).add(tunnelEnd.getLocation()); + } + } + } + + public boolean isTunnelUsedThisTurn() { + return placedTunnelCurrentTurn != null; + } + public Road getPlacedTunnel() { + return placedTunnelCurrentTurn; + } + + + @Override + public void turnCleanUp() { + placedTunnelCurrentTurn = null; + } + + private int getTunnelId(Player p, boolean isB) { + return p.getIndex() + (isB ? 100 : 0); + } + + public void placeTunnelPiece(Position p, Location d, boolean isB) { + Road road = (Road) getBoard().get(p).getFeature(d); + if (!road.isTunnelOpen()) { + throw new IllegalStateException("No open tunnel here."); + } + Player player = game.getActivePlayer(); + int connectionId = getTunnelId(player, isB); + decreaseTunnelTokens(player, isB); + for (Road r : tunnels) { + if (r.getTunnelEnd() == connectionId) { + r.setTunnelEdge(road); + road.setTunnelEdge(r); + break; + } + } + road.setTunnelEnd(connectionId); + placedTunnelCurrentTurn = road; + game.fireGameEvent().tunnelPiecePlaced(player, p, d, isB); + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + for (Road tunnel : tunnels) { + if (tunnel.getTile().getPosition() != null && tunnel.getTunnelEnd() != Road.OPEN_TUNNEL) { + Element el = doc.createElement("tunnel"); + node.appendChild(el); + XmlUtils.injectPosition(el, tunnel.getTile().getPosition()); + el.setAttribute("location", tunnel.getLocation().toString()); + el.setAttribute("player", "" + (tunnel.getTunnelEnd() % 100)); + el.setAttribute("b", tunnel.getTunnelEnd() > 100 ? "yes" : "no"); + } + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("tunnel"); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + Position pos = XmlUtils.extractPosition(el); + Location loc = Location.valueOf(el.getAttribute("location")); + Road road = (Road) getBoard().get(pos).getFeature(loc); + if (!road.isTunnelEnd()) { + logger.error("Tunnel end does not exist."); + continue; + } + Player player = game.getPlayer(Integer.parseInt(el.getAttribute("player"))); + boolean isB = "yes".equals(el.getAttribute("b")); + road.setTunnelEnd(getTunnelId(player, isB)); + game.fireGameEvent().tunnelPiecePlaced(player, pos, loc, isB); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/WagonCapability.java b/src/main/java/com/jcloisterzone/game/capability/WagonCapability.java index 013b514ee..ef466efb8 100644 --- a/src/main/java/com/jcloisterzone/game/capability/WagonCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/WagonCapability.java @@ -1,178 +1,178 @@ -package com.jcloisterzone.game.capability; - -import static com.jcloisterzone.XmlUtils.asLocation; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.TileFeature; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Wagon; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.phase.ScorePhase; - -public class WagonCapability extends Capability { - - private final Map returnedWagons = new HashMap<>(); - private Player wagonPlayer; - - public WagonCapability(final Game game) { - super(game); - } - - @Override - public void undeployed(Meeple m) { - if (m instanceof Wagon && game.getPhase() instanceof ScorePhase) { - returnedWagons.put(m.getPlayer(), m.getFeature()); - } - } - - @Override - public Object backup() { - return new Object[] { - wagonPlayer, - new HashMap<>(returnedWagons) - }; - } - - @SuppressWarnings("unchecked") - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - wagonPlayer = (Player) a[0]; - returnedWagons.clear(); - returnedWagons.putAll((Map) a[1]); - } - - @Override - public void initPlayer(Player player) { - player.addMeeple(new Wagon(game, player)); - } - - public Map getReturnedWagons() { - return returnedWagons; - } - - @Override - public void initTile(Tile tile, Element xml) { - NodeList nl = xml.getElementsByTagName("wagon-move"); - assert nl.getLength() <= 1; - if (nl.getLength() == 1) { - nl = ((Element) nl.item(0)).getElementsByTagName("neighbouring"); - for (int i = 0; i < nl.getLength(); i++) { - processNeighbouringElement(tile, (Element) nl.item(i)); - } - } - } - - private void processNeighbouringElement(Tile tile, Element e) { - String[] sides = asLocation(e); - Feature[] te = new Feature[sides.length]; - for (int i = 0; i < te.length; i++) { - te[i] = tile.getFeaturePartOf(Location.valueOf(sides[i])); - } - for (int i = 0; i < te.length; i++) { - Feature[] neighbouring = new Feature[te.length - 1]; - int ni = 0; - for (int j = 0; j < te.length; j++) { - if (j == i) - continue; - neighbouring[ni++] = te[j]; - } - ((TileFeature) te[i]).addNeighbouring(neighbouring); - } - } - - @Override - public void turnCleanUp() { - returnedWagons.clear(); - wagonPlayer = null; - } - - private Set copyWagonsLocations(Set locations) { - Set result = new HashSet<>(); - for (Feature piece : getTile().getFeatures()) { - Location loc = piece.getLocation(); - if (piece instanceof Road || piece instanceof City || piece instanceof Cloister) { - if (locations.contains(loc)) { - result.add(loc); - } - } - - } - return result; - } - - @Override - public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { - Position pos = getTile().getPosition(); - Set tileLocations = followerLocMap.get(pos); - if (game.getActivePlayer().hasFollower(Wagon.class)) { - if (tileLocations != null) { - Set wagonLocations = copyWagonsLocations(tileLocations); - if (!wagonLocations.isEmpty()) { - actions.add(new MeepleAction(Wagon.class, pos, wagonLocations)); - } - } - } - } - - @Override - public void prepareActions(List actions, LocationsMap commonSites) { - prepareFollowerActions(actions, commonSites); - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - for (Entry rv : returnedWagons.entrySet()) { - Element el = doc.createElement("wagon"); - el.setAttribute("player", "" + rv.getKey().getIndex()); - el.setAttribute("loc", "" + rv.getValue().getLocation()); - XmlUtils.injectPosition(el, rv.getValue().getTile().getPosition()); - node.appendChild(el); - } - } - - @Override - public void loadFromSnapshot(Document doc, Element node) { - NodeList nl = node.getElementsByTagName("wagon"); - for (int i = 0; i < nl.getLength(); i++) { - Element wg = (Element) nl.item(i); - Location loc = Location.valueOf(wg.getAttribute("loc")); - Position pos = XmlUtils.extractPosition(wg); - int playerIndex = Integer.parseInt(wg.getAttribute("player")); - Player player = game.getPlayer(playerIndex); - returnedWagons.put(player, getBoard().get(pos).getFeature(loc)); - } - } - - public Player getWagonPlayer() { - return wagonPlayer; - } - - public void setWagonPlayer(Player wagonPlayer) { - this.wagonPlayer = wagonPlayer; - } - -} +package com.jcloisterzone.game.capability; + +import static com.jcloisterzone.XmlUtils.asLocation; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.TileFeature; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Wagon; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.phase.ScorePhase; + +public class WagonCapability extends Capability { + + private final Map returnedWagons = new HashMap<>(); + private Player wagonPlayer; + + public WagonCapability(final Game game) { + super(game); + } + + @Override + public void undeployed(Meeple m) { + if (m instanceof Wagon && game.getPhase() instanceof ScorePhase) { + returnedWagons.put(m.getPlayer(), m.getFeature()); + } + } + + @Override + public Object backup() { + return new Object[] { + wagonPlayer, + new HashMap<>(returnedWagons) + }; + } + + @SuppressWarnings("unchecked") + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + wagonPlayer = (Player) a[0]; + returnedWagons.clear(); + returnedWagons.putAll((Map) a[1]); + } + + @Override + public void initPlayer(Player player) { + player.addMeeple(new Wagon(game, player)); + } + + public Map getReturnedWagons() { + return returnedWagons; + } + + @Override + public void initTile(Tile tile, Element xml) { + NodeList nl = xml.getElementsByTagName("wagon-move"); + assert nl.getLength() <= 1; + if (nl.getLength() == 1) { + nl = ((Element) nl.item(0)).getElementsByTagName("neighbouring"); + for (int i = 0; i < nl.getLength(); i++) { + processNeighbouringElement(tile, (Element) nl.item(i)); + } + } + } + + private void processNeighbouringElement(Tile tile, Element e) { + String[] sides = asLocation(e); + Feature[] te = new Feature[sides.length]; + for (int i = 0; i < te.length; i++) { + te[i] = tile.getFeaturePartOf(Location.valueOf(sides[i])); + } + for (int i = 0; i < te.length; i++) { + Feature[] neighbouring = new Feature[te.length - 1]; + int ni = 0; + for (int j = 0; j < te.length; j++) { + if (j == i) + continue; + neighbouring[ni++] = te[j]; + } + ((TileFeature) te[i]).addNeighbouring(neighbouring); + } + } + + @Override + public void turnCleanUp() { + returnedWagons.clear(); + wagonPlayer = null; + } + + private Set copyWagonsLocations(Set locations) { + Set result = new HashSet<>(); + for (Feature piece : getTile().getFeatures()) { + Location loc = piece.getLocation(); + if (piece instanceof Road || piece instanceof City || piece instanceof Cloister) { + if (locations.contains(loc)) { + result.add(loc); + } + } + + } + return result; + } + + @Override + public void prepareFollowerActions(List actions, LocationsMap followerLocMap) { + Position pos = getTile().getPosition(); + Set tileLocations = followerLocMap.get(pos); + if (game.getActivePlayer().hasFollower(Wagon.class)) { + if (tileLocations != null) { + Set wagonLocations = copyWagonsLocations(tileLocations); + if (!wagonLocations.isEmpty()) { + actions.add(new MeepleAction(Wagon.class, pos, wagonLocations)); + } + } + } + } + + @Override + public void prepareActions(List actions, LocationsMap commonSites) { + prepareFollowerActions(actions, commonSites); + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + for (Entry rv : returnedWagons.entrySet()) { + Element el = doc.createElement("wagon"); + el.setAttribute("player", "" + rv.getKey().getIndex()); + el.setAttribute("loc", "" + rv.getValue().getLocation()); + XmlUtils.injectPosition(el, rv.getValue().getTile().getPosition()); + node.appendChild(el); + } + } + + @Override + public void loadFromSnapshot(Document doc, Element node) { + NodeList nl = node.getElementsByTagName("wagon"); + for (int i = 0; i < nl.getLength(); i++) { + Element wg = (Element) nl.item(i); + Location loc = Location.valueOf(wg.getAttribute("loc")); + Position pos = XmlUtils.extractPosition(wg); + int playerIndex = Integer.parseInt(wg.getAttribute("player")); + Player player = game.getPlayer(playerIndex); + returnedWagons.put(player, getBoard().get(pos).getFeature(loc)); + } + } + + public Player getWagonPlayer() { + return wagonPlayer; + } + + public void setWagonPlayer(Player wagonPlayer) { + this.wagonPlayer = wagonPlayer; + } + +} diff --git a/src/main/java/com/jcloisterzone/game/capability/WindRoseCapability.java b/src/main/java/com/jcloisterzone/game/capability/WindRoseCapability.java index 0caf9ba6c..83b7a0703 100644 --- a/src/main/java/com/jcloisterzone/game/capability/WindRoseCapability.java +++ b/src/main/java/com/jcloisterzone/game/capability/WindRoseCapability.java @@ -1,93 +1,93 @@ -package com.jcloisterzone.game.capability; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.SnapshotCorruptedException; - -public class WindRoseCapability extends Capability { - - public static final int WIND_ROSE_POINTS = 3; - - private Rotation roseRotation; - private Position rosePosition; - - public WindRoseCapability(final Game game) { - super(game); - } - - @Override - public void tilePlaced(Tile tile) { - Location rose = tile.getWindRose(); - if (rose == null) return; - if (rose == Location.NWSE) { - roseRotation = tile.getRotation(); - rosePosition = tile.getPosition(); - } else { - rose = rose.rotateCW(roseRotation); - if (isInProperQuadrant(rose, tile.getPosition())) { - Player p = game.getActivePlayer(); - p.addPoints(WIND_ROSE_POINTS, PointCategory.WIND_ROSE); - game.fireGameEvent().scored(tile.getPosition(), p, WIND_ROSE_POINTS, WIND_ROSE_POINTS+"", false); - } - } - } - - @Override - public Object backup() { - return new Object[] { rosePosition, roseRotation }; - } - - @Override - public void restore(Object data) { - Object[] a = (Object[]) data; - rosePosition = (Position) a[0]; - roseRotation = (Rotation) a[1]; - } - - @Override - public void initTile(Tile tile, Element xml) { - if (xml.hasAttribute("wind-rose")) { - Location loc = Location.valueOf(xml.getAttribute("wind-rose")); - tile.setWindRose(loc); - } - } - - private boolean isInProperQuadrant(Location rose, Position pos) { - if (rose == Location.NW) { - return pos.x <= rosePosition.x && pos.y <= rosePosition.y; - } - if (rose == Location.NE) { - return pos.x >= rosePosition.x && pos.y <= rosePosition.y; - } - if (rose == Location.SW) { - return pos.x <= rosePosition.x && pos.y >= rosePosition.y; - } - if (rose == Location.SE) { - return pos.x >= rosePosition.x && pos.y >= rosePosition.y; - } - throw new IllegalArgumentException("Wrong rose argument"); - } - - @Override - public void saveToSnapshot(Document doc, Element node) { - node.setAttribute("rotation", roseRotation.name()); - XmlUtils.injectPosition(node, rosePosition); - } - - @Override - public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { - roseRotation = Rotation.valueOf(node.getAttribute("rotation")); - rosePosition = XmlUtils.extractPosition(node); - } - -} +package com.jcloisterzone.game.capability; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.SnapshotCorruptedException; + +public class WindRoseCapability extends Capability { + + public static final int WIND_ROSE_POINTS = 3; + + private Rotation roseRotation; + private Position rosePosition; + + public WindRoseCapability(final Game game) { + super(game); + } + + @Override + public void tilePlaced(Tile tile) { + Location rose = tile.getWindRose(); + if (rose == null) return; + if (rose == Location.NWSE) { + roseRotation = tile.getRotation(); + rosePosition = tile.getPosition(); + } else { + rose = rose.rotateCW(roseRotation); + if (isInProperQuadrant(rose, tile.getPosition())) { + Player p = game.getActivePlayer(); + p.addPoints(WIND_ROSE_POINTS, PointCategory.WIND_ROSE); + game.fireGameEvent().scored(tile.getPosition(), p, WIND_ROSE_POINTS, WIND_ROSE_POINTS+"", false); + } + } + } + + @Override + public Object backup() { + return new Object[] { rosePosition, roseRotation }; + } + + @Override + public void restore(Object data) { + Object[] a = (Object[]) data; + rosePosition = (Position) a[0]; + roseRotation = (Rotation) a[1]; + } + + @Override + public void initTile(Tile tile, Element xml) { + if (xml.hasAttribute("wind-rose")) { + Location loc = Location.valueOf(xml.getAttribute("wind-rose")); + tile.setWindRose(loc); + } + } + + private boolean isInProperQuadrant(Location rose, Position pos) { + if (rose == Location.NW) { + return pos.x <= rosePosition.x && pos.y <= rosePosition.y; + } + if (rose == Location.NE) { + return pos.x >= rosePosition.x && pos.y <= rosePosition.y; + } + if (rose == Location.SW) { + return pos.x <= rosePosition.x && pos.y >= rosePosition.y; + } + if (rose == Location.SE) { + return pos.x >= rosePosition.x && pos.y >= rosePosition.y; + } + throw new IllegalArgumentException("Wrong rose argument"); + } + + @Override + public void saveToSnapshot(Document doc, Element node) { + node.setAttribute("rotation", roseRotation.name()); + XmlUtils.injectPosition(node, rosePosition); + } + + @Override + public void loadFromSnapshot(Document doc, Element node) throws SnapshotCorruptedException { + roseRotation = Rotation.valueOf(node.getAttribute("rotation")); + rosePosition = XmlUtils.extractPosition(node); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/AbbeyPhase.java b/src/main/java/com/jcloisterzone/game/phase/AbbeyPhase.java index 9a631f594..cc29acf63 100644 --- a/src/main/java/com/jcloisterzone/game/phase/AbbeyPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/AbbeyPhase.java @@ -1,56 +1,56 @@ -package com.jcloisterzone.game.phase; - -import com.jcloisterzone.action.AbbeyPlacementAction; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.AbbeyCapability; -import com.jcloisterzone.game.capability.BazaarCapability; - -public class AbbeyPhase extends Phase { - - private AbbeyCapability abbeyCap; - private BazaarCapability bazaarCap; - - public AbbeyPhase(Game game) { - super(game); - abbeyCap = game.getCapability(AbbeyCapability.class); - bazaarCap = game.getCapability(BazaarCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(AbbeyCapability.class); - } - - @Override - public void enter() { - if (bazaarCap == null || bazaarCap.getBazaarSupply() == null) { - if (abbeyCap.hasUnusedAbbey(getActivePlayer()) && ! getBoard().getHoles().isEmpty()) { - notifyUI(new AbbeyPlacementAction(getBoard().getHoles()), true); - return; - } - } - next(); - } - - @Override - public void pass() { - next(); - } - - @Override - public void placeTile(Rotation rotation, Position position) { - abbeyCap.useAbbey(getActivePlayer()); - - Tile nextTile = game.getTilePack().drawTile("inactive", Tile.ABBEY_TILE_ID); - game.setCurrentTile(nextTile); - nextTile.setRotation(rotation); - getBoard().add(nextTile, position); - getBoard().mergeFeatures(nextTile); - - game.fireGameEvent().tilePlaced(nextTile); - next(ActionPhase.class); - } -} +package com.jcloisterzone.game.phase; + +import com.jcloisterzone.action.AbbeyPlacementAction; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.AbbeyCapability; +import com.jcloisterzone.game.capability.BazaarCapability; + +public class AbbeyPhase extends Phase { + + private AbbeyCapability abbeyCap; + private BazaarCapability bazaarCap; + + public AbbeyPhase(Game game) { + super(game); + abbeyCap = game.getCapability(AbbeyCapability.class); + bazaarCap = game.getCapability(BazaarCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(AbbeyCapability.class); + } + + @Override + public void enter() { + if (bazaarCap == null || bazaarCap.getBazaarSupply() == null) { + if (abbeyCap.hasUnusedAbbey(getActivePlayer()) && ! getBoard().getHoles().isEmpty()) { + notifyUI(new AbbeyPlacementAction(getBoard().getHoles()), true); + return; + } + } + next(); + } + + @Override + public void pass() { + next(); + } + + @Override + public void placeTile(Rotation rotation, Position position) { + abbeyCap.useAbbey(getActivePlayer()); + + Tile nextTile = game.getTilePack().drawTile("inactive", Tile.ABBEY_TILE_ID); + game.setCurrentTile(nextTile); + nextTile.setRotation(rotation); + getBoard().add(nextTile, position); + getBoard().mergeFeatures(nextTile); + + game.fireGameEvent().tilePlaced(nextTile); + next(ActionPhase.class); + } +} diff --git a/src/main/java/com/jcloisterzone/game/phase/ActionPhase.java b/src/main/java/com/jcloisterzone/game/phase/ActionPhase.java index 351bcd36a..0b72332d3 100644 --- a/src/main/java/com/jcloisterzone/game/phase/ActionPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/ActionPhase.java @@ -1,180 +1,180 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.collect.Iterables; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.TakePrisonerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.BridgeCapability; -import com.jcloisterzone.game.capability.FairyCapability; -import com.jcloisterzone.game.capability.FlierCapability; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.game.capability.TunnelCapability; - - -public class ActionPhase extends Phase { - - private final TowerCapability towerCap; - private final FlierCapability flierCap; - - public ActionPhase(Game game) { - super(game); - towerCap = game.getCapability(TowerCapability.class); - flierCap = game.getCapability(FlierCapability.class); - } - - @Override - public void enter() { - List actions = new ArrayList<>(); - - LocationsMap locMap = game.prepareFollowerLocations(); - if (getActivePlayer().hasFollower(SmallFollower.class) && !locMap.isEmpty()) { - actions.add(new MeepleAction(SmallFollower.class, locMap)); - } - game.prepareActions(actions, locMap); - if (isAutoTurnEnd(actions)) { - next(); - } else { - notifyUI(actions, true); - } - } - - @Override - public void notifyRansomPaid() { - enter(); //recompute available actions - } - - private boolean isAutoTurnEnd(List actions) { - if (!actions.isEmpty()) return false; - if (towerCap != null && !towerCap.isRansomPaidThisTurn() && towerCap.hasImprisonedFollower(getActivePlayer())) { - //player can return figure immediately - return false; - } - if (flierCap != null && flierCap.isFlierRollAllowed()) { - return false; - } - return true; - } - - @Override - public void pass() { - if (getDefaultNext() instanceof PhantomPhase) { - //skip PhantomPhase if user pass turn - getDefaultNext().next(); - } else { - next(); - } - } - - private int doPlaceTowerPiece(Position p) { - Tower tower = getBoard().get(p).getTower(); - if (tower == null) { - throw new IllegalArgumentException("No tower on tile."); - } - if (tower.getMeeple() != null) { - throw new IllegalArgumentException("The tower is sealed"); - } - towerCap.decreaseTowerPieces(getActivePlayer()); - return tower.increaseHeight(); - } - - public TakePrisonerAction prepareCapture(Position p, int range) { - //TODO custom rule - opponent only - TakePrisonerAction captureAction = new TakePrisonerAction(PlayerRestriction.any()); - for (Meeple pf : game.getDeployedMeeples()) { - if (!(pf instanceof Follower)) continue; - Position pos = pf.getPosition(); - if (pos.x != p.x && pos.y != p.y) continue; //check if is in same row or column - if (pos.squareDistance(p) > range) continue; - captureAction.getOrCreate(pos).add(pf.getLocation()); - } - return captureAction; - } - - @Override - public void placeTowerPiece(Position p) { - int captureRange = doPlaceTowerPiece(p); - game.fireGameEvent().towerIncreased(p, captureRange); - TakePrisonerAction captureAction = prepareCapture(p, captureRange); - if (captureAction.getLocationsMap().isEmpty()) { - next(); - return; - } - next(TowerCapturePhase.class); - notifyUI(captureAction, false); - } - - @Override - public void moveFairy(Position p) { - if (!Iterables.any(getActivePlayer().getFollowers(), MeeplePredicates.at(p))) { - throw new IllegalArgumentException("The tile has deployed not own follower."); - } - - game.getCapability(FairyCapability.class).setFairyPosition(p); - game.fireGameEvent().fairyMoved(p); - next(); - } - - private boolean isFestivalUndeploy(Meeple m) { - return getTile().hasTrigger(TileTrigger.FESTIVAL) && m.getPlayer() == getActivePlayer(); - } - - private boolean isPrincessUndeploy(Meeple m) { - //TODO proper validation - return m.getFeature() instanceof City; - } - - @Override - public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { - Meeple m = game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); - if (isFestivalUndeploy(m) || isPrincessUndeploy(m)) { - m.undeploy(); - next(); - } else { - throw new IllegalArgumentException(); - } - } - - @Override - public void placeTunnelPiece(Position p, Location loc, boolean isB) { - game.getCapability(TunnelCapability.class).placeTunnelPiece(p, loc, isB); - next(ActionPhase.class); - } - - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); - m.deploy(getBoard().get(p), loc); - next(); - } - - @Override - public void deployBridge(Position pos, Location loc) { - BridgeCapability bridgeCap = game.getCapability(BridgeCapability.class); - bridgeCap.decreaseBridges(getActivePlayer()); - bridgeCap.deployBridge(pos, loc); - next(ActionPhase.class); - } - - @Override - public void setFlierDistance(int distance) { - flierCap.setFlierDistance(distance); - next(FlierActionPhase.class); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; +import java.util.List; + +import com.google.common.collect.Iterables; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.TakePrisonerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.BridgeCapability; +import com.jcloisterzone.game.capability.FairyCapability; +import com.jcloisterzone.game.capability.FlierCapability; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.game.capability.TunnelCapability; + + +public class ActionPhase extends Phase { + + private final TowerCapability towerCap; + private final FlierCapability flierCap; + + public ActionPhase(Game game) { + super(game); + towerCap = game.getCapability(TowerCapability.class); + flierCap = game.getCapability(FlierCapability.class); + } + + @Override + public void enter() { + List actions = new ArrayList<>(); + + LocationsMap locMap = game.prepareFollowerLocations(); + if (getActivePlayer().hasFollower(SmallFollower.class) && !locMap.isEmpty()) { + actions.add(new MeepleAction(SmallFollower.class, locMap)); + } + game.prepareActions(actions, locMap); + if (isAutoTurnEnd(actions)) { + next(); + } else { + notifyUI(actions, true); + } + } + + @Override + public void notifyRansomPaid() { + enter(); //recompute available actions + } + + private boolean isAutoTurnEnd(List actions) { + if (!actions.isEmpty()) return false; + if (towerCap != null && !towerCap.isRansomPaidThisTurn() && towerCap.hasImprisonedFollower(getActivePlayer())) { + //player can return figure immediately + return false; + } + if (flierCap != null && flierCap.isFlierRollAllowed()) { + return false; + } + return true; + } + + @Override + public void pass() { + if (getDefaultNext() instanceof PhantomPhase) { + //skip PhantomPhase if user pass turn + getDefaultNext().next(); + } else { + next(); + } + } + + private int doPlaceTowerPiece(Position p) { + Tower tower = getBoard().get(p).getTower(); + if (tower == null) { + throw new IllegalArgumentException("No tower on tile."); + } + if (tower.getMeeple() != null) { + throw new IllegalArgumentException("The tower is sealed"); + } + towerCap.decreaseTowerPieces(getActivePlayer()); + return tower.increaseHeight(); + } + + public TakePrisonerAction prepareCapture(Position p, int range) { + //TODO custom rule - opponent only + TakePrisonerAction captureAction = new TakePrisonerAction(PlayerRestriction.any()); + for (Meeple pf : game.getDeployedMeeples()) { + if (!(pf instanceof Follower)) continue; + Position pos = pf.getPosition(); + if (pos.x != p.x && pos.y != p.y) continue; //check if is in same row or column + if (pos.squareDistance(p) > range) continue; + captureAction.getOrCreate(pos).add(pf.getLocation()); + } + return captureAction; + } + + @Override + public void placeTowerPiece(Position p) { + int captureRange = doPlaceTowerPiece(p); + game.fireGameEvent().towerIncreased(p, captureRange); + TakePrisonerAction captureAction = prepareCapture(p, captureRange); + if (captureAction.getLocationsMap().isEmpty()) { + next(); + return; + } + next(TowerCapturePhase.class); + notifyUI(captureAction, false); + } + + @Override + public void moveFairy(Position p) { + if (!Iterables.any(getActivePlayer().getFollowers(), MeeplePredicates.at(p))) { + throw new IllegalArgumentException("The tile has deployed not own follower."); + } + + game.getCapability(FairyCapability.class).setFairyPosition(p); + game.fireGameEvent().fairyMoved(p); + next(); + } + + private boolean isFestivalUndeploy(Meeple m) { + return getTile().hasTrigger(TileTrigger.FESTIVAL) && m.getPlayer() == getActivePlayer(); + } + + private boolean isPrincessUndeploy(Meeple m) { + //TODO proper validation + return m.getFeature() instanceof City; + } + + @Override + public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { + Meeple m = game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); + if (isFestivalUndeploy(m) || isPrincessUndeploy(m)) { + m.undeploy(); + next(); + } else { + throw new IllegalArgumentException(); + } + } + + @Override + public void placeTunnelPiece(Position p, Location loc, boolean isB) { + game.getCapability(TunnelCapability.class).placeTunnelPiece(p, loc, isB); + next(ActionPhase.class); + } + + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); + m.deploy(getBoard().get(p), loc); + next(); + } + + @Override + public void deployBridge(Position pos, Location loc) { + BridgeCapability bridgeCap = game.getCapability(BridgeCapability.class); + bridgeCap.decreaseBridges(getActivePlayer()); + bridgeCap.deployBridge(pos, loc); + next(ActionPhase.class); + } + + @Override + public void setFlierDistance(int distance) { + flierCap.setFlierDistance(distance); + next(FlierActionPhase.class); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/BazaarPhase.java b/src/main/java/com/jcloisterzone/game/phase/BazaarPhase.java index 055478c5b..d2295d48c 100644 --- a/src/main/java/com/jcloisterzone/game/phase/BazaarPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/BazaarPhase.java @@ -1,190 +1,190 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.game.capability.BazaarItem; -import com.jcloisterzone.rmi.ServerIF; - -public class BazaarPhase extends ServerAwarePhase { - - private final BazaarCapability bazaarCap; - - public BazaarPhase(Game game, ServerIF server) { - super(game, server); - bazaarCap = game.getCapability(BazaarCapability.class); - } - - - @Override - public boolean isActive() { - return game.hasCapability(BazaarCapability.class); - } - - @Override - public Player getActivePlayer() { - Player bidding = bazaarCap.getBazaarBiddingPlayer(); - return bidding == null ? bazaarCap.getBazaarTileSelectingPlayer() : bidding; - } - - @Override - public void enter() { - if (!isBazaarTriggered()) { - next(); - return; - } - Player p = game.getNextPlayer(); - bazaarCap.setBazaarTileSelectingPlayer(p); - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - if (isLocalPlayer(p)) { - //call only from one client (from the active one) - getServer().selectTiles(getTilePack().size(), game.getAllPlayers().length); - } - } - - @Override - public void loadGame(Snapshot snapshot) { - setEntered(true); //avoid call enter on load phase to this phase switch - Player selecting = bazaarCap.getBazaarTileSelectingPlayer(); - if (selecting != null) { - Player bidding = bazaarCap.getBazaarBiddingPlayer(); - int supplyIdx = bazaarCap.getBazaarSupply().indexOf(bazaarCap.getCurrentBazaarAuction()); - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - - if (bidding == null) { - game.getUserInterface().selectBazaarTile(); - } else if (selecting == bidding) { - game.getUserInterface().selectBuyOrSellBazaarOffer(supplyIdx); - } else { - game.getUserInterface().makeBazaarBid(supplyIdx); - } - } - } - - private boolean isBazaarTriggered() { - if (!getTile().hasTrigger(TileTrigger.BAZAAR)) return false; - if (getTilePack().size() < game.getAllPlayers().length) return false; //there isn't one tile for each player available - if (bazaarCap.getBazaarSupply() != null) return false; - return true; - } - - @Override - public void drawTiles(int[] tileIndexes) { - ArrayList supply = new ArrayList(tileIndexes.length); - for (int tileIndex : tileIndexes) { - supply.add(new BazaarItem(getTilePack().drawTile(tileIndex))); - } - bazaarCap.setBazaarSupply(supply); - game.getUserInterface().selectBazaarTile(); - } - - private boolean canPlayerBid(Player p) { - for (BazaarItem bi : bazaarCap.getBazaarSupply()) { - if (bi.getOwner() == p) return false; - } - return true; - } - - @Override - public void bazaarBid(Integer supplyIndex, Integer price) { - BazaarItem bi = bazaarCap.getCurrentBazaarAuction(); - boolean isTileSelection = bi == null; - if (bi == null) { - bi = bazaarCap.getBazaarSupply().get(supplyIndex); - bazaarCap.setCurrentBazaarAuction(bi); - - if (game.hasRule(CustomRule.BAZAAR_NO_AUCTION)) { - bi.setOwner(getActivePlayer()); - nextSelectingPlayer(); - return; - } - } - bi.setCurrentPrice(price); - bi.setCurrentBidder(getActivePlayer()); - - if (isTileSelection) { - game.fireGameEvent().bazaarTileSelected(supplyIndex, bi); - } - nextBidder(); - } - - private void nextBidder() { - Player nextBidder = getActivePlayer(); - int supplyIdx = bazaarCap.getBazaarSupply().indexOf(bazaarCap.getCurrentBazaarAuction()); - do { - nextBidder = game.getNextPlayer(nextBidder); - if (nextBidder == bazaarCap.getBazaarTileSelectingPlayer()) { - //all players makes bid - BazaarItem bi = bazaarCap.getCurrentBazaarAuction(); - if (bazaarCap.getBazaarTileSelectingPlayer() == bi.getCurrentBidder()) { - bazaarBuyOrSell(true); - } else { - bazaarCap.setBazaarBiddingPlayer(bazaarCap.getBazaarTileSelectingPlayer()); //need for correct save&load - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - game.getUserInterface().selectBuyOrSellBazaarOffer(supplyIdx); - } - return; - } - } while (!canPlayerBid(nextBidder)); - - bazaarCap.setBazaarBiddingPlayer(nextBidder); - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - game.getUserInterface().makeBazaarBid(supplyIdx); - } - - private void nextSelectingPlayer() { - bazaarCap.setCurrentBazaarAuction(null); - bazaarCap.setBazaarBiddingPlayer(null); - Player currentSelectingPlayer = bazaarCap.getBazaarTileSelectingPlayer(); - Player player = currentSelectingPlayer; - do { - player = game.getNextPlayer(player); - if (!bazaarCap.hasTileAuctioned(player)) { - bazaarCap.setBazaarTileSelectingPlayer(player); - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - game.getUserInterface().selectBazaarTile(); - return; - } - } while (player != currentSelectingPlayer); - //all tiles has been auctioned - bazaarCap.setBazaarTileSelectingPlayer(null); - game.fireGameEvent().bazaarAuctionsEnded(); - next(); - } - - @Override - public void pass() { - if (bazaarCap.getBazaarBiddingPlayer() == bazaarCap.getBazaarTileSelectingPlayer()) { - logger.error("Tile selecting player is not allowed to pass"); - return; - } - nextBidder(); - } - - @Override - public void bazaarBuyOrSell(boolean buy) { - BazaarItem bi = bazaarCap.getCurrentBazaarAuction(); - int points = bi.getCurrentPrice(); - Player pSelecting = bazaarCap.getBazaarTileSelectingPlayer(); - Player pBidding = bi.getCurrentBidder(); - - assert pSelecting != pBidding || buy; //if same, buy is flag expected - if (!buy) points *= -1; - pSelecting.addPoints(-points, PointCategory.BAZAAR_AUCTION); - if (pSelecting != pBidding) { - pBidding.addPoints(points, PointCategory.BAZAAR_AUCTION); - } - - bi.setOwner(buy ? pSelecting : pBidding); - bi.setCurrentBidder(null); - nextSelectingPlayer(); - } - - -} +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.game.capability.BazaarItem; +import com.jcloisterzone.rmi.ServerIF; + +public class BazaarPhase extends ServerAwarePhase { + + private final BazaarCapability bazaarCap; + + public BazaarPhase(Game game, ServerIF server) { + super(game, server); + bazaarCap = game.getCapability(BazaarCapability.class); + } + + + @Override + public boolean isActive() { + return game.hasCapability(BazaarCapability.class); + } + + @Override + public Player getActivePlayer() { + Player bidding = bazaarCap.getBazaarBiddingPlayer(); + return bidding == null ? bazaarCap.getBazaarTileSelectingPlayer() : bidding; + } + + @Override + public void enter() { + if (!isBazaarTriggered()) { + next(); + return; + } + Player p = game.getNextPlayer(); + bazaarCap.setBazaarTileSelectingPlayer(p); + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + if (isLocalPlayer(p)) { + //call only from one client (from the active one) + getServer().selectTiles(getTilePack().size(), game.getAllPlayers().length); + } + } + + @Override + public void loadGame(Snapshot snapshot) { + setEntered(true); //avoid call enter on load phase to this phase switch + Player selecting = bazaarCap.getBazaarTileSelectingPlayer(); + if (selecting != null) { + Player bidding = bazaarCap.getBazaarBiddingPlayer(); + int supplyIdx = bazaarCap.getBazaarSupply().indexOf(bazaarCap.getCurrentBazaarAuction()); + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + + if (bidding == null) { + game.getUserInterface().selectBazaarTile(); + } else if (selecting == bidding) { + game.getUserInterface().selectBuyOrSellBazaarOffer(supplyIdx); + } else { + game.getUserInterface().makeBazaarBid(supplyIdx); + } + } + } + + private boolean isBazaarTriggered() { + if (!getTile().hasTrigger(TileTrigger.BAZAAR)) return false; + if (getTilePack().size() < game.getAllPlayers().length) return false; //there isn't one tile for each player available + if (bazaarCap.getBazaarSupply() != null) return false; + return true; + } + + @Override + public void drawTiles(int[] tileIndexes) { + ArrayList supply = new ArrayList(tileIndexes.length); + for (int tileIndex : tileIndexes) { + supply.add(new BazaarItem(getTilePack().drawTile(tileIndex))); + } + bazaarCap.setBazaarSupply(supply); + game.getUserInterface().selectBazaarTile(); + } + + private boolean canPlayerBid(Player p) { + for (BazaarItem bi : bazaarCap.getBazaarSupply()) { + if (bi.getOwner() == p) return false; + } + return true; + } + + @Override + public void bazaarBid(Integer supplyIndex, Integer price) { + BazaarItem bi = bazaarCap.getCurrentBazaarAuction(); + boolean isTileSelection = bi == null; + if (bi == null) { + bi = bazaarCap.getBazaarSupply().get(supplyIndex); + bazaarCap.setCurrentBazaarAuction(bi); + + if (game.hasRule(CustomRule.BAZAAR_NO_AUCTION)) { + bi.setOwner(getActivePlayer()); + nextSelectingPlayer(); + return; + } + } + bi.setCurrentPrice(price); + bi.setCurrentBidder(getActivePlayer()); + + if (isTileSelection) { + game.fireGameEvent().bazaarTileSelected(supplyIndex, bi); + } + nextBidder(); + } + + private void nextBidder() { + Player nextBidder = getActivePlayer(); + int supplyIdx = bazaarCap.getBazaarSupply().indexOf(bazaarCap.getCurrentBazaarAuction()); + do { + nextBidder = game.getNextPlayer(nextBidder); + if (nextBidder == bazaarCap.getBazaarTileSelectingPlayer()) { + //all players makes bid + BazaarItem bi = bazaarCap.getCurrentBazaarAuction(); + if (bazaarCap.getBazaarTileSelectingPlayer() == bi.getCurrentBidder()) { + bazaarBuyOrSell(true); + } else { + bazaarCap.setBazaarBiddingPlayer(bazaarCap.getBazaarTileSelectingPlayer()); //need for correct save&load + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + game.getUserInterface().selectBuyOrSellBazaarOffer(supplyIdx); + } + return; + } + } while (!canPlayerBid(nextBidder)); + + bazaarCap.setBazaarBiddingPlayer(nextBidder); + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + game.getUserInterface().makeBazaarBid(supplyIdx); + } + + private void nextSelectingPlayer() { + bazaarCap.setCurrentBazaarAuction(null); + bazaarCap.setBazaarBiddingPlayer(null); + Player currentSelectingPlayer = bazaarCap.getBazaarTileSelectingPlayer(); + Player player = currentSelectingPlayer; + do { + player = game.getNextPlayer(player); + if (!bazaarCap.hasTileAuctioned(player)) { + bazaarCap.setBazaarTileSelectingPlayer(player); + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + game.getUserInterface().selectBazaarTile(); + return; + } + } while (player != currentSelectingPlayer); + //all tiles has been auctioned + bazaarCap.setBazaarTileSelectingPlayer(null); + game.fireGameEvent().bazaarAuctionsEnded(); + next(); + } + + @Override + public void pass() { + if (bazaarCap.getBazaarBiddingPlayer() == bazaarCap.getBazaarTileSelectingPlayer()) { + logger.error("Tile selecting player is not allowed to pass"); + return; + } + nextBidder(); + } + + @Override + public void bazaarBuyOrSell(boolean buy) { + BazaarItem bi = bazaarCap.getCurrentBazaarAuction(); + int points = bi.getCurrentPrice(); + Player pSelecting = bazaarCap.getBazaarTileSelectingPlayer(); + Player pBidding = bi.getCurrentBidder(); + + assert pSelecting != pBidding || buy; //if same, buy is flag expected + if (!buy) points *= -1; + pSelecting.addPoints(-points, PointCategory.BAZAAR_AUCTION); + if (pSelecting != pBidding) { + pBidding.addPoints(points, PointCategory.BAZAAR_AUCTION); + } + + bi.setOwner(buy ? pSelecting : pBidding); + bi.setCurrentBidder(null); + nextSelectingPlayer(); + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/CastlePhase.java b/src/main/java/com/jcloisterzone/game/phase/CastlePhase.java index fd9088ea2..a1c4c8237 100644 --- a/src/main/java/com/jcloisterzone/game/phase/CastlePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/CastlePhase.java @@ -1,125 +1,125 @@ -package com.jcloisterzone.game.phase; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.CastleAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.CastleCapability; - -public class CastlePhase extends Phase { - - private final CastleCapability castleCap; - - public CastlePhase(Game game) { - super(game); - castleCap = game.getCapability(CastleCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(CastleCapability.class); - } - - @Override - public Player getActivePlayer() { - Player p = castleCap.getCastlePlayer(); - return p == null ? game.getTurnPlayer() : p; - } - - @Override - public void enter() { - Tile tile = getTile(); - Map> currentTileCastleBases = null; - for (Feature f : tile.getFeatures()) { - if (!(f instanceof City)) continue; - Player owner = f.walk(new FindCastleBaseVisitor()); - if (owner == null || castleCap.getPlayerCastles(owner) == 0) continue; - if (currentTileCastleBases == null) currentTileCastleBases = new HashMap<>(); - Set locs = currentTileCastleBases.get(owner); - if (locs == null) { - locs = new HashSet<>(); - currentTileCastleBases.put(owner, locs); - } - locs.add(f.getLocation()); - } - if (currentTileCastleBases == null) { - next(); - return; - } - castleCap.setCurrentTileCastleBases(currentTileCastleBases); - prepareCastleAction(); - } - - private void prepareCastleAction() { - Map> currentTileCastleBases = castleCap.getCurrentTileCastleBases(); - if (currentTileCastleBases.isEmpty()) { - castleCap.setCastlePlayer(null); - castleCap.setCurrentTileCastleBases(null); - next(); - return; - } - int pi = game.getTurnPlayer().getIndex(); - while(! currentTileCastleBases.containsKey(game.getAllPlayers()[pi])) { - pi++; - if (pi == game.getAllPlayers().length) pi = 0; - } - Player player = game.getAllPlayers()[pi]; - castleCap.setCastlePlayer(player); - Set locs = currentTileCastleBases.remove(player); - notifyUI(new CastleAction(getTile().getPosition(), locs), true); - } - - @Override - public void pass() { - prepareCastleAction(); - } - - @Override - public void deployCastle(Position pos, Location loc) { - Player owner = castleCap.getCastlePlayer(); - castleCap.decreaseCastles(owner); - castleCap.convertCityToCastle(pos, loc); - prepareCastleAction(); //it is possible to deploy castle by another player - } - - class FindCastleBaseVisitor implements FeatureVisitor { - - int size = 0; - boolean castleBase = true; - Player owner; - - @Override - public boolean visit(Feature feature) { - City c = (City) feature; - if (!c.isCastleBase()) { - castleBase = false; - return false; - } - //if more then one follower is on caste, all has same owner - //possible scenario - deploy on city - add by crop circle another follower - deploy castle - if (!c.getMeeples().isEmpty()) { - owner = c.getMeeples().get(0).getPlayer(); - } - size++; - if (size > 2) return false; - return true; - } - - public Player getResult() { - if (castleBase && size == 2) return owner; - return null; - } - - } - -} +package com.jcloisterzone.game.phase; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.CastleAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.CastleCapability; + +public class CastlePhase extends Phase { + + private final CastleCapability castleCap; + + public CastlePhase(Game game) { + super(game); + castleCap = game.getCapability(CastleCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(CastleCapability.class); + } + + @Override + public Player getActivePlayer() { + Player p = castleCap.getCastlePlayer(); + return p == null ? game.getTurnPlayer() : p; + } + + @Override + public void enter() { + Tile tile = getTile(); + Map> currentTileCastleBases = null; + for (Feature f : tile.getFeatures()) { + if (!(f instanceof City)) continue; + Player owner = f.walk(new FindCastleBaseVisitor()); + if (owner == null || castleCap.getPlayerCastles(owner) == 0) continue; + if (currentTileCastleBases == null) currentTileCastleBases = new HashMap<>(); + Set locs = currentTileCastleBases.get(owner); + if (locs == null) { + locs = new HashSet<>(); + currentTileCastleBases.put(owner, locs); + } + locs.add(f.getLocation()); + } + if (currentTileCastleBases == null) { + next(); + return; + } + castleCap.setCurrentTileCastleBases(currentTileCastleBases); + prepareCastleAction(); + } + + private void prepareCastleAction() { + Map> currentTileCastleBases = castleCap.getCurrentTileCastleBases(); + if (currentTileCastleBases.isEmpty()) { + castleCap.setCastlePlayer(null); + castleCap.setCurrentTileCastleBases(null); + next(); + return; + } + int pi = game.getTurnPlayer().getIndex(); + while(! currentTileCastleBases.containsKey(game.getAllPlayers()[pi])) { + pi++; + if (pi == game.getAllPlayers().length) pi = 0; + } + Player player = game.getAllPlayers()[pi]; + castleCap.setCastlePlayer(player); + Set locs = currentTileCastleBases.remove(player); + notifyUI(new CastleAction(getTile().getPosition(), locs), true); + } + + @Override + public void pass() { + prepareCastleAction(); + } + + @Override + public void deployCastle(Position pos, Location loc) { + Player owner = castleCap.getCastlePlayer(); + castleCap.decreaseCastles(owner); + castleCap.convertCityToCastle(pos, loc); + prepareCastleAction(); //it is possible to deploy castle by another player + } + + class FindCastleBaseVisitor implements FeatureVisitor { + + int size = 0; + boolean castleBase = true; + Player owner; + + @Override + public boolean visit(Feature feature) { + City c = (City) feature; + if (!c.isCastleBase()) { + castleBase = false; + return false; + } + //if more then one follower is on caste, all has same owner + //possible scenario - deploy on city - add by crop circle another follower - deploy castle + if (!c.getMeeples().isEmpty()) { + owner = c.getMeeples().get(0).getPlayer(); + } + size++; + if (size > 2) return false; + return true; + } + + public Player getResult() { + if (castleBase && size == 2) return owner; + return null; + } + + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/CleanUpPhase.java b/src/main/java/com/jcloisterzone/game/phase/CleanUpPhase.java index 9ebbb47f9..e1c3a169d 100644 --- a/src/main/java/com/jcloisterzone/game/phase/CleanUpPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/CleanUpPhase.java @@ -1,29 +1,29 @@ -package com.jcloisterzone.game.phase; - -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.AbbeyCapability; -import com.jcloisterzone.game.capability.BuilderCapability; - -public class CleanUpPhase extends Phase { - - private final BuilderCapability builderCap; - - public CleanUpPhase(Game game) { - super(game); - builderCap = game.getCapability(BuilderCapability.class); - } - - @Override - public void enter() { - boolean builderTakeAnotherTurn = builderCap != null && builderCap.hasPlayerAnotherTurn(); - game.turnCleanUp(); - game.setCurrentTile(null); - if (builderTakeAnotherTurn) { - next(game.hasCapability(AbbeyCapability.class) ? AbbeyPhase.class : DrawPhase.class); - } else { - game.setTurnPlayer(game.getNextPlayer()); - next(); - } - } - -} +package com.jcloisterzone.game.phase; + +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.AbbeyCapability; +import com.jcloisterzone.game.capability.BuilderCapability; + +public class CleanUpPhase extends Phase { + + private final BuilderCapability builderCap; + + public CleanUpPhase(Game game) { + super(game); + builderCap = game.getCapability(BuilderCapability.class); + } + + @Override + public void enter() { + boolean builderTakeAnotherTurn = builderCap != null && builderCap.hasPlayerAnotherTurn(); + game.turnCleanUp(); + game.setCurrentTile(null); + if (builderTakeAnotherTurn) { + next(game.hasCapability(AbbeyCapability.class) ? AbbeyPhase.class : DrawPhase.class); + } else { + game.setTurnPlayer(game.getNextPlayer()); + next(); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/CornCirclePhase.java b/src/main/java/com/jcloisterzone/game/phase/CornCirclePhase.java index 0b3b69bbe..f421e03fa 100644 --- a/src/main/java/com/jcloisterzone/game/phase/CornCirclePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/CornCirclePhase.java @@ -1,204 +1,204 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.SelectFeatureAction; -import com.jcloisterzone.action.UndeployAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.BigFollower; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Mayor; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Phantom; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.Wagon; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.CornCircleCapability; -import com.jcloisterzone.game.capability.CornCircleCapability.CornCicleOption; - -public class CornCirclePhase extends Phase { - - private final CornCircleCapability cornCircleCap; - - public CornCirclePhase(Game game) { - super(game); - cornCircleCap = game.getCapability(CornCircleCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(CornCircleCapability.class); - } - - @Override - public Player getActivePlayer() { - Player player = cornCircleCap.getCornCirclePlayer(); - if (player == null) return super.getActivePlayer(); - return player; - } - - @Override - public void enter() { - if (getTile().getCornCircle() == null) { - next(); - return; - } - game.getUserInterface().selectCornCircleOption(); - } - - private void nextCornPlayer() { - Player active = getActivePlayer(); - if (active == game.getTurnPlayer()) { - cornCircleCap.setCornCirclePlayer(null); - cornCircleCap.setCornCircleOption(null); - next(); - } else { - Player cornPlayer = game.getNextPlayer(active); - cornCircleCap.setCornCirclePlayer(cornPlayer); - prepareCornAction(); - } - } - - @Override - public void cornCiclesRemoveOrDeploy(boolean remove) { - if (remove) { - cornCircleCap.setCornCircleOption(CornCicleOption.REMOVAL); - } else { - cornCircleCap.setCornCircleOption(CornCicleOption.DEPLOYMENT); - } - Player cornPlayer = game.getNextPlayer(getActivePlayer()); - cornCircleCap.setCornCirclePlayer(cornPlayer); - prepareCornAction(); - } - - private void prepareCornAction() { - List actions; - Class cornType = getTile().getCornCircle(); - if (cornCircleCap.getCornCircleOption() == CornCicleOption.REMOVAL) { - actions = prepareRemovalAction(cornType); - } else { - actions = prepareDeploymentAction(cornType); - } - if (actions.isEmpty()) { - nextCornPlayer(); - } else { - notifyUI(actions, cornCircleCap.getCornCircleOption() == CornCicleOption.DEPLOYMENT); - } - } - - private List prepareDeploymentAction(Class cornType) { - LocationsMap sites = new LocationsMap(); - for (Meeple m : game.getDeployedMeeples()) { - if (!(m instanceof Follower)) continue; - if (m.getPlayer() != getActivePlayer()) continue; - if (!cornType.isInstance(m.getFeature())) continue; - sites.getOrCreate(m.getPosition()).add(m.getLocation()); - } - if (sites.isEmpty()) return Collections.emptyList(); - - List actions = new ArrayList<>(); - //TODO nice to do this in generic way independtly on particular followers enumeration - if (getActivePlayer().hasFollower(SmallFollower.class)) { - actions.add(new MeepleAction(SmallFollower.class, sites)); - } - if (getActivePlayer().hasFollower(BigFollower.class)) { - actions.add(new MeepleAction(BigFollower.class, sites)); - } - if (getActivePlayer().hasFollower(Phantom.class)) { - actions.add(new MeepleAction(Phantom.class, sites)); - } - if (cornType.equals(City.class) && getActivePlayer().hasFollower(Mayor.class)) { - actions.add(new MeepleAction(Mayor.class, sites)); - } - if (!cornType.equals(Farm.class) && getActivePlayer().hasFollower(Wagon.class)) { - actions.add(new MeepleAction(Wagon.class, sites)); - } - return actions; - } - - private List prepareRemovalAction(Class cornType) { - SelectFeatureAction action = null; - for (Meeple m : game.getDeployedMeeples()) { - if (!(m instanceof Follower)) continue; - if (m.getPlayer() != getActivePlayer()) continue; - if (!cornType.isInstance(m.getFeature())) continue; - if (action == null) { - action = new UndeployAction("undeploy", PlayerRestriction.only(getActivePlayer())); - } - action.getOrCreate(m.getPosition()).add(m.getLocation()); - } - if (action == null) return Collections.emptyList(); - return Collections.singletonList(action); - } - - @Override - public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { - if (cornCircleCap.getCornCircleOption() != CornCicleOption.REMOVAL) { - logger.error("Removal not selected as corn options."); - return; - } - Meeple m = game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); - Class cornType = getTile().getCornCircle(); - if (!cornType.isInstance(m.getFeature())) { - logger.error("Improper feature type"); - return; - } - m.undeploy(); - nextCornPlayer(); - } - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - if (cornCircleCap.getCornCircleOption() != CornCicleOption.DEPLOYMENT) { - logger.error("Deployment not selected as corn options."); - return; - } - List meeples = getBoard().get(p).getFeature(loc).getMeeples(); - if (meeples.isEmpty()) { - logger.error("Feature must be occupies"); - return; - } - if (meeples.get(0).getPlayer() != getActivePlayer()) { - logger.error("Feature must be occupies with own follower"); - return; - } - - Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); - Tile tile = getBoard().get(p); - m.deployUnchecked(tile, loc, tile.getFeature(loc)); - game.fireGameEvent().deployed(m); - nextCornPlayer(); - } - - @Override - public void pass() { - if (cornCircleCap.getCornCircleOption() == CornCicleOption.REMOVAL) { - logger.error("Removal cannot be passed"); - return; - } - nextCornPlayer(); - } - - @Override - public void loadGame(Snapshot snapshot) { - setEntered(true); //avoid call enter on load phase to this phase switch - if (cornCircleCap.getCornCircleOption() == null) { - game.getUserInterface().selectCornCircleOption(); - } else { - prepareCornAction(); - } - } -} +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.SelectFeatureAction; +import com.jcloisterzone.action.UndeployAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.BigFollower; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Mayor; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Phantom; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.Wagon; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.CornCircleCapability; +import com.jcloisterzone.game.capability.CornCircleCapability.CornCicleOption; + +public class CornCirclePhase extends Phase { + + private final CornCircleCapability cornCircleCap; + + public CornCirclePhase(Game game) { + super(game); + cornCircleCap = game.getCapability(CornCircleCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(CornCircleCapability.class); + } + + @Override + public Player getActivePlayer() { + Player player = cornCircleCap.getCornCirclePlayer(); + if (player == null) return super.getActivePlayer(); + return player; + } + + @Override + public void enter() { + if (getTile().getCornCircle() == null) { + next(); + return; + } + game.getUserInterface().selectCornCircleOption(); + } + + private void nextCornPlayer() { + Player active = getActivePlayer(); + if (active == game.getTurnPlayer()) { + cornCircleCap.setCornCirclePlayer(null); + cornCircleCap.setCornCircleOption(null); + next(); + } else { + Player cornPlayer = game.getNextPlayer(active); + cornCircleCap.setCornCirclePlayer(cornPlayer); + prepareCornAction(); + } + } + + @Override + public void cornCiclesRemoveOrDeploy(boolean remove) { + if (remove) { + cornCircleCap.setCornCircleOption(CornCicleOption.REMOVAL); + } else { + cornCircleCap.setCornCircleOption(CornCicleOption.DEPLOYMENT); + } + Player cornPlayer = game.getNextPlayer(getActivePlayer()); + cornCircleCap.setCornCirclePlayer(cornPlayer); + prepareCornAction(); + } + + private void prepareCornAction() { + List actions; + Class cornType = getTile().getCornCircle(); + if (cornCircleCap.getCornCircleOption() == CornCicleOption.REMOVAL) { + actions = prepareRemovalAction(cornType); + } else { + actions = prepareDeploymentAction(cornType); + } + if (actions.isEmpty()) { + nextCornPlayer(); + } else { + notifyUI(actions, cornCircleCap.getCornCircleOption() == CornCicleOption.DEPLOYMENT); + } + } + + private List prepareDeploymentAction(Class cornType) { + LocationsMap sites = new LocationsMap(); + for (Meeple m : game.getDeployedMeeples()) { + if (!(m instanceof Follower)) continue; + if (m.getPlayer() != getActivePlayer()) continue; + if (!cornType.isInstance(m.getFeature())) continue; + sites.getOrCreate(m.getPosition()).add(m.getLocation()); + } + if (sites.isEmpty()) return Collections.emptyList(); + + List actions = new ArrayList<>(); + //TODO nice to do this in generic way independtly on particular followers enumeration + if (getActivePlayer().hasFollower(SmallFollower.class)) { + actions.add(new MeepleAction(SmallFollower.class, sites)); + } + if (getActivePlayer().hasFollower(BigFollower.class)) { + actions.add(new MeepleAction(BigFollower.class, sites)); + } + if (getActivePlayer().hasFollower(Phantom.class)) { + actions.add(new MeepleAction(Phantom.class, sites)); + } + if (cornType.equals(City.class) && getActivePlayer().hasFollower(Mayor.class)) { + actions.add(new MeepleAction(Mayor.class, sites)); + } + if (!cornType.equals(Farm.class) && getActivePlayer().hasFollower(Wagon.class)) { + actions.add(new MeepleAction(Wagon.class, sites)); + } + return actions; + } + + private List prepareRemovalAction(Class cornType) { + SelectFeatureAction action = null; + for (Meeple m : game.getDeployedMeeples()) { + if (!(m instanceof Follower)) continue; + if (m.getPlayer() != getActivePlayer()) continue; + if (!cornType.isInstance(m.getFeature())) continue; + if (action == null) { + action = new UndeployAction("undeploy", PlayerRestriction.only(getActivePlayer())); + } + action.getOrCreate(m.getPosition()).add(m.getLocation()); + } + if (action == null) return Collections.emptyList(); + return Collections.singletonList(action); + } + + @Override + public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { + if (cornCircleCap.getCornCircleOption() != CornCicleOption.REMOVAL) { + logger.error("Removal not selected as corn options."); + return; + } + Meeple m = game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); + Class cornType = getTile().getCornCircle(); + if (!cornType.isInstance(m.getFeature())) { + logger.error("Improper feature type"); + return; + } + m.undeploy(); + nextCornPlayer(); + } + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + if (cornCircleCap.getCornCircleOption() != CornCicleOption.DEPLOYMENT) { + logger.error("Deployment not selected as corn options."); + return; + } + List meeples = getBoard().get(p).getFeature(loc).getMeeples(); + if (meeples.isEmpty()) { + logger.error("Feature must be occupies"); + return; + } + if (meeples.get(0).getPlayer() != getActivePlayer()) { + logger.error("Feature must be occupies with own follower"); + return; + } + + Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); + Tile tile = getBoard().get(p); + m.deployUnchecked(tile, loc, tile.getFeature(loc)); + game.fireGameEvent().deployed(m); + nextCornPlayer(); + } + + @Override + public void pass() { + if (cornCircleCap.getCornCircleOption() == CornCicleOption.REMOVAL) { + logger.error("Removal cannot be passed"); + return; + } + nextCornPlayer(); + } + + @Override + public void loadGame(Snapshot snapshot) { + setEntered(true); //avoid call enter on load phase to this phase switch + if (cornCircleCap.getCornCircleOption() == null) { + game.getUserInterface().selectCornCircleOption(); + } else { + prepareCornAction(); + } + } +} diff --git a/src/main/java/com/jcloisterzone/game/phase/CreateGamePhase.java b/src/main/java/com/jcloisterzone/game/phase/CreateGamePhase.java index ec516d36e..ea27ed334 100644 --- a/src/main/java/com/jcloisterzone/game/phase/CreateGamePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/CreateGamePhase.java @@ -1,244 +1,244 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.google.common.collect.ClassToInstanceMap; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.ai.AiPlayer; -import com.jcloisterzone.ai.AiUserInterfaceAdapter; -import com.jcloisterzone.board.DefaultTilePack; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePackFactory; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.rmi.ServerIF; - - -public class CreateGamePhase extends ServerAwarePhase { - - private final class PlayerSlotComparator implements Comparator { - @Override - public int compare(PlayerSlot o1, PlayerSlot o2) { - if (o1.getSerial() == null) { - return o2.getSerial() == null ? 0 : 1; - } - if (o2.getSerial() == null) return -1; - if (o1.getSerial() < o2.getSerial()) return -1; - if (o1.getSerial() > o2.getSerial()) return 1; - return 0; - } - } - - protected PlayerSlot[] slots; - - public CreateGamePhase(Game game, ServerIF server) { - super(game, server); - } - - public void setSlots(PlayerSlot[] slots) { - this.slots = slots; - } - - public PlayerSlot[] getPlayerSlots() { - return slots; - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - if (enabled) { - game.getCustomRules().add(rule); - } else { - game.getCustomRules().remove(rule); - } - game.fireGameEvent().updateCustomRule(rule, enabled); - } - - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - if (enabled) { - game.getExpansions().add(expansion); - } else { - game.getExpansions().remove(expansion); - } - game.fireGameEvent().updateExpansion(expansion, enabled); - } - - @Override - public void updateSlot(PlayerSlot slot) { - slots[slot.getNumber()] = slot; - game.fireGameEvent().updateSlot(slot); - } - - @Override - public void updateSupportedExpansions(EnumSet expansions) { - game.fireGameEvent().updateSupportedExpansions(expansions); - } - - - private Phase addPhase(Phase next, Phase phase) { - if (!phase.isActive()) return next; - - ClassToInstanceMap phases = game.getPhases(); - phases.put(phase.getClass(), phase); - if (next != null) { - phase.setDefaultNext(next); - } - return phase; - } - - protected void preparePhases() { - Phase next = null; - //if there isn't assignment - phase is out of standard flow - addPhase(next, new GameOverPhase(game)); - next = addPhase(next, new CleanUpPhase(game)); - next = addPhase(next, new BazaarPhase(game, getServer())); - next = addPhase(next, new CornCirclePhase(game)); - next = addPhase(next, new EscapePhase(game)); - next = addPhase(next, new WagonPhase(game)); - next = addPhase(next, new ScorePhase(game)); - next = addPhase(next, new CastlePhase(game)); - addPhase(next, new DragonMovePhase(game)); - next = addPhase(next, new DragonPhase(game)); - next = addPhase(next, new PhantomPhase(game)); - addPhase(next, new TowerCapturePhase(game)); - addPhase(next, new FlierActionPhase(game)); - next = addPhase(next, new ActionPhase(game)); - next = addPhase(next, new PlaguePhase(game)); - next = addPhase(next, new TilePhase(game)); - next = addPhase(next, new DrawPhase(game, getServer())); - next = addPhase(next, new AbbeyPhase(game)); - next = addPhase(next, new FairyPhase(game)); - setDefaultNext(next); //set next phase for this (CreateGamePhase) instance - game.getPhases().get(CleanUpPhase.class).setDefaultNext(next); //after last phase, the first is default - } - - private void createPlayers() { - List players = new ArrayList<>(); - Arrays.sort(slots, new PlayerSlotComparator()); - for (int i = 0; i < slots.length; i++) { - PlayerSlot slot = slots[i]; - if (slot.isOccupied()) { - Player player = new Player(slot.getNick(), i, slot); - players.add(player); - } - } - if (players.isEmpty()) { - throw new IllegalStateException("No players in game"); - } - game.setPlayers(players, 0); - } - - protected Snapshot getSnapshot() { - return null; - } - - protected void initializePlayersMeeples() { - for (Player player : game.getAllPlayers()) { - for (int i = 0; i < SmallFollower.QUANTITY; i++) { - player.addMeeple(new SmallFollower(game, player)); - } - game.initPlayer(player); - } - } - - protected void preparePlayers() { - createPlayers(); - initializePlayersMeeples(); - } - - protected void prepareTilePack() { - TilePackFactory tilePackFactory = new TilePackFactory(); - tilePackFactory.setGame(game); - tilePackFactory.setConfig(game.getConfig()); - tilePackFactory.setExpansions(game.getExpansions()); - game.setTilePack(tilePackFactory.createTilePack()); - getTilePack().activateGroup("default"); - getTilePack().activateGroup("count"); - getTilePack().activateGroup("wind-rose-initial"); - game.begin(); - } - - protected void preplaceTiles() { - for (Tile preplaced : ((DefaultTilePack)getTilePack()).drawPrePlacedActiveTiles()) { - game.getBoard().add(preplaced, preplaced.getPosition(), true); - game.getBoard().mergeFeatures(preplaced); - game.fireGameEvent().tilePlaced(preplaced); - } - } - - protected void prepareAiPlayers() { - for (PlayerSlot slot : slots) { - if (slot != null && slot.getType() == SlotType.AI && isLocalSlot(slot)) { - try { - AiPlayer ai = (AiPlayer) Class.forName(slot.getAiClassName()).newInstance(); - ai.setGame(game); - ai.setServer(getServer()); - for (Player player : game.getAllPlayers()) { - if (player.getSlot().getNumber() == slot.getNumber()) { - ai.setPlayer(player); - break; - } - } - game.addUserInterface(new AiUserInterfaceAdapter(ai)); - logger.info("AI player created - " + slot.getAiClassName()); - } catch (Exception e) { - logger.error("Unable to create AI player", e); - } - } - } - } - - protected void prepareCapabilities() { - for (Expansion exp : game.getExpansions()) { - game.getCapabilityClasses().addAll(Arrays.asList(exp.getCapabilities())); - } - - String offVal = game.getConfig().get("debug", "off_capabilities"); - Set> off = new HashSet<>(); - if (offVal != null) { - for (String tok : offVal.split(",")) { - tok = tok.trim(); - try { - String className = "com.jcloisterzone.game.capability."+tok+"Capability"; - @SuppressWarnings("unchecked") - Class clazz = (Class) Class.forName(className); - off.add(clazz); - } catch (Exception e) { - logger.warn("Invalid capability name: " + tok, e); - } - } - } - game.getCapabilityClasses().removeAll(off); - } - - @Override - public void startGame() { - //temporary code should be configured by player as rules - prepareCapabilities(); - - game.start(); - preparePlayers(); - preparePhases(); - prepareTilePack(); - prepareAiPlayers(); - - game.fireGameEvent().started(getSnapshot()); - preplaceTiles(); - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - - next(); - } - +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ClassToInstanceMap; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.ai.AiPlayer; +import com.jcloisterzone.ai.AiUserInterfaceAdapter; +import com.jcloisterzone.board.DefaultTilePack; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePackFactory; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.rmi.ServerIF; + + +public class CreateGamePhase extends ServerAwarePhase { + + private final class PlayerSlotComparator implements Comparator { + @Override + public int compare(PlayerSlot o1, PlayerSlot o2) { + if (o1.getSerial() == null) { + return o2.getSerial() == null ? 0 : 1; + } + if (o2.getSerial() == null) return -1; + if (o1.getSerial() < o2.getSerial()) return -1; + if (o1.getSerial() > o2.getSerial()) return 1; + return 0; + } + } + + protected PlayerSlot[] slots; + + public CreateGamePhase(Game game, ServerIF server) { + super(game, server); + } + + public void setSlots(PlayerSlot[] slots) { + this.slots = slots; + } + + public PlayerSlot[] getPlayerSlots() { + return slots; + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + if (enabled) { + game.getCustomRules().add(rule); + } else { + game.getCustomRules().remove(rule); + } + game.fireGameEvent().updateCustomRule(rule, enabled); + } + + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + if (enabled) { + game.getExpansions().add(expansion); + } else { + game.getExpansions().remove(expansion); + } + game.fireGameEvent().updateExpansion(expansion, enabled); + } + + @Override + public void updateSlot(PlayerSlot slot) { + slots[slot.getNumber()] = slot; + game.fireGameEvent().updateSlot(slot); + } + + @Override + public void updateSupportedExpansions(EnumSet expansions) { + game.fireGameEvent().updateSupportedExpansions(expansions); + } + + + private Phase addPhase(Phase next, Phase phase) { + if (!phase.isActive()) return next; + + ClassToInstanceMap phases = game.getPhases(); + phases.put(phase.getClass(), phase); + if (next != null) { + phase.setDefaultNext(next); + } + return phase; + } + + protected void preparePhases() { + Phase next = null; + //if there isn't assignment - phase is out of standard flow + addPhase(next, new GameOverPhase(game)); + next = addPhase(next, new CleanUpPhase(game)); + next = addPhase(next, new BazaarPhase(game, getServer())); + next = addPhase(next, new CornCirclePhase(game)); + next = addPhase(next, new EscapePhase(game)); + next = addPhase(next, new WagonPhase(game)); + next = addPhase(next, new ScorePhase(game)); + next = addPhase(next, new CastlePhase(game)); + addPhase(next, new DragonMovePhase(game)); + next = addPhase(next, new DragonPhase(game)); + next = addPhase(next, new PhantomPhase(game)); + addPhase(next, new TowerCapturePhase(game)); + addPhase(next, new FlierActionPhase(game)); + next = addPhase(next, new ActionPhase(game)); + next = addPhase(next, new PlaguePhase(game)); + next = addPhase(next, new TilePhase(game)); + next = addPhase(next, new DrawPhase(game, getServer())); + next = addPhase(next, new AbbeyPhase(game)); + next = addPhase(next, new FairyPhase(game)); + setDefaultNext(next); //set next phase for this (CreateGamePhase) instance + game.getPhases().get(CleanUpPhase.class).setDefaultNext(next); //after last phase, the first is default + } + + private void createPlayers() { + List players = new ArrayList<>(); + Arrays.sort(slots, new PlayerSlotComparator()); + for (int i = 0; i < slots.length; i++) { + PlayerSlot slot = slots[i]; + if (slot.isOccupied()) { + Player player = new Player(slot.getNick(), i, slot); + players.add(player); + } + } + if (players.isEmpty()) { + throw new IllegalStateException("No players in game"); + } + game.setPlayers(players, 0); + } + + protected Snapshot getSnapshot() { + return null; + } + + protected void initializePlayersMeeples() { + for (Player player : game.getAllPlayers()) { + for (int i = 0; i < SmallFollower.QUANTITY; i++) { + player.addMeeple(new SmallFollower(game, player)); + } + game.initPlayer(player); + } + } + + protected void preparePlayers() { + createPlayers(); + initializePlayersMeeples(); + } + + protected void prepareTilePack() { + TilePackFactory tilePackFactory = new TilePackFactory(); + tilePackFactory.setGame(game); + tilePackFactory.setConfig(game.getConfig()); + tilePackFactory.setExpansions(game.getExpansions()); + game.setTilePack(tilePackFactory.createTilePack()); + getTilePack().activateGroup("default"); + getTilePack().activateGroup("count"); + getTilePack().activateGroup("wind-rose-initial"); + game.begin(); + } + + protected void preplaceTiles() { + for (Tile preplaced : ((DefaultTilePack)getTilePack()).drawPrePlacedActiveTiles()) { + game.getBoard().add(preplaced, preplaced.getPosition(), true); + game.getBoard().mergeFeatures(preplaced); + game.fireGameEvent().tilePlaced(preplaced); + } + } + + protected void prepareAiPlayers() { + for (PlayerSlot slot : slots) { + if (slot != null && slot.getType() == SlotType.AI && isLocalSlot(slot)) { + try { + AiPlayer ai = (AiPlayer) Class.forName(slot.getAiClassName()).newInstance(); + ai.setGame(game); + ai.setServer(getServer()); + for (Player player : game.getAllPlayers()) { + if (player.getSlot().getNumber() == slot.getNumber()) { + ai.setPlayer(player); + break; + } + } + game.addUserInterface(new AiUserInterfaceAdapter(ai)); + logger.info("AI player created - " + slot.getAiClassName()); + } catch (Exception e) { + logger.error("Unable to create AI player", e); + } + } + } + } + + protected void prepareCapabilities() { + for (Expansion exp : game.getExpansions()) { + game.getCapabilityClasses().addAll(Arrays.asList(exp.getCapabilities())); + } + + String offVal = game.getConfig().get("debug", "off_capabilities"); + Set> off = new HashSet<>(); + if (offVal != null) { + for (String tok : offVal.split(",")) { + tok = tok.trim(); + try { + String className = "com.jcloisterzone.game.capability."+tok+"Capability"; + @SuppressWarnings("unchecked") + Class clazz = (Class) Class.forName(className); + off.add(clazz); + } catch (Exception e) { + logger.warn("Invalid capability name: " + tok, e); + } + } + } + game.getCapabilityClasses().removeAll(off); + } + + @Override + public void startGame() { + //temporary code should be configured by player as rules + prepareCapabilities(); + + game.start(); + preparePlayers(); + preparePhases(); + prepareTilePack(); + prepareAiPlayers(); + + game.fireGameEvent().started(getSnapshot()); + preplaceTiles(); + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + + next(); + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/game/phase/DragonMovePhase.java b/src/main/java/com/jcloisterzone/game/phase/DragonMovePhase.java index 7f3505721..e95e7e279 100644 --- a/src/main/java/com/jcloisterzone/game/phase/DragonMovePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/DragonMovePhase.java @@ -1,64 +1,64 @@ -package com.jcloisterzone.game.phase; - -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.DragonCapability; - - -public class DragonMovePhase extends Phase { - - private final DragonCapability dragonCap; - - public DragonMovePhase(Game game) { - super(game); - dragonCap = game.getCapability(DragonCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(DragonCapability.class); - } - - @Override - public Player getActivePlayer() { - return dragonCap.getDragonPlayer(); - } - - @Override - public void enter() { - selectDragonMove(); - } - - private void selectDragonMove() { - if (dragonCap.getDragonMovesLeft() > 0) { - Set moves = dragonCap.getAvailDragonMoves(); - if (!moves.isEmpty()) { - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - game.getUserInterface().selectDragonMove(moves, dragonCap.getDragonMovesLeft()); - return; - } - } - dragonCap.endDragonMove(); - next(); - } - - @Override - public void moveDragon(Position p) { - if (!dragonCap.getAvailDragonMoves().contains(p)) { - throw new IllegalArgumentException("Invalid dragon move."); - } - dragonCap.moveDragon(p); - for (Meeple m : game.getDeployedMeeples()) { - if (m.at(p) && m.canBeEatenByDragon()) { - m.undeploy(); - } - } - game.fireGameEvent().dragonMoved(p); - selectDragonMove(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.DragonCapability; + + +public class DragonMovePhase extends Phase { + + private final DragonCapability dragonCap; + + public DragonMovePhase(Game game) { + super(game); + dragonCap = game.getCapability(DragonCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(DragonCapability.class); + } + + @Override + public Player getActivePlayer() { + return dragonCap.getDragonPlayer(); + } + + @Override + public void enter() { + selectDragonMove(); + } + + private void selectDragonMove() { + if (dragonCap.getDragonMovesLeft() > 0) { + Set moves = dragonCap.getAvailDragonMoves(); + if (!moves.isEmpty()) { + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + game.getUserInterface().selectDragonMove(moves, dragonCap.getDragonMovesLeft()); + return; + } + } + dragonCap.endDragonMove(); + next(); + } + + @Override + public void moveDragon(Position p) { + if (!dragonCap.getAvailDragonMoves().contains(p)) { + throw new IllegalArgumentException("Invalid dragon move."); + } + dragonCap.moveDragon(p); + for (Meeple m : game.getDeployedMeeples()) { + if (m.at(p) && m.canBeEatenByDragon()) { + m.undeploy(); + } + } + game.fireGameEvent().dragonMoved(p); + selectDragonMove(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/DragonPhase.java b/src/main/java/com/jcloisterzone/game/phase/DragonPhase.java index a17a3a270..e62d6cc63 100644 --- a/src/main/java/com/jcloisterzone/game/phase/DragonPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/DragonPhase.java @@ -1,38 +1,38 @@ -package com.jcloisterzone.game.phase; - -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.DragonCapability; - -public class DragonPhase extends Phase { - - private final DragonCapability dragonCap; - - public DragonPhase(Game game) { - super(game); - dragonCap = game.getCapability(DragonCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(DragonCapability.class); - } - - @Override - public void enter() { - if (getTile().hasTrigger(TileTrigger.DRAGON)) { - if (dragonCap.getDragonPosition() != null) { - dragonCap.triggerDragonMove(); - next(DragonMovePhase.class); - return; - } - } - next(); - } - - - - - - -} +package com.jcloisterzone.game.phase; + +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.DragonCapability; + +public class DragonPhase extends Phase { + + private final DragonCapability dragonCap; + + public DragonPhase(Game game) { + super(game); + dragonCap = game.getCapability(DragonCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(DragonCapability.class); + } + + @Override + public void enter() { + if (getTile().hasTrigger(TileTrigger.DRAGON)) { + if (dragonCap.getDragonPosition() != null) { + dragonCap.triggerDragonMove(); + next(DragonMovePhase.class); + return; + } + } + next(); + } + + + + + + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/DrawPhase.java b/src/main/java/com/jcloisterzone/game/phase/DrawPhase.java index d6364fc69..a30e7b50b 100644 --- a/src/main/java/com/jcloisterzone/game/phase/DrawPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/DrawPhase.java @@ -1,97 +1,97 @@ -package com.jcloisterzone.game.phase; - -import java.util.List; - -import org.ini4j.Profile.Section; - -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.game.capability.RiverCapability; -import com.jcloisterzone.rmi.ServerIF; - - -public class DrawPhase extends ServerAwarePhase { - - private List debugTiles; - private final BazaarCapability bazaarCap; - - public DrawPhase(Game game, ServerIF server) { - super(game, server); - Section debugSection = game.getConfig().get("debug"); - if (debugSection != null) { - debugTiles = debugSection.getAll("draw"); - } - bazaarCap = game.getCapability(BazaarCapability.class); - } - - private boolean makeDebugDraw() { - if (debugTiles != null && debugTiles.size() > 0) { //for debug purposes only - String tileId = debugTiles.remove(0); - if (tileId.equals("!")) { - next(GameOverPhase.class); - return true; - } - TilePack tilePack = getTilePack(); - Tile tile = tilePack.drawTile(tileId); - if (tile == null) { - logger.warn("Invalid debug draw id: " + tileId); - } else { - if (game.hasCapability(RiverCapability.class) && tile.getRiver() == null && (tilePack.isGroupActive("river-start") || tilePack.isGroupActive("river"))) { - game.getCapability(RiverCapability.class).activateNonRiverTiles(); - tilePack.deactivateGroup("river-start"); - game.setCurrentTile(tile); //recovery from lake placement - } - nextTile(tile); - return true; - } - } - return false; - } - - @Override - public void enter() { - if (getTilePack().isEmpty()) { - next(GameOverPhase.class); - return; - } - if (bazaarCap != null) { - Tile tile = bazaarCap.drawNextTile(); - if (tile != null) { - nextTile(tile); - return; - } - } - - if (makeDebugDraw()) { - return; - } - if (isLocalPlayer(getActivePlayer())) { - //call only from one client (from the active one) - getServer().selectTiles(getTilePack().size(), 1); - } - } - - - - @Override - public void drawTiles(int[] tileIndex) { - assert tileIndex.length == 1; - Tile tile = getTilePack().drawTile(tileIndex[0]); - nextTile(tile); - } - - private void nextTile(Tile tile) { - game.setCurrentTile(tile); - getBoard().refreshAvailablePlacements(tile); - if (getBoard().getAvailablePlacementPositions().isEmpty()) { - getBoard().discardTile(tile); - next(DrawPhase.class); - return; - } - game.fireGameEvent().tileDrawn(tile); - next(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.List; + +import org.ini4j.Profile.Section; + +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.game.capability.RiverCapability; +import com.jcloisterzone.rmi.ServerIF; + + +public class DrawPhase extends ServerAwarePhase { + + private List debugTiles; + private final BazaarCapability bazaarCap; + + public DrawPhase(Game game, ServerIF server) { + super(game, server); + Section debugSection = game.getConfig().get("debug"); + if (debugSection != null) { + debugTiles = debugSection.getAll("draw"); + } + bazaarCap = game.getCapability(BazaarCapability.class); + } + + private boolean makeDebugDraw() { + if (debugTiles != null && debugTiles.size() > 0) { //for debug purposes only + String tileId = debugTiles.remove(0); + if (tileId.equals("!")) { + next(GameOverPhase.class); + return true; + } + TilePack tilePack = getTilePack(); + Tile tile = tilePack.drawTile(tileId); + if (tile == null) { + logger.warn("Invalid debug draw id: " + tileId); + } else { + if (game.hasCapability(RiverCapability.class) && tile.getRiver() == null && (tilePack.isGroupActive("river-start") || tilePack.isGroupActive("river"))) { + game.getCapability(RiverCapability.class).activateNonRiverTiles(); + tilePack.deactivateGroup("river-start"); + game.setCurrentTile(tile); //recovery from lake placement + } + nextTile(tile); + return true; + } + } + return false; + } + + @Override + public void enter() { + if (getTilePack().isEmpty()) { + next(GameOverPhase.class); + return; + } + if (bazaarCap != null) { + Tile tile = bazaarCap.drawNextTile(); + if (tile != null) { + nextTile(tile); + return; + } + } + + if (makeDebugDraw()) { + return; + } + if (isLocalPlayer(getActivePlayer())) { + //call only from one client (from the active one) + getServer().selectTiles(getTilePack().size(), 1); + } + } + + + + @Override + public void drawTiles(int[] tileIndex) { + assert tileIndex.length == 1; + Tile tile = getTilePack().drawTile(tileIndex[0]); + nextTile(tile); + } + + private void nextTile(Tile tile) { + game.setCurrentTile(tile); + getBoard().refreshAvailablePlacements(tile); + if (getBoard().getAvailablePlacementPositions().isEmpty()) { + getBoard().discardTile(tile); + next(DrawPhase.class); + return; + } + game.fireGameEvent().tileDrawn(tile); + next(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/EscapePhase.java b/src/main/java/com/jcloisterzone/game/phase/EscapePhase.java index 9f18e796a..f2648e0f5 100644 --- a/src/main/java/com/jcloisterzone/game/phase/EscapePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/EscapePhase.java @@ -1,96 +1,96 @@ -package com.jcloisterzone.game.phase; - -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.action.UndeployAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.SiegeCapability; - - -public class EscapePhase extends Phase { - - public EscapePhase(Game game) { - super(game); - } - - @Override - public boolean isActive() { - return game.hasCapability(SiegeCapability.class); - } - - @Override - public void enter() { - UndeployAction action = prepareEscapeAction(); - if (prepareEscapeAction() != null) { - notifyUI(action, true); - } else { - next(); - } - } - - @Override - public void pass() { - next(); - } - - private class FindNearbyCloister implements FeatureVisitor { - - private boolean result; - - - public Boolean getResult() { - return result; - } - - @Override - public boolean visit(Feature feature) { - City city = (City) feature; - if (city.isBesieged()) { //cloister must border Cathar tile - Position p = city.getTile().getPosition(); - for (Tile tile : getBoard().getAdjacentAndDiagonalTiles(p)) { - if (tile.hasCloister()) { - result = true; - return false; //do not continue, besieged cloister exists - } - } - } - return true; - } - } - - - public UndeployAction prepareEscapeAction() { - UndeployAction escapeAction = null; - for (Meeple m : game.getDeployedMeeples()) { - if (m.getPlayer() != getActivePlayer()) continue; - if (!(m.getFeature() instanceof City)) continue; - if (m.getFeature().walk(new FindNearbyCloister())) { - if (escapeAction == null) { - escapeAction = new UndeployAction("escape", PlayerRestriction.only(getActivePlayer())); - } - escapeAction.getOrCreate(m.getPosition()).add(m.getLocation()); - } - } - return escapeAction; - } - - - @Override - public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { - assert meepleOwner == getActivePlayer().getIndex(); - Meeple m = game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); - if (!(m.getFeature() instanceof City)) { - logger.error("Feature for escape action must be a city"); - return; - } - m.undeploy(); - next(); - } - -} +package com.jcloisterzone.game.phase; + +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.action.UndeployAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.SiegeCapability; + + +public class EscapePhase extends Phase { + + public EscapePhase(Game game) { + super(game); + } + + @Override + public boolean isActive() { + return game.hasCapability(SiegeCapability.class); + } + + @Override + public void enter() { + UndeployAction action = prepareEscapeAction(); + if (prepareEscapeAction() != null) { + notifyUI(action, true); + } else { + next(); + } + } + + @Override + public void pass() { + next(); + } + + private class FindNearbyCloister implements FeatureVisitor { + + private boolean result; + + + public Boolean getResult() { + return result; + } + + @Override + public boolean visit(Feature feature) { + City city = (City) feature; + if (city.isBesieged()) { //cloister must border Cathar tile + Position p = city.getTile().getPosition(); + for (Tile tile : getBoard().getAdjacentAndDiagonalTiles(p)) { + if (tile.hasCloister()) { + result = true; + return false; //do not continue, besieged cloister exists + } + } + } + return true; + } + } + + + public UndeployAction prepareEscapeAction() { + UndeployAction escapeAction = null; + for (Meeple m : game.getDeployedMeeples()) { + if (m.getPlayer() != getActivePlayer()) continue; + if (!(m.getFeature() instanceof City)) continue; + if (m.getFeature().walk(new FindNearbyCloister())) { + if (escapeAction == null) { + escapeAction = new UndeployAction("escape", PlayerRestriction.only(getActivePlayer())); + } + escapeAction.getOrCreate(m.getPosition()).add(m.getLocation()); + } + } + return escapeAction; + } + + + @Override + public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { + assert meepleOwner == getActivePlayer().getIndex(); + Meeple m = game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); + if (!(m.getFeature() instanceof City)) { + logger.error("Feature for escape action must be a city"); + return; + } + m.undeploy(); + next(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/FairyPhase.java b/src/main/java/com/jcloisterzone/game/phase/FairyPhase.java index f4788599b..b313f7dad 100644 --- a/src/main/java/com/jcloisterzone/game/phase/FairyPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/FairyPhase.java @@ -1,40 +1,40 @@ -package com.jcloisterzone.game.phase; - -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.FairyCapability; - - -public class FairyPhase extends Phase { - - private final FairyCapability fairyCap; - - public FairyPhase(Game game) { - super(game); - fairyCap = game.getCapability(FairyCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(FairyCapability.class); - } - - @Override - public void enter() { - Position fairyPos = fairyCap.getFairyPosition(); - if (fairyPos != null) { - for (Meeple m : game.getDeployedMeeples()) { - if (m.at(fairyPos) && m.getPlayer() == getActivePlayer()) { - m.getPlayer().addPoints(1, PointCategory.FAIRY); - game.fireGameEvent().scored(m.getPosition(), m.getPlayer(), 1, "1", false); - break; - } - } - } - next(); - } - - -} +package com.jcloisterzone.game.phase; + +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.FairyCapability; + + +public class FairyPhase extends Phase { + + private final FairyCapability fairyCap; + + public FairyPhase(Game game) { + super(game); + fairyCap = game.getCapability(FairyCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(FairyCapability.class); + } + + @Override + public void enter() { + Position fairyPos = fairyCap.getFairyPosition(); + if (fairyPos != null) { + for (Meeple m : game.getDeployedMeeples()) { + if (m.at(fairyPos) && m.getPlayer() == getActivePlayer()) { + m.getPlayer().addPoints(1, PointCategory.FAIRY); + game.fireGameEvent().scored(m.getPosition(), m.getPlayer(), 1, "1", false); + break; + } + } + } + next(); + } + + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/FlierActionPhase.java b/src/main/java/com/jcloisterzone/game/phase/FlierActionPhase.java index 4868e5a87..2bf27c324 100644 --- a/src/main/java/com/jcloisterzone/game/phase/FlierActionPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/FlierActionPhase.java @@ -1,89 +1,89 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.IsCompleted; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.FlierCapability; - -public class FlierActionPhase extends Phase { - - private final FlierCapability flierCap; - - public FlierActionPhase(Game game) { - super(game); - flierCap = game.getCapability(FlierCapability.class); - } - - @Override - public void enter() { - int distance = flierCap.getFlierDistance(); - Tile origin = game.getCurrentTile(); - Location direction = origin.getFlier().rotateCW(origin.getRotation()); - Position pos = game.getCurrentTile().getPosition(); - for (int i = 0; i < distance; i++) { - pos = pos.add(direction); - } - Tile target = getBoard().get(pos); - - if (target == null || !game.isDeployAllowed(target, Follower.class)) { - next(); - return; - } - - LocationsMap sites = new LocationsMap(); - Set locations = new HashSet<>(); - for (Feature f : target.getFeatures()) { - if (f instanceof Farm) continue; - if (f.walk(new IsCompleted())) continue; - locations.add(f.getLocation()); - } - if (locations.isEmpty()) { - next(); - return; - } - sites.put(pos, locations); - - List actions = new ArrayList<>(); - if (getActivePlayer().hasFollower(SmallFollower.class)) { - actions.add(new MeepleAction(SmallFollower.class, sites)); - } - game.prepareFollowerActions(actions, sites); - notifyUI(actions, false); - } - - @Override - public void notifyRansomPaid() { - enter(); //recompute available actions - } - - @Override - public void next() { - flierCap.setFlierDistance(0); - super.next(); - } - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); - Tile tile = getBoard().get(p); - m.deployUnchecked(tile, loc, tile.getFeature(loc)); - game.fireGameEvent().deployed(m); - next(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.IsCompleted; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.FlierCapability; + +public class FlierActionPhase extends Phase { + + private final FlierCapability flierCap; + + public FlierActionPhase(Game game) { + super(game); + flierCap = game.getCapability(FlierCapability.class); + } + + @Override + public void enter() { + int distance = flierCap.getFlierDistance(); + Tile origin = game.getCurrentTile(); + Location direction = origin.getFlier().rotateCW(origin.getRotation()); + Position pos = game.getCurrentTile().getPosition(); + for (int i = 0; i < distance; i++) { + pos = pos.add(direction); + } + Tile target = getBoard().get(pos); + + if (target == null || !game.isDeployAllowed(target, Follower.class)) { + next(); + return; + } + + LocationsMap sites = new LocationsMap(); + Set locations = new HashSet<>(); + for (Feature f : target.getFeatures()) { + if (f instanceof Farm) continue; + if (f.walk(new IsCompleted())) continue; + locations.add(f.getLocation()); + } + if (locations.isEmpty()) { + next(); + return; + } + sites.put(pos, locations); + + List actions = new ArrayList<>(); + if (getActivePlayer().hasFollower(SmallFollower.class)) { + actions.add(new MeepleAction(SmallFollower.class, sites)); + } + game.prepareFollowerActions(actions, sites); + notifyUI(actions, false); + } + + @Override + public void notifyRansomPaid() { + enter(); //recompute available actions + } + + @Override + public void next() { + flierCap.setFlierDistance(0); + super.next(); + } + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); + Tile tile = getBoard().get(p); + m.deployUnchecked(tile, loc, tile.getFeature(loc)); + game.fireGameEvent().deployed(m); + next(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/GameOverPhase.java b/src/main/java/com/jcloisterzone/game/phase/GameOverPhase.java index 477ac65c3..88fcfba17 100644 --- a/src/main/java/com/jcloisterzone/game/phase/GameOverPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/GameOverPhase.java @@ -1,77 +1,77 @@ -package com.jcloisterzone.game.phase; - -import com.jcloisterzone.Player; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.score.ScoreAllCallback; -import com.jcloisterzone.feature.score.ScoreAllFeatureFinder; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.FairyCapability; - - -public class GameOverPhase extends Phase implements ScoreAllCallback { - - public GameOverPhase(Game game) { - super(game); - } - - @Override - public void enter() { - FairyCapability fairyCap = game.getCapability(FairyCapability.class); - if (fairyCap != null) { - //erase position to not affect final scoring - fairyCap.setFairyPosition(null); - } - - ScoreAllFeatureFinder scoreAll = new ScoreAllFeatureFinder(); - scoreAll.scoreAll(game, this); - - game.finalScoring(); - game.fireGameEvent().gameOver(); - } - - @Override - public void scoreCastle(Meeple meeple, Castle castle) { - game.fireGameEvent().scored(meeple.getFeature(), 0, "0", meeple, true); - } - - @Override - public void scoreFarm(FarmScoreContext ctx, Player p) { - int points = ctx.getPoints(p); - game.scoreFeature(points, ctx, p); - } - - @Override - public void scoreBarn(FarmScoreContext ctx, Barn meeple) { - int points = ctx.getBarnPoints(); - meeple.getPlayer().addPoints(points, ctx.getMasterFeature().getPointCategory()); - game.fireGameEvent().scored(meeple.getFeature(), points, points+"", meeple, true); - } - - - @Override - public void scoreCompletableFeature(CompletableScoreContext ctx) { - game.scoreCompletableFeature(ctx); - } - - @Override - public CompletableScoreContext getCompletableScoreContext(Completable completable) { - return completable.getScoreContext(); - } - - @Override - public FarmScoreContext getFarmScoreContext(Farm farm) { - return farm.getScoreContext(); - } - - @Override - public Player getActivePlayer() { - return null; - } - -} +package com.jcloisterzone.game.phase; + +import com.jcloisterzone.Player; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.score.ScoreAllCallback; +import com.jcloisterzone.feature.score.ScoreAllFeatureFinder; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.FairyCapability; + + +public class GameOverPhase extends Phase implements ScoreAllCallback { + + public GameOverPhase(Game game) { + super(game); + } + + @Override + public void enter() { + FairyCapability fairyCap = game.getCapability(FairyCapability.class); + if (fairyCap != null) { + //erase position to not affect final scoring + fairyCap.setFairyPosition(null); + } + + ScoreAllFeatureFinder scoreAll = new ScoreAllFeatureFinder(); + scoreAll.scoreAll(game, this); + + game.finalScoring(); + game.fireGameEvent().gameOver(); + } + + @Override + public void scoreCastle(Meeple meeple, Castle castle) { + game.fireGameEvent().scored(meeple.getFeature(), 0, "0", meeple, true); + } + + @Override + public void scoreFarm(FarmScoreContext ctx, Player p) { + int points = ctx.getPoints(p); + game.scoreFeature(points, ctx, p); + } + + @Override + public void scoreBarn(FarmScoreContext ctx, Barn meeple) { + int points = ctx.getBarnPoints(); + meeple.getPlayer().addPoints(points, ctx.getMasterFeature().getPointCategory()); + game.fireGameEvent().scored(meeple.getFeature(), points, points+"", meeple, true); + } + + + @Override + public void scoreCompletableFeature(CompletableScoreContext ctx) { + game.scoreCompletableFeature(ctx); + } + + @Override + public CompletableScoreContext getCompletableScoreContext(Completable completable) { + return completable.getScoreContext(); + } + + @Override + public FarmScoreContext getFarmScoreContext(Farm farm) { + return farm.getScoreContext(); + } + + @Override + public Player getActivePlayer() { + return null; + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/LoadGamePhase.java b/src/main/java/com/jcloisterzone/game/phase/LoadGamePhase.java index e84fcc560..7ec544684 100644 --- a/src/main/java/com/jcloisterzone/game/phase/LoadGamePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/LoadGamePhase.java @@ -1,101 +1,101 @@ -package com.jcloisterzone.game.phase; - -import java.util.Iterator; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.DefaultTilePack; -import com.jcloisterzone.board.LoadGameTilePackFactory; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.rmi.ServerIF; - -public class LoadGamePhase extends CreateGamePhase { - - private Snapshot snapshot; - private LoadGameTilePackFactory tilePackFactory; - - public LoadGamePhase(Game game, Snapshot snapshot, ServerIF server) { - super(game, server); - this.snapshot = snapshot; - } - - @Override - protected Snapshot getSnapshot() { - return snapshot; - } - - @Override - protected void preparePlayers() { - //update plain (created by snapshot) players's slot with real one from dialog - for (int i = 0; i < slots.length; i++) { - for (Player p: game.getAllPlayers()) { - if (p.getSlot().getNumber() == i) { - p.setSlot(slots[i]); - } - } - } - initializePlayersMeeples(); - } - - - @Override - protected void preparePhases() { - super.preparePhases(); - Phase active = game.getPhases().get(snapshot.getActivePhase()); - setDefaultNext(active); - } - - @Override - protected void preplaceTiles() { - //super.preplaceTiles(); - for (Iterator iter = ((DefaultTilePack)getTilePack()).drawPrePlacedActiveTiles().iterator(); iter.hasNext();) { - Tile preplaced = iter.next(); - game.getBoard().add(preplaced, preplaced.getPosition(), true); - game.getBoard().mergeFeatures(preplaced); - game.fireGameEvent().tilePlaced(preplaced); - if (preplaced.getBridge() != null) { - game.fireGameEvent().bridgeDeployed(preplaced.getPosition(), preplaced.getBridge().getLocation()); - } - } - for (Meeple m : tilePackFactory.getPreplacedMeeples()) { - Tile tile = game.getBoard().get(m.getPosition()); - Feature f; - if (m instanceof Barn) { - //special case, barn holds 'corner' location - f = tile.getFeaturePartOf(m.getLocation()); - } else { - f = tile.getFeature(m.getLocation()); - } - m.setFeature(f); - f.addMeeple(m); - game.fireGameEvent().deployed(m); - } - tilePackFactory.activateGroups((DefaultTilePack) game.getTilePack()); - snapshot.loadCapabilities(game); - } - - @Override - protected void prepareTilePack() { - tilePackFactory = new LoadGameTilePackFactory(); - tilePackFactory.setGame(game); - tilePackFactory.setConfig(game.getConfig()); - tilePackFactory.setExpansions(game.getExpansions()); - tilePackFactory.setSnapshot(snapshot); - DefaultTilePack tilePack = tilePackFactory.createTilePack(); - game.setTilePack(tilePack); - for (String tileId : snapshot.getDiscardedTiles()) { - Tile tile = tilePack.drawTile(tileId); - game.getBoard().discardTile(tile); - } - } - - @Override - public void next() { - super.next(); - getDefaultNext().loadGame(snapshot); //call after super.next() to be able fake entered flag - } -} +package com.jcloisterzone.game.phase; + +import java.util.Iterator; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.DefaultTilePack; +import com.jcloisterzone.board.LoadGameTilePackFactory; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.rmi.ServerIF; + +public class LoadGamePhase extends CreateGamePhase { + + private Snapshot snapshot; + private LoadGameTilePackFactory tilePackFactory; + + public LoadGamePhase(Game game, Snapshot snapshot, ServerIF server) { + super(game, server); + this.snapshot = snapshot; + } + + @Override + protected Snapshot getSnapshot() { + return snapshot; + } + + @Override + protected void preparePlayers() { + //update plain (created by snapshot) players's slot with real one from dialog + for (int i = 0; i < slots.length; i++) { + for (Player p: game.getAllPlayers()) { + if (p.getSlot().getNumber() == i) { + p.setSlot(slots[i]); + } + } + } + initializePlayersMeeples(); + } + + + @Override + protected void preparePhases() { + super.preparePhases(); + Phase active = game.getPhases().get(snapshot.getActivePhase()); + setDefaultNext(active); + } + + @Override + protected void preplaceTiles() { + //super.preplaceTiles(); + for (Iterator iter = ((DefaultTilePack)getTilePack()).drawPrePlacedActiveTiles().iterator(); iter.hasNext();) { + Tile preplaced = iter.next(); + game.getBoard().add(preplaced, preplaced.getPosition(), true); + game.getBoard().mergeFeatures(preplaced); + game.fireGameEvent().tilePlaced(preplaced); + if (preplaced.getBridge() != null) { + game.fireGameEvent().bridgeDeployed(preplaced.getPosition(), preplaced.getBridge().getLocation()); + } + } + for (Meeple m : tilePackFactory.getPreplacedMeeples()) { + Tile tile = game.getBoard().get(m.getPosition()); + Feature f; + if (m instanceof Barn) { + //special case, barn holds 'corner' location + f = tile.getFeaturePartOf(m.getLocation()); + } else { + f = tile.getFeature(m.getLocation()); + } + m.setFeature(f); + f.addMeeple(m); + game.fireGameEvent().deployed(m); + } + tilePackFactory.activateGroups((DefaultTilePack) game.getTilePack()); + snapshot.loadCapabilities(game); + } + + @Override + protected void prepareTilePack() { + tilePackFactory = new LoadGameTilePackFactory(); + tilePackFactory.setGame(game); + tilePackFactory.setConfig(game.getConfig()); + tilePackFactory.setExpansions(game.getExpansions()); + tilePackFactory.setSnapshot(snapshot); + DefaultTilePack tilePack = tilePackFactory.createTilePack(); + game.setTilePack(tilePack); + for (String tileId : snapshot.getDiscardedTiles()) { + Tile tile = tilePack.drawTile(tileId); + game.getBoard().discardTile(tile); + } + } + + @Override + public void next() { + super.next(); + getDefaultNext().loadGame(snapshot); //call after super.next() to be able fake entered flag + } +} diff --git a/src/main/java/com/jcloisterzone/game/phase/PhantomPhase.java b/src/main/java/com/jcloisterzone/game/phase/PhantomPhase.java index 1aae28d21..1623bdda7 100644 --- a/src/main/java/com/jcloisterzone/game/phase/PhantomPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/PhantomPhase.java @@ -1,80 +1,80 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; -import java.util.List; - -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Phantom; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.PhantomCapability; -import com.jcloisterzone.game.capability.TowerCapability; - -public class PhantomPhase extends Phase { - - private final TowerCapability towerCap; - - public PhantomPhase(Game game) { - super(game); - towerCap = game.getCapability(TowerCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(PhantomCapability.class); - } - - @Override - public void notifyRansomPaid() { - enter(); //recompute available actions - } - - @Override - public void enter() { - List actions = new ArrayList<>(); - - LocationsMap commonSites = game.prepareFollowerLocations(); - if (getActivePlayer().hasFollower(Phantom.class)) { - if (towerCap != null) { - towerCap.prepareTowerFollowerDeploy(commonSites); - } - if (!commonSites.isEmpty()) { - actions.add(new MeepleAction(Phantom.class, commonSites)); - } - } - if (isAutoTurnEnd(actions)) { - next(); - } else { - notifyUI(actions, true); - } - } - - private boolean isAutoTurnEnd(List actions) { - if (!actions.isEmpty()) return false; - if (towerCap != null && !towerCap.isRansomPaidThisTurn() && towerCap.hasImprisonedFollower(getActivePlayer(), Phantom.class)) { - //player can return phantom figure immediately - return false; - } - return true; - } - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - if (!meepleType.equals(Phantom.class)) { - throw new IllegalArgumentException("Only phantom can be placed as second follower."); - } - Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); - m.deploy(getBoard().get(p), loc); - next(); - } - - @Override - public void pass() { - next(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; +import java.util.List; + +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Phantom; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.PhantomCapability; +import com.jcloisterzone.game.capability.TowerCapability; + +public class PhantomPhase extends Phase { + + private final TowerCapability towerCap; + + public PhantomPhase(Game game) { + super(game); + towerCap = game.getCapability(TowerCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(PhantomCapability.class); + } + + @Override + public void notifyRansomPaid() { + enter(); //recompute available actions + } + + @Override + public void enter() { + List actions = new ArrayList<>(); + + LocationsMap commonSites = game.prepareFollowerLocations(); + if (getActivePlayer().hasFollower(Phantom.class)) { + if (towerCap != null) { + towerCap.prepareTowerFollowerDeploy(commonSites); + } + if (!commonSites.isEmpty()) { + actions.add(new MeepleAction(Phantom.class, commonSites)); + } + } + if (isAutoTurnEnd(actions)) { + next(); + } else { + notifyUI(actions, true); + } + } + + private boolean isAutoTurnEnd(List actions) { + if (!actions.isEmpty()) return false; + if (towerCap != null && !towerCap.isRansomPaidThisTurn() && towerCap.hasImprisonedFollower(getActivePlayer(), Phantom.class)) { + //player can return phantom figure immediately + return false; + } + return true; + } + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + if (!meepleType.equals(Phantom.class)) { + throw new IllegalArgumentException("Only phantom can be placed as second follower."); + } + Meeple m = getActivePlayer().getMeepleFromSupply(meepleType); + m.deploy(getBoard().get(p), loc); + next(); + } + + @Override + public void pass() { + next(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/Phase.java b/src/main/java/com/jcloisterzone/game/phase/Phase.java index c0e0533b6..0729a80d3 100644 --- a/src/main/java/com/jcloisterzone/game/phase/Phase.java +++ b/src/main/java/com/jcloisterzone/game/phase/Phase.java @@ -1,235 +1,235 @@ -package com.jcloisterzone.game.phase; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Application; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Board; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.rmi.ClientIF; - - -public abstract class Phase implements ClientIF { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - protected final Game game; - - private boolean entered; - private Phase defaultNext; - - public Phase(Game game) { - this.game = game; - } - - public boolean isEntered() { - return entered; - } - - public void setEntered(boolean entered) { - this.entered = entered; - } - - public Phase getDefaultNext() { - return defaultNext; - } - - public void setDefaultNext(Phase defaultNext) { - this.defaultNext = defaultNext; - } - - public void next() { - game.setPhase(defaultNext); - } - - public void next(Class phaseClass) { - game.setPhase(game.getPhases().get(phaseClass)); - } - - public void enter() { } - - /** - * Method is invoked on active phase when user buy back inprisoned follower - */ - public void notifyRansomPaid() { - //do nothing by default - } - - public boolean isActive() { - return true; - } - - //shortcuts - - protected TilePack getTilePack() { - return game.getTilePack(); - } - protected Board getBoard() { - return game.getBoard(); - } - - protected Tile getTile() { - return game.getCurrentTile(); - } - - public Player getActivePlayer() { - return game.getTurnPlayer(); - } - - - protected void notifyUI(List actions, boolean canPass) { - game.getUserInterface().selectAction(actions, canPass); - } - - protected void notifyUI(PlayerAction action, boolean canPass) { - game.getUserInterface().selectAction(Collections.singletonList(action), canPass); - } - - /** handler called after game is load if this phase is active */ - public void loadGame(Snapshot snapshot) { - //do nothing by default - } - - //adapter methods - - @Override - public void startGame() { - logger.error(Application.ILLEGAL_STATE_MSG, "startGame"); - } - - @Override - public void pass() { - logger.error(Application.ILLEGAL_STATE_MSG, "pass"); - } - - @Override - public void placeTile(Rotation rotation, Position position) { - logger.error(Application.ILLEGAL_STATE_MSG, "placeTile"); - } - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - logger.error(Application.ILLEGAL_STATE_MSG, "deployMeeple"); - } - - @Override - public void moveFairy(Position p) { - logger.error(Application.ILLEGAL_STATE_MSG, "moveFairy"); - } - - @Override - public void placeTowerPiece(Position p) { - logger.error(Application.ILLEGAL_STATE_MSG, "placeTowerPiece"); - } - - @Override - public void placeTunnelPiece(Position p, Location loc, boolean isSecondPiece) { - logger.error(Application.ILLEGAL_STATE_MSG, "placeTunnelPiece"); - } - - @Override - public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { - logger.error(Application.ILLEGAL_STATE_MSG, "undeployMeeple"); - } - - @Override - public void moveDragon(Position p) { - logger.error(Application.ILLEGAL_STATE_MSG, "moveDragon"); - } - - @Override - public void payRansom(Integer playerIndexToPay, Class meepleType) { - //pay ransom is valid any time - TowerCapability towerCap = game.getCapability(TowerCapability.class); - if (towerCap == null) { - logger.error(Application.ILLEGAL_STATE_MSG, "payRansom"); - return; - } - towerCap.payRansom(playerIndexToPay, meepleType); - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateCustomRule"); - } - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateExpansion"); - - } - @Override - public void updateSlot(PlayerSlot slot) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateSlot"); - } - - @Override - public void updateSupportedExpansions(EnumSet expansions) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateSupportedExpansions"); - } - - - @Override - public void drawTiles(int[] tileIndex) { - logger.error(Application.ILLEGAL_STATE_MSG, "drawTiles"); - } - - @Override - public void takePrisoner(Position p, Location loc, Class meepleType, Integer meepleOwner) { - logger.error(Application.ILLEGAL_STATE_MSG, "takePrisoner"); - } - - @Override - public void deployBridge(Position pos, Location loc) { - logger.error(Application.ILLEGAL_STATE_MSG, "deployBridge"); - - } - - @Override - public void deployCastle(Position pos, Location loc) { - logger.error(Application.ILLEGAL_STATE_MSG, "deployCastle"); - } - - @Override - public void bazaarBid(Integer supplyIndex, Integer price) { - logger.error(Application.ILLEGAL_STATE_MSG, "bazaarBid"); - } - - @Override - public void bazaarBuyOrSell(boolean buy) { - logger.error(Application.ILLEGAL_STATE_MSG, "bazaarBuyOrSell"); - } - - @Override - public void cornCiclesRemoveOrDeploy(boolean remove) { - logger.error(Application.ILLEGAL_STATE_MSG, "cornCiclesRemoveOrDeploy"); - } - - @Override - public void setFlierDistance(int distance) { - logger.error(Application.ILLEGAL_STATE_MSG, "setFlierDistance"); - } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Application; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Board; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.rmi.ClientIF; + + +public abstract class Phase implements ClientIF { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + protected final Game game; + + private boolean entered; + private Phase defaultNext; + + public Phase(Game game) { + this.game = game; + } + + public boolean isEntered() { + return entered; + } + + public void setEntered(boolean entered) { + this.entered = entered; + } + + public Phase getDefaultNext() { + return defaultNext; + } + + public void setDefaultNext(Phase defaultNext) { + this.defaultNext = defaultNext; + } + + public void next() { + game.setPhase(defaultNext); + } + + public void next(Class phaseClass) { + game.setPhase(game.getPhases().get(phaseClass)); + } + + public void enter() { } + + /** + * Method is invoked on active phase when user buy back inprisoned follower + */ + public void notifyRansomPaid() { + //do nothing by default + } + + public boolean isActive() { + return true; + } + + //shortcuts + + protected TilePack getTilePack() { + return game.getTilePack(); + } + protected Board getBoard() { + return game.getBoard(); + } + + protected Tile getTile() { + return game.getCurrentTile(); + } + + public Player getActivePlayer() { + return game.getTurnPlayer(); + } + + + protected void notifyUI(List actions, boolean canPass) { + game.getUserInterface().selectAction(actions, canPass); + } + + protected void notifyUI(PlayerAction action, boolean canPass) { + game.getUserInterface().selectAction(Collections.singletonList(action), canPass); + } + + /** handler called after game is load if this phase is active */ + public void loadGame(Snapshot snapshot) { + //do nothing by default + } + + //adapter methods + + @Override + public void startGame() { + logger.error(Application.ILLEGAL_STATE_MSG, "startGame"); + } + + @Override + public void pass() { + logger.error(Application.ILLEGAL_STATE_MSG, "pass"); + } + + @Override + public void placeTile(Rotation rotation, Position position) { + logger.error(Application.ILLEGAL_STATE_MSG, "placeTile"); + } + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + logger.error(Application.ILLEGAL_STATE_MSG, "deployMeeple"); + } + + @Override + public void moveFairy(Position p) { + logger.error(Application.ILLEGAL_STATE_MSG, "moveFairy"); + } + + @Override + public void placeTowerPiece(Position p) { + logger.error(Application.ILLEGAL_STATE_MSG, "placeTowerPiece"); + } + + @Override + public void placeTunnelPiece(Position p, Location loc, boolean isSecondPiece) { + logger.error(Application.ILLEGAL_STATE_MSG, "placeTunnelPiece"); + } + + @Override + public void undeployMeeple(Position p, Location loc, Class meepleType, Integer meepleOwner) { + logger.error(Application.ILLEGAL_STATE_MSG, "undeployMeeple"); + } + + @Override + public void moveDragon(Position p) { + logger.error(Application.ILLEGAL_STATE_MSG, "moveDragon"); + } + + @Override + public void payRansom(Integer playerIndexToPay, Class meepleType) { + //pay ransom is valid any time + TowerCapability towerCap = game.getCapability(TowerCapability.class); + if (towerCap == null) { + logger.error(Application.ILLEGAL_STATE_MSG, "payRansom"); + return; + } + towerCap.payRansom(playerIndexToPay, meepleType); + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateCustomRule"); + } + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateExpansion"); + + } + @Override + public void updateSlot(PlayerSlot slot) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateSlot"); + } + + @Override + public void updateSupportedExpansions(EnumSet expansions) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateSupportedExpansions"); + } + + + @Override + public void drawTiles(int[] tileIndex) { + logger.error(Application.ILLEGAL_STATE_MSG, "drawTiles"); + } + + @Override + public void takePrisoner(Position p, Location loc, Class meepleType, Integer meepleOwner) { + logger.error(Application.ILLEGAL_STATE_MSG, "takePrisoner"); + } + + @Override + public void deployBridge(Position pos, Location loc) { + logger.error(Application.ILLEGAL_STATE_MSG, "deployBridge"); + + } + + @Override + public void deployCastle(Position pos, Location loc) { + logger.error(Application.ILLEGAL_STATE_MSG, "deployCastle"); + } + + @Override + public void bazaarBid(Integer supplyIndex, Integer price) { + logger.error(Application.ILLEGAL_STATE_MSG, "bazaarBid"); + } + + @Override + public void bazaarBuyOrSell(boolean buy) { + logger.error(Application.ILLEGAL_STATE_MSG, "bazaarBuyOrSell"); + } + + @Override + public void cornCiclesRemoveOrDeploy(boolean remove) { + logger.error(Application.ILLEGAL_STATE_MSG, "cornCiclesRemoveOrDeploy"); + } + + @Override + public void setFlierDistance(int distance) { + logger.error(Application.ILLEGAL_STATE_MSG, "setFlierDistance"); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/PlaguePhase.java b/src/main/java/com/jcloisterzone/game/phase/PlaguePhase.java index a30bf1b54..1e02d9771 100644 --- a/src/main/java/com/jcloisterzone/game/phase/PlaguePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/PlaguePhase.java @@ -1,39 +1,39 @@ -package com.jcloisterzone.game.phase; - -import java.util.List; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.TileTrigger; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.PlagueCapability; -import com.jcloisterzone.game.capability.PlagueCapability.PlagueSource; - -public class PlaguePhase extends Phase { - - private final PlagueCapability plagueCap; - - public PlaguePhase(Game game) { - super(game); - plagueCap = game.getCapability(PlagueCapability.class); - } - - @Override - public boolean isActive() { - return game.hasCapability(PlagueCapability.class); - } - - @Override - public void enter() { - if (getTile().hasTrigger(TileTrigger.PLAGUE)) { - PlagueSource source = new PlagueSource(getTile().getPosition()); - plagueCap.getPlagueSources().add(source); - } else { - List sources = plagueCap.getActiveSources(); - if (!sources.isEmpty()) { - //TODO spread flea - } - } - next(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.List; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.TileTrigger; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.PlagueCapability; +import com.jcloisterzone.game.capability.PlagueCapability.PlagueSource; + +public class PlaguePhase extends Phase { + + private final PlagueCapability plagueCap; + + public PlaguePhase(Game game) { + super(game); + plagueCap = game.getCapability(PlagueCapability.class); + } + + @Override + public boolean isActive() { + return game.hasCapability(PlagueCapability.class); + } + + @Override + public void enter() { + if (getTile().hasTrigger(TileTrigger.PLAGUE)) { + PlagueSource source = new PlagueSource(getTile().getPosition()); + plagueCap.getPlagueSources().add(source); + } else { + List sources = plagueCap.getActiveSources(); + if (!sources.isEmpty()) { + //TODO spread flea + } + } + next(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/ScorePhase.java b/src/main/java/com/jcloisterzone/game/phase/ScorePhase.java index 4b39f3a6d..350c102dc 100644 --- a/src/main/java/com/jcloisterzone/game/phase/ScorePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/ScorePhase.java @@ -1,177 +1,177 @@ -package com.jcloisterzone.game.phase; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.feature.visitor.score.FarmScoreContext; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Builder; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.BarnCapability; -import com.jcloisterzone.game.capability.BuilderCapability; -import com.jcloisterzone.game.capability.CastleCapability; -import com.jcloisterzone.game.capability.TunnelCapability; - -public class ScorePhase extends Phase { - - private Set alredyScored = new HashSet<>(); - - private final BarnCapability barnCap; - private final BuilderCapability builderCap; - private final CastleCapability castleCap; - private final TunnelCapability tunnelCap; - - public ScorePhase(Game game) { - super(game); - barnCap = game.getCapability(BarnCapability.class); - builderCap = game.getCapability(BuilderCapability.class); - tunnelCap = game.getCapability(TunnelCapability.class); - castleCap = game.getCapability(CastleCapability.class); - } - - private void scoreCompletedOnTile(Tile tile) { - for (Feature feature : tile.getFeatures()) { - if (feature instanceof Completable) { - scoreCompleted((Completable) feature); - } - } - } - - private void scoreCompletedNearAbbey(Position pos) { - for (Entry e : getBoard().getAdjacentTilesMap(pos).entrySet()) { - Tile tile = e.getValue(); - Feature feature = tile.getFeaturePartOf(e.getKey().rev()); - if (feature instanceof Completable) { - scoreCompleted((Completable) feature); - } - } - } - - private void scoreFollowersOnBarnFarm(Farm farm, Map cityCache) { - FarmScoreContext ctx = farm.getScoreContext(); - ctx.setCityCache(cityCache); - farm.walk(ctx); - - boolean hasBarn = false; - for (Meeple m : ctx.getSpecialMeeples()) { - if (m instanceof Barn) { - hasBarn = true; - break; - } - } - if (hasBarn) { - for (Player p : ctx.getMajorOwners()) { - int points = ctx.getPointsWhenBarnIsConnected(p); - game.scoreFeature(points, ctx, p); - } - for (Meeple m : ctx.getMeeples()) { - if (!(m instanceof Barn)) { - m.undeploy(false); - } - } - } - } - - @Override - public void enter() { - Position pos = getTile().getPosition(); - - //TODO separate event here ??? and move this code to abbey and mayor game - if (barnCap != null) { - Map cityCache = new HashMap<>(); - for (Feature feature : getTile().getFeatures()) { - if (feature instanceof Farm) { - scoreFollowersOnBarnFarm((Farm) feature, cityCache); - } - } - } - - scoreCompletedOnTile(getTile()); - if (getTile().isAbbeyTile()) { - scoreCompletedNearAbbey(pos); - } - - if (tunnelCap != null) { - Road r = tunnelCap.getPlacedTunnel(); - if (r != null) { - scoreCompleted(r); - } - } - - for (Tile neighbour : getBoard().getAdjacentAndDiagonalTiles(pos)) { - Cloister cloister = neighbour.getCloister(); - if (cloister != null) { - scoreCompleted(cloister); - } - } - - if (castleCap != null) { - for (Entry entry : castleCap.getCastleScore().entrySet()) { - scoreCastle(entry.getKey(), entry.getValue()); - } - } - - alredyScored.clear(); - next(); - } - - protected void undeployMeeples(CompletableScoreContext ctx) { - for (Meeple m : ctx.getMeeples()) { - m.undeploy(false); - } - } - - private void scoreCastle(Castle castle, int points) { - List meeples = castle.getMeeples(); - if (meeples.isEmpty()) meeples = castle.getSecondFeature().getMeeples(); - Meeple m = meeples.get(0); //all meeples must share same owner - m.getPlayer().addPoints(points, PointCategory.CASTLE); - game.fireGameEvent().scored(m.getFeature(), points, points+"", m, false); - m.undeploy(false); - } - - private void scoreCompleted(Completable completable) { - CompletableScoreContext ctx = completable.getScoreContext(); - completable.walk(ctx); - if (builderCap != null) { - for (Meeple m : ctx.getSpecialMeeples()) { - if (m instanceof Builder && m.getPlayer().equals(getActivePlayer())) { - if (!m.at(getTile().getPosition())) { - builderCap.useBuilder(); - } - break; - } - } - } - if (ctx.isCompleted()) { - Completable master = (Completable) ctx.getMasterFeature(); - if (!alredyScored.contains(master)) { - alredyScored.add(master); - game.scoreCompleted(ctx); - game.scoreCompletableFeature(ctx); - undeployMeeples(ctx); - game.fireGameEvent().completed(master, ctx); - } - } - } - -} +package com.jcloisterzone.game.phase; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.feature.visitor.score.FarmScoreContext; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Builder; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.BarnCapability; +import com.jcloisterzone.game.capability.BuilderCapability; +import com.jcloisterzone.game.capability.CastleCapability; +import com.jcloisterzone.game.capability.TunnelCapability; + +public class ScorePhase extends Phase { + + private Set alredyScored = new HashSet<>(); + + private final BarnCapability barnCap; + private final BuilderCapability builderCap; + private final CastleCapability castleCap; + private final TunnelCapability tunnelCap; + + public ScorePhase(Game game) { + super(game); + barnCap = game.getCapability(BarnCapability.class); + builderCap = game.getCapability(BuilderCapability.class); + tunnelCap = game.getCapability(TunnelCapability.class); + castleCap = game.getCapability(CastleCapability.class); + } + + private void scoreCompletedOnTile(Tile tile) { + for (Feature feature : tile.getFeatures()) { + if (feature instanceof Completable) { + scoreCompleted((Completable) feature); + } + } + } + + private void scoreCompletedNearAbbey(Position pos) { + for (Entry e : getBoard().getAdjacentTilesMap(pos).entrySet()) { + Tile tile = e.getValue(); + Feature feature = tile.getFeaturePartOf(e.getKey().rev()); + if (feature instanceof Completable) { + scoreCompleted((Completable) feature); + } + } + } + + private void scoreFollowersOnBarnFarm(Farm farm, Map cityCache) { + FarmScoreContext ctx = farm.getScoreContext(); + ctx.setCityCache(cityCache); + farm.walk(ctx); + + boolean hasBarn = false; + for (Meeple m : ctx.getSpecialMeeples()) { + if (m instanceof Barn) { + hasBarn = true; + break; + } + } + if (hasBarn) { + for (Player p : ctx.getMajorOwners()) { + int points = ctx.getPointsWhenBarnIsConnected(p); + game.scoreFeature(points, ctx, p); + } + for (Meeple m : ctx.getMeeples()) { + if (!(m instanceof Barn)) { + m.undeploy(false); + } + } + } + } + + @Override + public void enter() { + Position pos = getTile().getPosition(); + + //TODO separate event here ??? and move this code to abbey and mayor game + if (barnCap != null) { + Map cityCache = new HashMap<>(); + for (Feature feature : getTile().getFeatures()) { + if (feature instanceof Farm) { + scoreFollowersOnBarnFarm((Farm) feature, cityCache); + } + } + } + + scoreCompletedOnTile(getTile()); + if (getTile().isAbbeyTile()) { + scoreCompletedNearAbbey(pos); + } + + if (tunnelCap != null) { + Road r = tunnelCap.getPlacedTunnel(); + if (r != null) { + scoreCompleted(r); + } + } + + for (Tile neighbour : getBoard().getAdjacentAndDiagonalTiles(pos)) { + Cloister cloister = neighbour.getCloister(); + if (cloister != null) { + scoreCompleted(cloister); + } + } + + if (castleCap != null) { + for (Entry entry : castleCap.getCastleScore().entrySet()) { + scoreCastle(entry.getKey(), entry.getValue()); + } + } + + alredyScored.clear(); + next(); + } + + protected void undeployMeeples(CompletableScoreContext ctx) { + for (Meeple m : ctx.getMeeples()) { + m.undeploy(false); + } + } + + private void scoreCastle(Castle castle, int points) { + List meeples = castle.getMeeples(); + if (meeples.isEmpty()) meeples = castle.getSecondFeature().getMeeples(); + Meeple m = meeples.get(0); //all meeples must share same owner + m.getPlayer().addPoints(points, PointCategory.CASTLE); + game.fireGameEvent().scored(m.getFeature(), points, points+"", m, false); + m.undeploy(false); + } + + private void scoreCompleted(Completable completable) { + CompletableScoreContext ctx = completable.getScoreContext(); + completable.walk(ctx); + if (builderCap != null) { + for (Meeple m : ctx.getSpecialMeeples()) { + if (m instanceof Builder && m.getPlayer().equals(getActivePlayer())) { + if (!m.at(getTile().getPosition())) { + builderCap.useBuilder(); + } + break; + } + } + } + if (ctx.isCompleted()) { + Completable master = (Completable) ctx.getMasterFeature(); + if (!alredyScored.contains(master)) { + alredyScored.add(master); + game.scoreCompleted(ctx); + game.scoreCompletableFeature(ctx); + undeployMeeples(ctx); + game.fireGameEvent().completed(master, ctx); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/ServerAwarePhase.java b/src/main/java/com/jcloisterzone/game/phase/ServerAwarePhase.java index 3b608e875..7df5fb3ef 100644 --- a/src/main/java/com/jcloisterzone/game/phase/ServerAwarePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/ServerAwarePhase.java @@ -1,32 +1,32 @@ -package com.jcloisterzone.game.phase; - -import java.lang.reflect.Proxy; - -import com.jcloisterzone.Player; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.rmi.ServerIF; -import com.jcloisterzone.rmi.mina.ClientStub; - -public class ServerAwarePhase extends Phase { - - private final ServerIF server; - - public ServerAwarePhase(Game game, ServerIF server) { - super(game); - this.server = server; - } - - public ServerIF getServer() { - return server; - } - - public boolean isLocalPlayer(Player player) { - return ((ClientStub)Proxy.getInvocationHandler(server)).isLocalPlayer(player); - } - - public boolean isLocalSlot(PlayerSlot slot) { - return ((ClientStub)Proxy.getInvocationHandler(server)).isLocalSlot(slot); - } - -} +package com.jcloisterzone.game.phase; + +import java.lang.reflect.Proxy; + +import com.jcloisterzone.Player; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.rmi.ServerIF; +import com.jcloisterzone.rmi.mina.ClientStub; + +public class ServerAwarePhase extends Phase { + + private final ServerIF server; + + public ServerAwarePhase(Game game, ServerIF server) { + super(game); + this.server = server; + } + + public ServerIF getServer() { + return server; + } + + public boolean isLocalPlayer(Player player) { + return ((ClientStub)Proxy.getInvocationHandler(server)).isLocalPlayer(player); + } + + public boolean isLocalSlot(PlayerSlot slot) { + return ((ClientStub)Proxy.getInvocationHandler(server)).isLocalSlot(slot); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/TilePhase.java b/src/main/java/com/jcloisterzone/game/phase/TilePhase.java index 277071393..cf881b51c 100644 --- a/src/main/java/com/jcloisterzone/game/phase/TilePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/TilePhase.java @@ -1,69 +1,69 @@ -package com.jcloisterzone.game.phase; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.action.TilePlacementAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BridgeCapability; -import com.jcloisterzone.game.capability.TowerCapability; - -public class TilePhase extends Phase { - - private final BridgeCapability bridgeCap; - - public TilePhase(Game game) { - super(game); - bridgeCap = game.getCapability(BridgeCapability.class); - } - - @Override - public void enter() { - Map> freezed = new HashMap<>(getBoard().getAvailablePlacements()); - notifyUI(new TilePlacementAction(game.getCurrentTile(), freezed), false); - } - - @Override - public void loadGame(Snapshot snapshot) { - String tileId = snapshot.getNextTile(); - Tile tile = game.getTilePack().drawTile(tileId); - game.setCurrentTile(tile); - game.getBoard().refreshAvailablePlacements(tile); - game.fireGameEvent().tileDrawn(tile); - } - - @Override - public void placeTile(Rotation rotation, Position p) { - Tile tile = getTile(); - tile.setRotation(rotation); - - boolean bridgeRequired = bridgeCap != null && !getBoard().isPlacementAllowed(tile, p); - - getBoard().add(tile, p); - if (tile.getTower() != null) { - game.getCapability(TowerCapability.class).registerTower(p); - } - game.fireGameEvent().tilePlaced(tile); - - if (bridgeRequired) { - LocationsMap sites = bridgeCap.prepareMandatoryBridgeAction().getLocationsMap(); - - assert sites.size() == 1; - Position pos = sites.keySet().iterator().next(); - Location loc = sites.get(pos).iterator().next(); - - bridgeCap.decreaseBridges(getActivePlayer()); - bridgeCap.deployBridge(pos, loc); - } - getBoard().mergeFeatures(tile); - - next(); - } +package com.jcloisterzone.game.phase; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.action.TilePlacementAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BridgeCapability; +import com.jcloisterzone.game.capability.TowerCapability; + +public class TilePhase extends Phase { + + private final BridgeCapability bridgeCap; + + public TilePhase(Game game) { + super(game); + bridgeCap = game.getCapability(BridgeCapability.class); + } + + @Override + public void enter() { + Map> freezed = new HashMap<>(getBoard().getAvailablePlacements()); + notifyUI(new TilePlacementAction(game.getCurrentTile(), freezed), false); + } + + @Override + public void loadGame(Snapshot snapshot) { + String tileId = snapshot.getNextTile(); + Tile tile = game.getTilePack().drawTile(tileId); + game.setCurrentTile(tile); + game.getBoard().refreshAvailablePlacements(tile); + game.fireGameEvent().tileDrawn(tile); + } + + @Override + public void placeTile(Rotation rotation, Position p) { + Tile tile = getTile(); + tile.setRotation(rotation); + + boolean bridgeRequired = bridgeCap != null && !getBoard().isPlacementAllowed(tile, p); + + getBoard().add(tile, p); + if (tile.getTower() != null) { + game.getCapability(TowerCapability.class).registerTower(p); + } + game.fireGameEvent().tilePlaced(tile); + + if (bridgeRequired) { + LocationsMap sites = bridgeCap.prepareMandatoryBridgeAction().getLocationsMap(); + + assert sites.size() == 1; + Position pos = sites.keySet().iterator().next(); + Location loc = sites.get(pos).iterator().next(); + + bridgeCap.decreaseBridges(getActivePlayer()); + bridgeCap.deployBridge(pos, loc); + } + getBoard().mergeFeatures(tile); + + next(); + } } diff --git a/src/main/java/com/jcloisterzone/game/phase/TowerCapturePhase.java b/src/main/java/com/jcloisterzone/game/phase/TowerCapturePhase.java index 0de68b0d7..695b6c40d 100644 --- a/src/main/java/com/jcloisterzone/game/phase/TowerCapturePhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/TowerCapturePhase.java @@ -1,62 +1,62 @@ -package com.jcloisterzone.game.phase; - -import java.util.ArrayList; -import java.util.List; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.TowerCapability; - - -public class TowerCapturePhase extends Phase { - - public TowerCapturePhase(Game game) { - super(game); - } - - @Override - public boolean isActive() { - return game.hasCapability(TowerCapability.class); - } - - @Override - public void enter() { - //TODO move handle tower placement here from action phase or not ? - } - - @Override - public void takePrisoner(Position p, Location loc, Class meepleType, Integer meepleOwner) { - Follower m = (Follower) game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); - m.undeploy(); - //unplace figure returns figure to owner -> we must handle capture / prisoner exchange - Player me = getActivePlayer(); - if (m.getPlayer() != me) { - TowerCapability towerCap = game.getCapability(TowerCapability.class); - List prisoners = towerCap.getPrisoners().get(m.getPlayer()); - List myCapturedFollowers = new ArrayList<>(); - for (Follower f : prisoners) { - if (f.getPlayer() == me) { - myCapturedFollowers.add(f); - } - } - - if (myCapturedFollowers.isEmpty()) { - towerCap.inprison(m, me); - } else { - //opponent has my prisoner - figure exchage - Follower exchanged = myCapturedFollowers.get(0); //TODO same type? - boolean removeOk = prisoners.remove(exchanged); - assert removeOk; - game.fireGameEvent().undeployed(exchanged); - exchanged.clearDeployment(); - //? some events ? - } - } - next(); - } - -} +package com.jcloisterzone.game.phase; + +import java.util.ArrayList; +import java.util.List; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.TowerCapability; + + +public class TowerCapturePhase extends Phase { + + public TowerCapturePhase(Game game) { + super(game); + } + + @Override + public boolean isActive() { + return game.hasCapability(TowerCapability.class); + } + + @Override + public void enter() { + //TODO move handle tower placement here from action phase or not ? + } + + @Override + public void takePrisoner(Position p, Location loc, Class meepleType, Integer meepleOwner) { + Follower m = (Follower) game.getMeeple(p, loc, meepleType, game.getPlayer(meepleOwner)); + m.undeploy(); + //unplace figure returns figure to owner -> we must handle capture / prisoner exchange + Player me = getActivePlayer(); + if (m.getPlayer() != me) { + TowerCapability towerCap = game.getCapability(TowerCapability.class); + List prisoners = towerCap.getPrisoners().get(m.getPlayer()); + List myCapturedFollowers = new ArrayList<>(); + for (Follower f : prisoners) { + if (f.getPlayer() == me) { + myCapturedFollowers.add(f); + } + } + + if (myCapturedFollowers.isEmpty()) { + towerCap.inprison(m, me); + } else { + //opponent has my prisoner - figure exchage + Follower exchanged = myCapturedFollowers.get(0); //TODO same type? + boolean removeOk = prisoners.remove(exchanged); + assert removeOk; + game.fireGameEvent().undeployed(exchanged); + exchanged.clearDeployment(); + //? some events ? + } + } + next(); + } + +} diff --git a/src/main/java/com/jcloisterzone/game/phase/WagonPhase.java b/src/main/java/com/jcloisterzone/game/phase/WagonPhase.java index cbaf6d506..78730103b 100644 --- a/src/main/java/com/jcloisterzone/game/phase/WagonPhase.java +++ b/src/main/java/com/jcloisterzone/game/phase/WagonPhase.java @@ -1,107 +1,107 @@ -package com.jcloisterzone.game.phase; - -import java.util.Map; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.collection.LocationsMap; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.FeatureVisitor; -import com.jcloisterzone.feature.visitor.IsOccupiedOrCompleted; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.Wagon; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.WagonCapability; - - -public class WagonPhase extends Phase { - - final WagonCapability wagonCap; - - - public WagonPhase(Game game) { - super(game); - wagonCap = game.getCapability(WagonCapability.class); - } - - - @Override - public boolean isActive() { - return game.hasCapability(WagonCapability.class); - } - - @Override - public void enter() { - if (!existsLegalMove()) next(); - } - - @Override - public void pass() { - enter(); - } - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - if (!meepleType.equals(Wagon.class)) { - logger.error("Illegal figure type."); - return; - } - Meeple m = getActivePlayer().getMeepleFromSupply(Wagon.class); - m.deploy(getBoard().get(p), loc); - enter(); - } - - @Override - public Player getActivePlayer() { - Player p = wagonCap.getWagonPlayer(); - return p == null ? game.getTurnPlayer() : p; - } - - private boolean existsLegalMove() { - Map rw = wagonCap.getReturnedWagons(); - while (!rw.isEmpty()) { - int pi = game.getTurnPlayer().getIndex(); - while(! rw.containsKey(game.getAllPlayers()[pi])) { - pi++; - if (pi == game.getAllPlayers().length) pi = 0; - } - Player player = game.getAllPlayers()[pi]; - Feature f = rw.remove(player); - LocationsMap wagonMoves = prepareWagonMoves(f); - if (!wagonMoves.isEmpty()) { - wagonCap.setWagonPlayer(player); - game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); - notifyUI(new MeepleAction(Wagon.class, wagonMoves), true); - return true; - } - } - return false; - } - - private LocationsMap prepareWagonMoves(Feature source) { - return source.walk(new FindUnoccupiedNeighbours()); - } - - private class FindUnoccupiedNeighbours implements FeatureVisitor { - - private LocationsMap wagonMoves = new LocationsMap(); - - @Override - public boolean visit(Feature feature) { - if (feature.getNeighbouring() != null) { - for (Feature nei : feature.getNeighbouring()) { - if (nei.walk(new IsOccupiedOrCompleted())) continue; - wagonMoves.getOrCreate(feature.getTile().getPosition()).add(nei.getLocation()); - } - } - return true; - } - - public LocationsMap getResult() { - return wagonMoves; - } - } - -} +package com.jcloisterzone.game.phase; + +import java.util.Map; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.collection.LocationsMap; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.FeatureVisitor; +import com.jcloisterzone.feature.visitor.IsOccupiedOrCompleted; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.Wagon; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.WagonCapability; + + +public class WagonPhase extends Phase { + + final WagonCapability wagonCap; + + + public WagonPhase(Game game) { + super(game); + wagonCap = game.getCapability(WagonCapability.class); + } + + + @Override + public boolean isActive() { + return game.hasCapability(WagonCapability.class); + } + + @Override + public void enter() { + if (!existsLegalMove()) next(); + } + + @Override + public void pass() { + enter(); + } + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + if (!meepleType.equals(Wagon.class)) { + logger.error("Illegal figure type."); + return; + } + Meeple m = getActivePlayer().getMeepleFromSupply(Wagon.class); + m.deploy(getBoard().get(p), loc); + enter(); + } + + @Override + public Player getActivePlayer() { + Player p = wagonCap.getWagonPlayer(); + return p == null ? game.getTurnPlayer() : p; + } + + private boolean existsLegalMove() { + Map rw = wagonCap.getReturnedWagons(); + while (!rw.isEmpty()) { + int pi = game.getTurnPlayer().getIndex(); + while(! rw.containsKey(game.getAllPlayers()[pi])) { + pi++; + if (pi == game.getAllPlayers().length) pi = 0; + } + Player player = game.getAllPlayers()[pi]; + Feature f = rw.remove(player); + LocationsMap wagonMoves = prepareWagonMoves(f); + if (!wagonMoves.isEmpty()) { + wagonCap.setWagonPlayer(player); + game.fireGameEvent().playerActivated(game.getTurnPlayer(), getActivePlayer()); + notifyUI(new MeepleAction(Wagon.class, wagonMoves), true); + return true; + } + } + return false; + } + + private LocationsMap prepareWagonMoves(Feature source) { + return source.walk(new FindUnoccupiedNeighbours()); + } + + private class FindUnoccupiedNeighbours implements FeatureVisitor { + + private LocationsMap wagonMoves = new LocationsMap(); + + @Override + public boolean visit(Feature feature) { + if (feature.getNeighbouring() != null) { + for (Feature nei : feature.getNeighbouring()) { + if (nei.walk(new IsOccupiedOrCompleted())) continue; + wagonMoves.getOrCreate(feature.getTile().getPosition()).add(nei.getLocation()); + } + } + return true; + } + + public LocationsMap getResult() { + return wagonMoves; + } + } + +} diff --git a/src/main/java/com/jcloisterzone/rmi/CallMessage.java b/src/main/java/com/jcloisterzone/rmi/CallMessage.java index a7e915471..935d975ed 100644 --- a/src/main/java/com/jcloisterzone/rmi/CallMessage.java +++ b/src/main/java/com/jcloisterzone/rmi/CallMessage.java @@ -1,67 +1,67 @@ -package com.jcloisterzone.rmi; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class CallMessage implements Serializable { - - private static final long serialVersionUID = 15L; - - protected String method; - protected Object[] args; - - public CallMessage(Method method, Object[] args) { - this(method.getName(), args); - } - - public CallMessage(String method, Object[] args) { - this.method = method; - this.args = args; - } - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public Object[] getArgs() { - return args; - } - - public void setArgs(Object[] args) { - this.args = args; - } - - - private void writeObject(ObjectOutputStream s) throws IOException { - s.writeObject(method); - s.writeObject(args); - } - - private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - method = (String) s.readObject(); - args = (Object[]) s.readObject(); - } - - @Override - public String toString() { - return "CallMessage(" + method + ")"; - } - - public void call(Object target, Class targetIF) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { - Method[] methods = targetIF.getMethods(); - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(method)) { - methods[i].invoke(target, args); - return; - } - } - } -} +package com.jcloisterzone.rmi; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class CallMessage implements Serializable { + + private static final long serialVersionUID = 15L; + + protected String method; + protected Object[] args; + + public CallMessage(Method method, Object[] args) { + this(method.getName(), args); + } + + public CallMessage(String method, Object[] args) { + this.method = method; + this.args = args; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public Object[] getArgs() { + return args; + } + + public void setArgs(Object[] args) { + this.args = args; + } + + + private void writeObject(ObjectOutputStream s) throws IOException { + s.writeObject(method); + s.writeObject(args); + } + + private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { + method = (String) s.readObject(); + args = (Object[]) s.readObject(); + } + + @Override + public String toString() { + return "CallMessage(" + method + ")"; + } + + public void call(Object target, Class targetIF) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException { + Method[] methods = targetIF.getMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(method)) { + methods[i].invoke(target, args); + return; + } + } + } +} diff --git a/src/main/java/com/jcloisterzone/rmi/Client2ClientIF.java b/src/main/java/com/jcloisterzone/rmi/Client2ClientIF.java index 725848d18..822c3bb49 100644 --- a/src/main/java/com/jcloisterzone/rmi/Client2ClientIF.java +++ b/src/main/java/com/jcloisterzone/rmi/Client2ClientIF.java @@ -1,48 +1,48 @@ -package com.jcloisterzone.rmi; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; - -/** - * Declares broadcast messages called between clients. - * Technically all messges are passed through server but messages - * from this class has origin on the client side. - * - */ -public interface Client2ClientIF { - - /* ---------------------- NEW GAME MESSAGES ------------------*/ - - public void updateExpansion(Expansion expansion, Boolean enabled); - public void updateCustomRule(CustomRule rule, Boolean enabled); - public void startGame(); - - /* ---------------------- STARTED GAME MESSAGES ------------------*/ - - public void pass(); - public void placeTile(Rotation rotation, Position position); - - public void deployMeeple(Position pos, Location loc, Class meepleType); - public void undeployMeeple(Position pos, Location loc, Class meepleType, Integer meepleOwner); - public void placeTowerPiece(Position pos); - public void takePrisoner(Position pos, Location loc, Class meepleType, Integer meepleOwner); - public void placeTunnelPiece(Position pos, Location loc, boolean isSecondPiece); - - public void moveFairy(Position pos); - public void moveDragon(Position pos); - - public void payRansom(Integer playerIndexToPay, Class meepleType); - - public void deployBridge(Position pos, Location loc); - public void deployCastle(Position pos, Location loc); - - public void bazaarBid(Integer supplyIndex, Integer price); - public void bazaarBuyOrSell(boolean buy); - - public void cornCiclesRemoveOrDeploy(boolean remove); -} +package com.jcloisterzone.rmi; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; + +/** + * Declares broadcast messages called between clients. + * Technically all messges are passed through server but messages + * from this class has origin on the client side. + * + */ +public interface Client2ClientIF { + + /* ---------------------- NEW GAME MESSAGES ------------------*/ + + public void updateExpansion(Expansion expansion, Boolean enabled); + public void updateCustomRule(CustomRule rule, Boolean enabled); + public void startGame(); + + /* ---------------------- STARTED GAME MESSAGES ------------------*/ + + public void pass(); + public void placeTile(Rotation rotation, Position position); + + public void deployMeeple(Position pos, Location loc, Class meepleType); + public void undeployMeeple(Position pos, Location loc, Class meepleType, Integer meepleOwner); + public void placeTowerPiece(Position pos); + public void takePrisoner(Position pos, Location loc, Class meepleType, Integer meepleOwner); + public void placeTunnelPiece(Position pos, Location loc, boolean isSecondPiece); + + public void moveFairy(Position pos); + public void moveDragon(Position pos); + + public void payRansom(Integer playerIndexToPay, Class meepleType); + + public void deployBridge(Position pos, Location loc); + public void deployCastle(Position pos, Location loc); + + public void bazaarBid(Integer supplyIndex, Integer price); + public void bazaarBuyOrSell(boolean buy); + + public void cornCiclesRemoveOrDeploy(boolean remove); +} diff --git a/src/main/java/com/jcloisterzone/rmi/ClientControllMessage.java b/src/main/java/com/jcloisterzone/rmi/ClientControllMessage.java index 22e9fcb85..5cb88344f 100644 --- a/src/main/java/com/jcloisterzone/rmi/ClientControllMessage.java +++ b/src/main/java/com/jcloisterzone/rmi/ClientControllMessage.java @@ -1,17 +1,17 @@ -package com.jcloisterzone.rmi; - -import java.io.Serializable; - -//temporaty mesage, before protocol will be revisited, allows reconnection -public class ClientControllMessage implements Serializable { - - private final Long clientId; - - public ClientControllMessage(Long clientId) { - this.clientId = clientId; - } - - public Long getClientId() { - return clientId; - } -} +package com.jcloisterzone.rmi; + +import java.io.Serializable; + +//temporaty mesage, before protocol will be revisited, allows reconnection +public class ClientControllMessage implements Serializable { + + private final Long clientId; + + public ClientControllMessage(Long clientId) { + this.clientId = clientId; + } + + public Long getClientId() { + return clientId; + } +} diff --git a/src/main/java/com/jcloisterzone/rmi/ClientIF.java b/src/main/java/com/jcloisterzone/rmi/ClientIF.java index 65362386c..95efcb3d8 100644 --- a/src/main/java/com/jcloisterzone/rmi/ClientIF.java +++ b/src/main/java/com/jcloisterzone/rmi/ClientIF.java @@ -1,23 +1,23 @@ -package com.jcloisterzone.rmi; - -import java.util.EnumSet; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.game.PlayerSlot; - -/** - * Declares complete client API. - * In addition to Client2ClientIF this class ass messages which has orginin on server side. - * - */ -public interface ClientIF extends Client2ClientIF { - - public void updateSlot(PlayerSlot slot); - public void updateSupportedExpansions(EnumSet expansions); - - /* ---------------------- STARTED GAME MESSAGES (server triggered) ------------------*/ - - void drawTiles(int[] tileIndexes); - void setFlierDistance(int distance); - -} +package com.jcloisterzone.rmi; + +import java.util.EnumSet; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.game.PlayerSlot; + +/** + * Declares complete client API. + * In addition to Client2ClientIF this class ass messages which has orginin on server side. + * + */ +public interface ClientIF extends Client2ClientIF { + + public void updateSlot(PlayerSlot slot); + public void updateSupportedExpansions(EnumSet expansions); + + /* ---------------------- STARTED GAME MESSAGES (server triggered) ------------------*/ + + void drawTiles(int[] tileIndexes); + void setFlierDistance(int distance); + +} diff --git a/src/main/java/com/jcloisterzone/rmi/ControllMessage.java b/src/main/java/com/jcloisterzone/rmi/ControllMessage.java index 02771d429..950824347 100644 --- a/src/main/java/com/jcloisterzone/rmi/ControllMessage.java +++ b/src/main/java/com/jcloisterzone/rmi/ControllMessage.java @@ -1,41 +1,41 @@ -package com.jcloisterzone.rmi; - -import java.io.Serializable; - -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; - - -public class ControllMessage implements Serializable { - - private static final long serialVersionUID = 840173772004529053L; - - private long clientId; - private int protocolVersion; - private Snapshot snapshot; - private PlayerSlot[] slots; - - public ControllMessage(long clientId, int protocolVersion, Snapshot snapshot, PlayerSlot[] slots) { - this.clientId = clientId; - this.protocolVersion = protocolVersion; - this.snapshot = snapshot; - this.slots = slots; - } - - public long getClientId() { - return clientId; - } - - public int getProtocolVersion() { - return protocolVersion; - } - - public Snapshot getSnapshot() { - return snapshot; - } - - public PlayerSlot[] getSlots() { - return slots; - } - -} +package com.jcloisterzone.rmi; + +import java.io.Serializable; + +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; + + +public class ControllMessage implements Serializable { + + private static final long serialVersionUID = 840173772004529053L; + + private long clientId; + private int protocolVersion; + private Snapshot snapshot; + private PlayerSlot[] slots; + + public ControllMessage(long clientId, int protocolVersion, Snapshot snapshot, PlayerSlot[] slots) { + this.clientId = clientId; + this.protocolVersion = protocolVersion; + this.snapshot = snapshot; + this.slots = slots; + } + + public long getClientId() { + return clientId; + } + + public int getProtocolVersion() { + return protocolVersion; + } + + public Snapshot getSnapshot() { + return snapshot; + } + + public PlayerSlot[] getSlots() { + return slots; + } + +} diff --git a/src/main/java/com/jcloisterzone/rmi/ServerIF.java b/src/main/java/com/jcloisterzone/rmi/ServerIF.java index e24f00a23..0fa157f30 100644 --- a/src/main/java/com/jcloisterzone/rmi/ServerIF.java +++ b/src/main/java/com/jcloisterzone/rmi/ServerIF.java @@ -1,24 +1,24 @@ -package com.jcloisterzone.rmi; - -import java.util.EnumSet; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.game.PlayerSlot; - -/** - * Declares complete server API. In addition to Client2ClientIF messages, which are just passed - * to all other connecte clients, messages described on this class represent some server side logic. - */ -public interface ServerIF extends Client2ClientIF { - - public void updateSlot(PlayerSlot slot, EnumSet supportedExpansions); //pass null if all expansions are supported - - /* ---------------------- STARTED GAME MESSAGES ------------------*/ - - /** - * Generates random tiles indexes. For security reasons all random selections are made on server side. - */ - public void selectTiles(int tilesCount, int drawCount); //generate random numbers - public void rollFlierDice(); - -} +package com.jcloisterzone.rmi; + +import java.util.EnumSet; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.game.PlayerSlot; + +/** + * Declares complete server API. In addition to Client2ClientIF messages, which are just passed + * to all other connecte clients, messages described on this class represent some server side logic. + */ +public interface ServerIF extends Client2ClientIF { + + public void updateSlot(PlayerSlot slot, EnumSet supportedExpansions); //pass null if all expansions are supported + + /* ---------------------- STARTED GAME MESSAGES ------------------*/ + + /** + * Generates random tiles indexes. For security reasons all random selections are made on server side. + */ + public void selectTiles(int tilesCount, int drawCount); //generate random numbers + public void rollFlierDice(); + +} diff --git a/src/main/java/com/jcloisterzone/rmi/mina/ClientStub.java b/src/main/java/com/jcloisterzone/rmi/mina/ClientStub.java index 2b3a03fc8..95286996c 100644 --- a/src/main/java/com/jcloisterzone/rmi/mina/ClientStub.java +++ b/src/main/java/com/jcloisterzone/rmi/mina/ClientStub.java @@ -1,204 +1,204 @@ -package com.jcloisterzone.rmi.mina; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -import org.apache.mina.core.future.ConnectFuture; -import org.apache.mina.core.service.IoHandlerAdapter; -import org.apache.mina.core.session.IoSession; -import org.apache.mina.filter.codec.ProtocolCodecFilter; -import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; -import org.apache.mina.filter.logging.LogLevel; -import org.apache.mina.filter.logging.LoggingFilter; -import org.apache.mina.transport.socket.nio.NioSocketConnector; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Objects; -import com.jcloisterzone.Application; -import com.jcloisterzone.Player; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.phase.CreateGamePhase; -import com.jcloisterzone.game.phase.LoadGamePhase; -import com.jcloisterzone.game.phase.Phase; -import com.jcloisterzone.rmi.CallMessage; -import com.jcloisterzone.rmi.ClientControllMessage; -import com.jcloisterzone.rmi.ClientIF; -import com.jcloisterzone.rmi.ControllMessage; -import com.jcloisterzone.rmi.ServerIF; - - -public abstract class ClientStub extends IoHandlerAdapter implements InvocationHandler { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private IoSession session; - private long clientId = -1; //remote session id - - private ServerIF serverProxy; - - protected Game game; - - - public void connect(InetAddress ia, int port) { - InetSocketAddress endpoint = new InetSocketAddress(ia, port); - connect(endpoint); - session.write(new ClientControllMessage(null)); - } - - private void connect(SocketAddress endpoint) { - NioSocketConnector connector = new NioSocketConnector(); - connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); - if (logger.isDebugEnabled()) { - LoggingFilter logFilter = new LoggingFilter(); - logFilter.setMessageSentLogLevel(LogLevel.DEBUG); - logFilter.setMessageReceivedLogLevel(LogLevel.DEBUG); - connector.getFilterChain().addLast("logger", logFilter); - } - connector.setHandler(this); - - ConnectFuture future = connector.connect(endpoint); - future.awaitUninterruptibly(); - if (future.isConnected()) { - session = future.getSession(); - } - } - - - public ServerIF getServerProxy() { - return serverProxy; - } - - public void setServerProxy(ServerIF serverProxy) { - this.serverProxy = serverProxy; - } - - public Game getGame() { - return game; - } - - //TODO revise; close from client side ??? - public void stop() { - session.close(false); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - if (session == null) { - logger.info("Not connected. Message ignored"); - } else { - session.write(new CallMessage(method, args)); - } - return null; - } - - @Override - public final void messageReceived(IoSession session, Object message) { - if (message instanceof ControllMessage) { - ControllMessage cm = (ControllMessage) message; - clientId = cm.getClientId(); - if (cm.getProtocolVersion() != Application.PROTCOL_VERSION) { - versionMismatch(cm.getProtocolVersion()); - session.close(true); - return; - } - controllMessageReceived(cm); - } else { - callMessageReceived((CallMessage) message); - } - } - - protected void versionMismatch(int version) { - logger.error("Version mismatch. Server version: " + version +". Client version " + Application.PROTCOL_VERSION); - } - - protected Game createGame(ControllMessage msg) { - if (msg.getSnapshot() == null) { - game = new Game(); - } else { - game = msg.getSnapshot().asGame(); - } - return game; - } - - protected void controllMessageReceived(ControllMessage msg) { - game = createGame(msg); - CreateGamePhase phase; - if (msg.getSnapshot() == null) { - phase = new CreateGamePhase(game, getServerProxy()); - } else { - phase = new LoadGamePhase(game, msg.getSnapshot(), getServerProxy()); - } - phase.setSlots(msg.getSlots()); - game.getPhases().put(phase.getClass(), phase); - game.setPhase(phase); - } - - protected void callMessageReceived(CallMessage msg) { - try { - Phase phase = game.getPhase(); - logger.debug("Delegating {} on phase {}", msg.getMethod(), phase.getClass().getSimpleName()); - msg.call(phase, ClientIF.class); - phase = game.getPhase(); //new phase can differ from the phase in prev msg.call !!! - while (phase != null && !phase.isEntered()) { - logger.debug("Entering phase {}", phase.getClass().getSimpleName()); - phase.setEntered(true); - phase.enter(); - phase = game.getPhase(); - game.fireGameEvent().phaseEntered(phase); - } - } catch (InvocationTargetException ie) { - logger.error(ie.getMessage(), ie.getCause()); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - } - - - public long getClientId() { - if (clientId == -1) throw new IllegalStateException("Client id hasn't been assigned yet"); - return clientId; - } - - public boolean isLocalPlayer(Player player) { - if (player == null) return false; - return Objects.equal(clientId, player.getOwnerId()); - } - - public boolean isLocalSlot(PlayerSlot slot) { - if (slot == null) return false; - return Objects.equal(clientId, slot.getOwner()); - } - - @Override - public void exceptionCaught(IoSession brokenSession, Throwable cause) { - SocketAddress endpoint = brokenSession.getServiceAddress(); - session = null; - int delay = 500; - logger.warn("Connection lost. Reconnecting to " + endpoint + " ..."); - onDisconnect(); - while (session == null) { - - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - } - connect(endpoint); - if (delay < 4000) delay *= 2; - } - onReconnect(); - session.write(new ClientControllMessage(clientId)); - } - - protected void onDisconnect() { - } - - protected void onReconnect() { - } - -} +package com.jcloisterzone.rmi.mina; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import org.apache.mina.core.future.ConnectFuture; +import org.apache.mina.core.service.IoHandlerAdapter; +import org.apache.mina.core.session.IoSession; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; +import org.apache.mina.filter.logging.LogLevel; +import org.apache.mina.filter.logging.LoggingFilter; +import org.apache.mina.transport.socket.nio.NioSocketConnector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Objects; +import com.jcloisterzone.Application; +import com.jcloisterzone.Player; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.phase.CreateGamePhase; +import com.jcloisterzone.game.phase.LoadGamePhase; +import com.jcloisterzone.game.phase.Phase; +import com.jcloisterzone.rmi.CallMessage; +import com.jcloisterzone.rmi.ClientControllMessage; +import com.jcloisterzone.rmi.ClientIF; +import com.jcloisterzone.rmi.ControllMessage; +import com.jcloisterzone.rmi.ServerIF; + + +public abstract class ClientStub extends IoHandlerAdapter implements InvocationHandler { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private IoSession session; + private long clientId = -1; //remote session id + + private ServerIF serverProxy; + + protected Game game; + + + public void connect(InetAddress ia, int port) { + InetSocketAddress endpoint = new InetSocketAddress(ia, port); + connect(endpoint); + session.write(new ClientControllMessage(null)); + } + + private void connect(SocketAddress endpoint) { + NioSocketConnector connector = new NioSocketConnector(); + connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); + if (logger.isDebugEnabled()) { + LoggingFilter logFilter = new LoggingFilter(); + logFilter.setMessageSentLogLevel(LogLevel.DEBUG); + logFilter.setMessageReceivedLogLevel(LogLevel.DEBUG); + connector.getFilterChain().addLast("logger", logFilter); + } + connector.setHandler(this); + + ConnectFuture future = connector.connect(endpoint); + future.awaitUninterruptibly(); + if (future.isConnected()) { + session = future.getSession(); + } + } + + + public ServerIF getServerProxy() { + return serverProxy; + } + + public void setServerProxy(ServerIF serverProxy) { + this.serverProxy = serverProxy; + } + + public Game getGame() { + return game; + } + + //TODO revise; close from client side ??? + public void stop() { + session.close(false); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (session == null) { + logger.info("Not connected. Message ignored"); + } else { + session.write(new CallMessage(method, args)); + } + return null; + } + + @Override + public final void messageReceived(IoSession session, Object message) { + if (message instanceof ControllMessage) { + ControllMessage cm = (ControllMessage) message; + clientId = cm.getClientId(); + if (cm.getProtocolVersion() != Application.PROTCOL_VERSION) { + versionMismatch(cm.getProtocolVersion()); + session.close(true); + return; + } + controllMessageReceived(cm); + } else { + callMessageReceived((CallMessage) message); + } + } + + protected void versionMismatch(int version) { + logger.error("Version mismatch. Server version: " + version +". Client version " + Application.PROTCOL_VERSION); + } + + protected Game createGame(ControllMessage msg) { + if (msg.getSnapshot() == null) { + game = new Game(); + } else { + game = msg.getSnapshot().asGame(); + } + return game; + } + + protected void controllMessageReceived(ControllMessage msg) { + game = createGame(msg); + CreateGamePhase phase; + if (msg.getSnapshot() == null) { + phase = new CreateGamePhase(game, getServerProxy()); + } else { + phase = new LoadGamePhase(game, msg.getSnapshot(), getServerProxy()); + } + phase.setSlots(msg.getSlots()); + game.getPhases().put(phase.getClass(), phase); + game.setPhase(phase); + } + + protected void callMessageReceived(CallMessage msg) { + try { + Phase phase = game.getPhase(); + logger.debug("Delegating {} on phase {}", msg.getMethod(), phase.getClass().getSimpleName()); + msg.call(phase, ClientIF.class); + phase = game.getPhase(); //new phase can differ from the phase in prev msg.call !!! + while (phase != null && !phase.isEntered()) { + logger.debug("Entering phase {}", phase.getClass().getSimpleName()); + phase.setEntered(true); + phase.enter(); + phase = game.getPhase(); + game.fireGameEvent().phaseEntered(phase); + } + } catch (InvocationTargetException ie) { + logger.error(ie.getMessage(), ie.getCause()); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + + + public long getClientId() { + if (clientId == -1) throw new IllegalStateException("Client id hasn't been assigned yet"); + return clientId; + } + + public boolean isLocalPlayer(Player player) { + if (player == null) return false; + return Objects.equal(clientId, player.getOwnerId()); + } + + public boolean isLocalSlot(PlayerSlot slot) { + if (slot == null) return false; + return Objects.equal(clientId, slot.getOwner()); + } + + @Override + public void exceptionCaught(IoSession brokenSession, Throwable cause) { + SocketAddress endpoint = brokenSession.getServiceAddress(); + session = null; + int delay = 500; + logger.warn("Connection lost. Reconnecting to " + endpoint + " ..."); + onDisconnect(); + while (session == null) { + + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + } + connect(endpoint); + if (delay < 4000) delay *= 2; + } + onReconnect(); + session.write(new ClientControllMessage(clientId)); + } + + protected void onDisconnect() { + } + + protected void onReconnect() { + } + +} diff --git a/src/main/java/com/jcloisterzone/rmi/mina/ServerStub.java b/src/main/java/com/jcloisterzone/rmi/mina/ServerStub.java index a9ac622ab..d8e3ff629 100644 --- a/src/main/java/com/jcloisterzone/rmi/mina/ServerStub.java +++ b/src/main/java/com/jcloisterzone/rmi/mina/ServerStub.java @@ -1,129 +1,129 @@ -package com.jcloisterzone.rmi.mina; - -import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.mina.core.service.IoHandlerAdapter; -import org.apache.mina.core.session.IoSession; -import org.apache.mina.filter.codec.ProtocolCodecFilter; -import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; -import org.apache.mina.transport.socket.nio.NioSocketAcceptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Application; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.rmi.CallMessage; -import com.jcloisterzone.rmi.ClientControllMessage; -import com.jcloisterzone.rmi.ControllMessage; -import com.jcloisterzone.rmi.ServerIF; -import com.jcloisterzone.server.Server; - - -public class ServerStub extends IoHandlerAdapter implements InvocationHandler { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private Server server; - private NioSocketAcceptor acceptor; - private boolean engageSlots = true; - private boolean acceptingNew = true; - - private Map> undelivered = new HashMap<>(); - - public ServerStub(Server server, int port) throws IOException { - this.server = server; - bind(new InetSocketAddress(port)); - } - - private void bind(SocketAddress address) throws IOException { - acceptor = new NioSocketAcceptor(); - acceptor.setReuseAddress(true); - //acceptor.getFilterChain().addLast("logger", new LoggingFilter() ); - acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); - //acceptor.getSessionConfig().setReadBufferSize( 2048 ); - //acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 ); - acceptor.setHandler(this); - acceptor.setCloseOnDeactivation(false); - acceptor.bind(address); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - CallMessage msg = new CallMessage(method, args); - acceptor.broadcast(msg); - for (List queue : undelivered.values()) { - queue.add(msg); - } - return null; - } - - public void stop() { - acceptor.setCloseOnDeactivation(true); - acceptor.unbind(); - acceptor.dispose(); - } - - public void closeAccepting() { - acceptingNew = false; - } - - @Override - public void messageReceived(IoSession session, Object message) throws Exception { - if (message instanceof ClientControllMessage) { - ClientControllMessage msg = (ClientControllMessage) message; - if (msg.getClientId() == null) { - session.setAttribute("clientId", session.getId()); - sessionReceivedControllMessage(session); - } else { - session.setAttribute("clientId", msg.getClientId()); - for (CallMessage callMsg : undelivered.remove(msg.getClientId())) { - session.write(callMsg); - } - } - } else { - //TODO check rights (has token) - ((CallMessage) message).call(server, ServerIF.class); - } - } - - private void sessionReceivedControllMessage(IoSession session) { - if (!acceptingNew) { - session.close(true); - return; - } - - session.write(new ControllMessage(session.getId(), Application.PROTCOL_VERSION, server.getSnapshot(), server.getSlots())); - - for (Expansion exp: server.getExpansions()) { - session.write(new CallMessage("updateExpansion", new Object[] { exp, true })); - } - for (CustomRule rule: server.getCustomRules()) { - session.write(new CallMessage("updateCustomRule", new Object[] { rule, true })); - } - } - - @Override - public void sessionOpened(IoSession session) throws Exception { - if (engageSlots) { - //first connected client is game owner - engage local slots - engageSlots = false; - server.engageSlots(session.getId()); - } - - } - - @Override - public void exceptionCaught(IoSession session, Throwable cause) { - logger.info("Session error " + session.getRemoteAddress()); - undelivered.put((Long)session.getAttribute("clientId"), new ArrayList()); - } -} +package com.jcloisterzone.rmi.mina; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.mina.core.service.IoHandlerAdapter; +import org.apache.mina.core.session.IoSession; +import org.apache.mina.filter.codec.ProtocolCodecFilter; +import org.apache.mina.filter.codec.serialization.ObjectSerializationCodecFactory; +import org.apache.mina.transport.socket.nio.NioSocketAcceptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Application; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.rmi.CallMessage; +import com.jcloisterzone.rmi.ClientControllMessage; +import com.jcloisterzone.rmi.ControllMessage; +import com.jcloisterzone.rmi.ServerIF; +import com.jcloisterzone.server.Server; + + +public class ServerStub extends IoHandlerAdapter implements InvocationHandler { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private Server server; + private NioSocketAcceptor acceptor; + private boolean engageSlots = true; + private boolean acceptingNew = true; + + private Map> undelivered = new HashMap<>(); + + public ServerStub(Server server, int port) throws IOException { + this.server = server; + bind(new InetSocketAddress(port)); + } + + private void bind(SocketAddress address) throws IOException { + acceptor = new NioSocketAcceptor(); + acceptor.setReuseAddress(true); + //acceptor.getFilterChain().addLast("logger", new LoggingFilter() ); + acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); + //acceptor.getSessionConfig().setReadBufferSize( 2048 ); + //acceptor.getSessionConfig().setIdleTime( IdleStatus.BOTH_IDLE, 10 ); + acceptor.setHandler(this); + acceptor.setCloseOnDeactivation(false); + acceptor.bind(address); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + CallMessage msg = new CallMessage(method, args); + acceptor.broadcast(msg); + for (List queue : undelivered.values()) { + queue.add(msg); + } + return null; + } + + public void stop() { + acceptor.setCloseOnDeactivation(true); + acceptor.unbind(); + acceptor.dispose(); + } + + public void closeAccepting() { + acceptingNew = false; + } + + @Override + public void messageReceived(IoSession session, Object message) throws Exception { + if (message instanceof ClientControllMessage) { + ClientControllMessage msg = (ClientControllMessage) message; + if (msg.getClientId() == null) { + session.setAttribute("clientId", session.getId()); + sessionReceivedControllMessage(session); + } else { + session.setAttribute("clientId", msg.getClientId()); + for (CallMessage callMsg : undelivered.remove(msg.getClientId())) { + session.write(callMsg); + } + } + } else { + //TODO check rights (has token) + ((CallMessage) message).call(server, ServerIF.class); + } + } + + private void sessionReceivedControllMessage(IoSession session) { + if (!acceptingNew) { + session.close(true); + return; + } + + session.write(new ControllMessage(session.getId(), Application.PROTCOL_VERSION, server.getSnapshot(), server.getSlots())); + + for (Expansion exp: server.getExpansions()) { + session.write(new CallMessage("updateExpansion", new Object[] { exp, true })); + } + for (CustomRule rule: server.getCustomRules()) { + session.write(new CallMessage("updateCustomRule", new Object[] { rule, true })); + } + } + + @Override + public void sessionOpened(IoSession session) throws Exception { + if (engageSlots) { + //first connected client is game owner - engage local slots + engageSlots = false; + server.engageSlots(session.getId()); + } + + } + + @Override + public void exceptionCaught(IoSession session, Throwable cause) { + logger.info("Session error " + session.getRemoteAddress()); + undelivered.put((Long)session.getAttribute("clientId"), new ArrayList()); + } +} diff --git a/src/main/java/com/jcloisterzone/server/Server.java b/src/main/java/com/jcloisterzone/server/Server.java index 5bf39a970..4cb19cd87 100644 --- a/src/main/java/com/jcloisterzone/server/Server.java +++ b/src/main/java/com/jcloisterzone/server/Server.java @@ -1,285 +1,285 @@ -package com.jcloisterzone.server; - -import java.io.IOException; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.EnumSet; -import java.util.Random; - -import org.ini4j.Ini; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Application; -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.GameSettings; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.rmi.ClientIF; -import com.jcloisterzone.rmi.ServerIF; -import com.jcloisterzone.rmi.mina.ServerStub; - - -public class Server extends GameSettings implements ServerIF { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - //TODO -// /** maximum length of player's nick, longer nicks are trimmed */ -// public static int MAX_NICK_LENGTH = 16; - - //private final Ini config; - - private boolean gameStarted; - - protected final PlayerSlot[] slots; - protected EnumSet[] slotSupportedExpansions; - protected int slotSerial; - private Snapshot snapshot; - - /** server stub for sending and receiving messages */ - private ClientIF stub; - - private Random random = new Random(); - - - @SuppressWarnings("unchecked") - public Server(Ini config) { - slots = new PlayerSlot[PlayerSlot.COUNT]; - slotSupportedExpansions = new EnumSet[slots.length]; - for (int i = 0; i < slots.length; i++) { - slots[i] = new PlayerSlot(i); - } - getExpansions().add(Expansion.BASIC); - for (Expansion exp: Expansion.values()) { - if (exp.isEnabled() && config.get("game-default-expansions", exp.name(), boolean.class)) { - getExpansions().add(exp); - } - } - for (CustomRule rule : CustomRule.values()) { - if (config.get("game-default-rules", rule.name(), boolean.class)) { - getCustomRules().add(rule); - } - } - } - - @SuppressWarnings("unchecked") - public Server(Snapshot snapshot) { - slots = snapshot.getPlayerSlots(); - slotSupportedExpansions = new EnumSet[slots.length]; //not used during load - getExpansions().addAll(snapshot.getExpansions()); - getCustomRules().addAll(snapshot.getCustomRules()); - this.snapshot = snapshot; - } - - public void engageSlots(long clientId) { - for (PlayerSlot slot : slots) { - if (slot != null && slot.getType() != SlotType.OPEN) { - slot.setOwner(clientId); - } - } - } - - public void start(int port) throws IOException { - InvocationHandler handler = new ServerStub(this, port); - stub = (ClientIF) Proxy.newProxyInstance(ClientIF.class.getClassLoader(), new Class[] { ClientIF.class }, handler); - } - - public void stop() { - ((ServerStub)Proxy.getInvocationHandler(stub)).stop(); - } - - public PlayerSlot[] getSlots() { - return slots; - } - - public Snapshot getSnapshot() { - return snapshot; - } - - private EnumSet mergeSupportedExpansions() { - EnumSet merged = null; - for (int i = 0; i < slotSupportedExpansions.length; i++) { - EnumSet supported = slotSupportedExpansions[i]; - if (supported == null) continue; - if (merged == null) { - merged = EnumSet.allOf(Expansion.class); - } - merged.retainAll(supported); - } - return merged; - } - - @Override - public void updateSlot(PlayerSlot slot, EnumSet supportedExpansions) { - if (gameStarted) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateSlot"); - return; - } - if (snapshot == null) { - //TODO check rights, maybe copy only - if (slots[slot.getNumber()].getType() == SlotType.OPEN) { //old type - slot.setSerial(++slotSerial); - } - if (slot.getType() == SlotType.OPEN) { //new type - slot.setNick(null); - slot.setSerial(null); - } - if (slot.getType() != SlotType.AI) { //new type - slot.setAiClassName(null); - } - } - slots[slot.getNumber()] = slot; - slotSupportedExpansions[slot.getNumber()] = supportedExpansions; - stub.updateSlot(slot); - //TODO - stub.updateSupportedExpansions(mergeSupportedExpansions()); - } - - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - if (gameStarted || ! expansion.isEnabled()) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateExpansion"); - return; - } - if (enabled) { - getExpansions().add(expansion); - } else { - getExpansions().remove(expansion); - } - //stub.updateGameSettings(slots, getExpansions(), getCustomRules()); - stub.updateExpansion(expansion, enabled); - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - if (gameStarted) { - logger.error(Application.ILLEGAL_STATE_MSG, "updateCustomRule"); - return; - } - if (enabled) { - getCustomRules().add(rule); - } else { - getCustomRules().remove(rule); - } - //stub.updateGameSettings(slots, getExpansions(), getCustomRules()); - stub.updateCustomRule(rule, enabled); - } - - @Override - public void startGame() { - ((ServerStub)Proxy.getInvocationHandler(stub)).closeAccepting(); - gameStarted = true; - EnumSet supported = mergeSupportedExpansions(); - if (supported != null) { - for (Expansion exp : Expansion.values()) { - if (exp.isEnabled() && ! supported.contains(exp)) { - stub.updateExpansion(exp, false); - } - } - } - stub.startGame(); - } - - @Override - public void pass() { - stub.pass(); - } - - @Override - public void placeTile(Rotation tileRotation, Position tilePosition) { - stub.placeTile(tileRotation, tilePosition); - } - - @Override - public void deployMeeple(Position p, Location loc, Class meepleType) { - stub.deployMeeple(p, loc, meepleType); - - } - - @Override - public void moveDragon(Position p) { - stub.moveDragon(p); - } - - @Override - public void payRansom(Integer playerIndexToPay, Class meepleType) { - stub.payRansom(playerIndexToPay, meepleType); - - } - - @Override - public void selectTiles(int tilesCount, int drawCount) { - assert tilesCount >= drawCount && drawCount > 0; - int[] result = new int[drawCount]; - for (int i = 0; i < drawCount; i++) { - result[i] = random.nextInt(tilesCount--); - } - stub.drawTiles(result); - } - - @Override - public void rollFlierDice() { - stub.setFlierDistance(1+random.nextInt(3)); - } - - @Override - public void moveFairy(Position p) { - stub.moveFairy(p); - } - - @Override - public void placeTowerPiece(Position p) { - stub.placeTowerPiece(p); - } - - @Override - public void placeTunnelPiece(Position p, Location d, boolean isSecondPiece) { - stub.placeTunnelPiece(p, d, isSecondPiece); - } - - @Override - public void takePrisoner(Position p, Location d, Class meepleType, Integer meepleOwner) { - stub.takePrisoner(p, d, meepleType, meepleOwner); - - } - - @Override - public void undeployMeeple(Position p, Location d, Class meepleType, Integer meepleOwner) { - stub.undeployMeeple(p, d, meepleType, meepleOwner); - } - - @Override - public void deployBridge(Position pos, Location loc) { - stub.deployBridge(pos, loc); - } - - @Override - public void deployCastle(Position pos, Location loc) { - stub.deployCastle(pos, loc); - } - - @Override - public void bazaarBid(Integer supplyIndex, Integer price) { - stub.bazaarBid(supplyIndex, price); - } - - @Override - public void bazaarBuyOrSell(boolean buy) { - stub.bazaarBuyOrSell(buy); - } - - @Override - public void cornCiclesRemoveOrDeploy(boolean remove) { - stub.cornCiclesRemoveOrDeploy(remove); - - } - -} +package com.jcloisterzone.server; + +import java.io.IOException; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.EnumSet; +import java.util.Random; + +import org.ini4j.Ini; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Application; +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.GameSettings; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.rmi.ClientIF; +import com.jcloisterzone.rmi.ServerIF; +import com.jcloisterzone.rmi.mina.ServerStub; + + +public class Server extends GameSettings implements ServerIF { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + //TODO +// /** maximum length of player's nick, longer nicks are trimmed */ +// public static int MAX_NICK_LENGTH = 16; + + //private final Ini config; + + private boolean gameStarted; + + protected final PlayerSlot[] slots; + protected EnumSet[] slotSupportedExpansions; + protected int slotSerial; + private Snapshot snapshot; + + /** server stub for sending and receiving messages */ + private ClientIF stub; + + private Random random = new Random(); + + + @SuppressWarnings("unchecked") + public Server(Ini config) { + slots = new PlayerSlot[PlayerSlot.COUNT]; + slotSupportedExpansions = new EnumSet[slots.length]; + for (int i = 0; i < slots.length; i++) { + slots[i] = new PlayerSlot(i); + } + getExpansions().add(Expansion.BASIC); + for (Expansion exp: Expansion.values()) { + if (exp.isEnabled() && config.get("game-default-expansions", exp.name(), boolean.class)) { + getExpansions().add(exp); + } + } + for (CustomRule rule : CustomRule.values()) { + if (config.get("game-default-rules", rule.name(), boolean.class)) { + getCustomRules().add(rule); + } + } + } + + @SuppressWarnings("unchecked") + public Server(Snapshot snapshot) { + slots = snapshot.getPlayerSlots(); + slotSupportedExpansions = new EnumSet[slots.length]; //not used during load + getExpansions().addAll(snapshot.getExpansions()); + getCustomRules().addAll(snapshot.getCustomRules()); + this.snapshot = snapshot; + } + + public void engageSlots(long clientId) { + for (PlayerSlot slot : slots) { + if (slot != null && slot.getType() != SlotType.OPEN) { + slot.setOwner(clientId); + } + } + } + + public void start(int port) throws IOException { + InvocationHandler handler = new ServerStub(this, port); + stub = (ClientIF) Proxy.newProxyInstance(ClientIF.class.getClassLoader(), new Class[] { ClientIF.class }, handler); + } + + public void stop() { + ((ServerStub)Proxy.getInvocationHandler(stub)).stop(); + } + + public PlayerSlot[] getSlots() { + return slots; + } + + public Snapshot getSnapshot() { + return snapshot; + } + + private EnumSet mergeSupportedExpansions() { + EnumSet merged = null; + for (int i = 0; i < slotSupportedExpansions.length; i++) { + EnumSet supported = slotSupportedExpansions[i]; + if (supported == null) continue; + if (merged == null) { + merged = EnumSet.allOf(Expansion.class); + } + merged.retainAll(supported); + } + return merged; + } + + @Override + public void updateSlot(PlayerSlot slot, EnumSet supportedExpansions) { + if (gameStarted) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateSlot"); + return; + } + if (snapshot == null) { + //TODO check rights, maybe copy only + if (slots[slot.getNumber()].getType() == SlotType.OPEN) { //old type + slot.setSerial(++slotSerial); + } + if (slot.getType() == SlotType.OPEN) { //new type + slot.setNick(null); + slot.setSerial(null); + } + if (slot.getType() != SlotType.AI) { //new type + slot.setAiClassName(null); + } + } + slots[slot.getNumber()] = slot; + slotSupportedExpansions[slot.getNumber()] = supportedExpansions; + stub.updateSlot(slot); + //TODO + stub.updateSupportedExpansions(mergeSupportedExpansions()); + } + + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + if (gameStarted || ! expansion.isEnabled()) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateExpansion"); + return; + } + if (enabled) { + getExpansions().add(expansion); + } else { + getExpansions().remove(expansion); + } + //stub.updateGameSettings(slots, getExpansions(), getCustomRules()); + stub.updateExpansion(expansion, enabled); + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + if (gameStarted) { + logger.error(Application.ILLEGAL_STATE_MSG, "updateCustomRule"); + return; + } + if (enabled) { + getCustomRules().add(rule); + } else { + getCustomRules().remove(rule); + } + //stub.updateGameSettings(slots, getExpansions(), getCustomRules()); + stub.updateCustomRule(rule, enabled); + } + + @Override + public void startGame() { + ((ServerStub)Proxy.getInvocationHandler(stub)).closeAccepting(); + gameStarted = true; + EnumSet supported = mergeSupportedExpansions(); + if (supported != null) { + for (Expansion exp : Expansion.values()) { + if (exp.isEnabled() && ! supported.contains(exp)) { + stub.updateExpansion(exp, false); + } + } + } + stub.startGame(); + } + + @Override + public void pass() { + stub.pass(); + } + + @Override + public void placeTile(Rotation tileRotation, Position tilePosition) { + stub.placeTile(tileRotation, tilePosition); + } + + @Override + public void deployMeeple(Position p, Location loc, Class meepleType) { + stub.deployMeeple(p, loc, meepleType); + + } + + @Override + public void moveDragon(Position p) { + stub.moveDragon(p); + } + + @Override + public void payRansom(Integer playerIndexToPay, Class meepleType) { + stub.payRansom(playerIndexToPay, meepleType); + + } + + @Override + public void selectTiles(int tilesCount, int drawCount) { + assert tilesCount >= drawCount && drawCount > 0; + int[] result = new int[drawCount]; + for (int i = 0; i < drawCount; i++) { + result[i] = random.nextInt(tilesCount--); + } + stub.drawTiles(result); + } + + @Override + public void rollFlierDice() { + stub.setFlierDistance(1+random.nextInt(3)); + } + + @Override + public void moveFairy(Position p) { + stub.moveFairy(p); + } + + @Override + public void placeTowerPiece(Position p) { + stub.placeTowerPiece(p); + } + + @Override + public void placeTunnelPiece(Position p, Location d, boolean isSecondPiece) { + stub.placeTunnelPiece(p, d, isSecondPiece); + } + + @Override + public void takePrisoner(Position p, Location d, Class meepleType, Integer meepleOwner) { + stub.takePrisoner(p, d, meepleType, meepleOwner); + + } + + @Override + public void undeployMeeple(Position p, Location d, Class meepleType, Integer meepleOwner) { + stub.undeployMeeple(p, d, meepleType, meepleOwner); + } + + @Override + public void deployBridge(Position pos, Location loc) { + stub.deployBridge(pos, loc); + } + + @Override + public void deployCastle(Position pos, Location loc) { + stub.deployCastle(pos, loc); + } + + @Override + public void bazaarBid(Integer supplyIndex, Integer price) { + stub.bazaarBid(supplyIndex, price); + } + + @Override + public void bazaarBuyOrSell(boolean buy) { + stub.bazaarBuyOrSell(buy); + } + + @Override + public void cornCiclesRemoveOrDeploy(boolean remove) { + stub.cornCiclesRemoveOrDeploy(remove); + + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/Bootstrap.java b/src/main/java/com/jcloisterzone/ui/Bootstrap.java index bbc2f92a0..293748af7 100644 --- a/src/main/java/com/jcloisterzone/ui/Bootstrap.java +++ b/src/main/java/com/jcloisterzone/ui/Bootstrap.java @@ -1,151 +1,151 @@ -package com.jcloisterzone.ui; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.LinkedList; -import java.util.List; - -import javax.swing.ImageIcon; -import javax.swing.SwingUtilities; - -import org.ini4j.Ini; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.apple.eawt.Application; -import com.apple.eawt.ApplicationAdapter; -import com.apple.eawt.ApplicationEvent; -import com.jcloisterzone.AppUpdate; -import com.jcloisterzone.FileTeeStream; -import com.jcloisterzone.VersionComparator; -import com.jcloisterzone.ui.plugin.Plugin; - -public class Bootstrap { - - { - //run before first logger is initialized - if (!"false".equals(System.getProperty("errorLog"))) { - System.setOut(new FileTeeStream(System.out, "error.log")); - } - } - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - public static boolean isMac() { - return System.getProperty("os.name").startsWith("Mac"); - } - - public Ini loadConfig() { - Ini config = new Ini(); - String configFile = System.getProperty("config"); - if (configFile == null) { - configFile = "config.ini"; - } - try { - config.load(Client.class.getClassLoader().getResource(configFile)); - } catch (Exception ex) { - logger.error("Unable to read config.ini", ex); - System.exit(1); - } - return config; - } - - public List loadPlugins(Ini config) { - LinkedList plugins = new LinkedList<>(); - List pluginPaths = null; - - if (config.get("plugins") != null) { - pluginPaths = config.get("plugins").getAll("plugin"); - } - - if (pluginPaths != null) { - for (String pluginPath : pluginPaths) { - try { - Plugin plugin = Plugin.loadPlugin(pluginPath); - plugins.addFirst(plugin); - logger.info("plugin <{}> loaded", plugin); - } catch (Exception e) { - logger.error("Unable to load plugin " + pluginPath, e); - } - } - } - - return plugins; - } - - private void checkForUpdate(Ini config, final Client client) { - final String updateUrlStr = config.get("update", "url"); - if (updateUrlStr != null && !com.jcloisterzone.Application.VERSION.contains("dev")) { - (new Thread() { - public void run() { - try { - URL url = new URL(updateUrlStr); - final AppUpdate update = AppUpdate.fetch(url); - if (update != null && (new VersionComparator()).compare(com.jcloisterzone.Application.VERSION, update.getVersion()) < 0) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - client.showUpdateIsAvailable(update); - }; - }); - } - } catch (MalformedURLException e) { - logger.error("Malformed key update.url in config file.", e); - } - }; - }).start(); - } - } - - public void run() { - System.setProperty("apple.awt.graphics.EnableQ2DX", "true"); - System.setProperty("apple.laf.useScreenMenuBar", "true"); - System.setProperty("com.apple.mrj.application.apple.menu.about.name", "JCloisterZone"); - - Ini config = loadConfig(); - List plugins = loadPlugins(config); - - final Client client = new Client(config, plugins); - - SwingUtilities.invokeLater(new Runnable() { - public void run() { - client.init(); - - if (isMac()) { - Application macApplication = Application.getApplication(); - macApplication.setDockIconImage(new ImageIcon(Client.class.getClassLoader().getResource("sysimages/ico.png")).getImage()); - macApplication.addApplicationListener(new MacApplicationAdapter(client)); - } - - if (client.getConfig().get("debug", "autostart", boolean.class)) { - client.createGame(); - } - } - }); - - checkForUpdate(config, client); - } - - public static void main(String[] args) { - (new Bootstrap()).run(); - } - - static class MacApplicationAdapter extends ApplicationAdapter { - private final Client client; - - public MacApplicationAdapter(Client client) { - this.client = client; - } - - @Override - public void handleAbout(ApplicationEvent ev) { - ev.setHandled(true); - client.handleAbout(); - } - - @Override - public void handleQuit(ApplicationEvent ev) { - ev.setHandled(true); - client.handleQuit(); - } - } -} +package com.jcloisterzone.ui; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.ImageIcon; +import javax.swing.SwingUtilities; + +import org.ini4j.Ini; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.apple.eawt.Application; +import com.apple.eawt.ApplicationAdapter; +import com.apple.eawt.ApplicationEvent; +import com.jcloisterzone.AppUpdate; +import com.jcloisterzone.FileTeeStream; +import com.jcloisterzone.VersionComparator; +import com.jcloisterzone.ui.plugin.Plugin; + +public class Bootstrap { + + { + //run before first logger is initialized + if (!"false".equals(System.getProperty("errorLog"))) { + System.setOut(new FileTeeStream(System.out, "error.log")); + } + } + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + public static boolean isMac() { + return System.getProperty("os.name").startsWith("Mac"); + } + + public Ini loadConfig() { + Ini config = new Ini(); + String configFile = System.getProperty("config"); + if (configFile == null) { + configFile = "config.ini"; + } + try { + config.load(Client.class.getClassLoader().getResource(configFile)); + } catch (Exception ex) { + logger.error("Unable to read config.ini", ex); + System.exit(1); + } + return config; + } + + public List loadPlugins(Ini config) { + LinkedList plugins = new LinkedList<>(); + List pluginPaths = null; + + if (config.get("plugins") != null) { + pluginPaths = config.get("plugins").getAll("plugin"); + } + + if (pluginPaths != null) { + for (String pluginPath : pluginPaths) { + try { + Plugin plugin = Plugin.loadPlugin(pluginPath); + plugins.addFirst(plugin); + logger.info("plugin <{}> loaded", plugin); + } catch (Exception e) { + logger.error("Unable to load plugin " + pluginPath, e); + } + } + } + + return plugins; + } + + private void checkForUpdate(Ini config, final Client client) { + final String updateUrlStr = config.get("update", "url"); + if (updateUrlStr != null && !com.jcloisterzone.Application.VERSION.contains("dev")) { + (new Thread() { + public void run() { + try { + URL url = new URL(updateUrlStr); + final AppUpdate update = AppUpdate.fetch(url); + if (update != null && (new VersionComparator()).compare(com.jcloisterzone.Application.VERSION, update.getVersion()) < 0) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + client.showUpdateIsAvailable(update); + }; + }); + } + } catch (MalformedURLException e) { + logger.error("Malformed key update.url in config file.", e); + } + }; + }).start(); + } + } + + public void run() { + System.setProperty("apple.awt.graphics.EnableQ2DX", "true"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + System.setProperty("com.apple.mrj.application.apple.menu.about.name", "JCloisterZone"); + + Ini config = loadConfig(); + List plugins = loadPlugins(config); + + final Client client = new Client(config, plugins); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + client.init(); + + if (isMac()) { + Application macApplication = Application.getApplication(); + macApplication.setDockIconImage(new ImageIcon(Client.class.getClassLoader().getResource("sysimages/ico.png")).getImage()); + macApplication.addApplicationListener(new MacApplicationAdapter(client)); + } + + if (client.getConfig().get("debug", "autostart", boolean.class)) { + client.createGame(); + } + } + }); + + checkForUpdate(config, client); + } + + public static void main(String[] args) { + (new Bootstrap()).run(); + } + + static class MacApplicationAdapter extends ApplicationAdapter { + private final Client client; + + public MacApplicationAdapter(Client client) { + this.client = client; + } + + @Override + public void handleAbout(ApplicationEvent ev) { + ev.setHandled(true); + client.handleAbout(); + } + + @Override + public void handleQuit(ApplicationEvent ev) { + ev.setHandled(true); + client.handleQuit(); + } + } +} diff --git a/src/main/java/com/jcloisterzone/ui/Client.java b/src/main/java/com/jcloisterzone/ui/Client.java index df6ed6403..ab383697d 100644 --- a/src/main/java/com/jcloisterzone/ui/Client.java +++ b/src/main/java/com/jcloisterzone/ui/Client.java @@ -1,566 +1,566 @@ -package com.jcloisterzone.ui; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Container; -import java.awt.Cursor; -import java.awt.Font; -import java.awt.GridBagLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Proxy; -import java.net.InetAddress; -import java.util.List; -import java.util.Locale; - -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.Clip; -import javax.swing.ImageIcon; -import javax.swing.JFileChooser; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextField; -import javax.swing.UIManager; -import javax.swing.WindowConstants; - -import org.ini4j.Ini; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.AppUpdate; -import com.jcloisterzone.Player; -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.event.GameEventListener; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.GuiClientStub; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.SnapshotVersionException; -import com.jcloisterzone.game.phase.GameOverPhase; -import com.jcloisterzone.rmi.ServerIF; -import com.jcloisterzone.rmi.mina.ClientStub; -import com.jcloisterzone.server.Server; -import com.jcloisterzone.ui.controls.ControlPanel; -import com.jcloisterzone.ui.dialog.AboutDialog; -import com.jcloisterzone.ui.dialog.DiscardedTilesDialog; -import com.jcloisterzone.ui.grid.GridPanel; -import com.jcloisterzone.ui.grid.MainPanel; -import com.jcloisterzone.ui.panel.BackgroundPanel; -import com.jcloisterzone.ui.panel.ConnectGamePanel; -import com.jcloisterzone.ui.panel.CreateGamePanel; -import com.jcloisterzone.ui.panel.HelpPanel; -import com.jcloisterzone.ui.panel.StartPanel; -import com.jcloisterzone.ui.plugin.Plugin; -import com.jcloisterzone.ui.resources.ConvenientResourceManager; -import com.jcloisterzone.ui.resources.PlugableResourceManager; -import com.jcloisterzone.ui.theme.ControlsTheme; -import com.jcloisterzone.ui.theme.FigureTheme; - -@SuppressWarnings("serial") -public class Client extends JFrame { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - public static final String BASE_TITLE = "JCloisterZone"; - - private ClientController controller = new ClientController(this); - - private final Ini config; - private final ClientSettings settings; - private final ConvenientResourceManager resourceManager; - - @Deprecated - private FigureTheme figureTheme; - @Deprecated - private ControlsTheme controlsTheme; - private Color[] playerColors; - - //private MenuBar menuBar; - private StartPanel startPanel; - private ControlPanel controlPanel; - private MainPanel mainPanel; - - - private CreateGamePanel createGamePanel; - private DiscardedTilesDialog discardedTilesDialog; - - private Server localServer; - private ServerIF server; - - - private Game game; - //active player must be cached locally because of game's active player record is changed in other thread immediately - private Player activePlayer; - - protected ClientStub getClientStub() { - return (ClientStub) Proxy.getInvocationHandler(server); - } - - public long getClientId() { - return getClientStub().getClientId(); - } - - private Locale getLocaleFromConfig() { - String language = config.get("ui", "locale"); - if (language == null) { - return Locale.getDefault(); - } - if (language.contains("_")) { - String[] tokens = language.split("_", 2); - return new Locale(tokens[0], tokens[1]); - } - return new Locale(language); - } - - private Color stringToColor(String colorName) { - if (colorName.startsWith("#")) { - //RGB format - int r = Integer.parseInt(colorName.substring(1,3),16); - int g = Integer.parseInt(colorName.substring(3,5),16); - int b = Integer.parseInt(colorName.substring(5,7),16); - return new Color(r,g,b); - } else { - //constant format - java.lang.reflect.Field f; - try { - f = Color.class.getField(colorName); - return (Color) f.get(null); - } catch (Exception e1) { - logger.error("Invalid color name in config file: " + colorName); - return Color.BLACK; - } - } - } - - @Override - public void setLocale(Locale l) { - I18nUtils.setLocale(l); - super.setLocale(l); - } - - public Client(Ini config, List plugins) { - this.config = config; - settings = new ClientSettings(config); - resourceManager = new ConvenientResourceManager(new PlugableResourceManager(this, plugins)); - } - - public void init() { - setLocale(getLocaleFromConfig()); - - List colorNames = config.get("players").getAll("color"); - playerColors = new Color[colorNames.size()]; - for (int i = 0; i < playerColors.length; i++ ) { - playerColors[i] = stringToColor(colorNames.get(i)); - } - figureTheme = new FigureTheme(this); - controlsTheme = new ControlsTheme(this); - - resetWindowIcon(); - - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception e) { - e.printStackTrace(); //TODO logger - } - - setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - this.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - if (closeGame() == true) { - System.exit(0); - } - } - }); - MenuBar menuBar = new MenuBar(this); - this.setJMenuBar(menuBar); - - //Toolkit.getDefaultToolkit().addAWTEventListener(new GlobalKeyListener(), AWTEvent.KEY_EVENT_MASK); - - Container pane = getContentPane(); - - pane.setLayout(new BorderLayout()); - JPanel envelope = new BackgroundPanel(new GridBagLayout()); - pane.add(envelope, BorderLayout.CENTER); - - startPanel = new StartPanel(); - startPanel.setClient(this); - envelope.add(startPanel); - - this.pack(); - this.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); - this.setTitle(BASE_TITLE); - this.setVisible(true); - } - - @Override - public MenuBar getJMenuBar() { - return (MenuBar) super.getJMenuBar(); - } - - void resetWindowIcon() { - this.setIconImage(new ImageIcon(Client.class.getClassLoader().getResource("sysimages/ico.png")).getImage()); - } - - public Ini getConfig() { - return config; - } - - public ClientSettings getSettings() { - return settings; - } - - public ConvenientResourceManager getResourceManager() { - return resourceManager; - } - - @Deprecated - public FigureTheme getFigureTheme() { - return figureTheme; - } - - @Deprecated - public ControlsTheme getControlsTheme() { - return controlsTheme; - } - - public ServerIF getServer() { - return server; - } - - public Game getGame() { - return game; - } - - public ControlPanel getControlPanel() { - return controlPanel; - } - - public void setControlPanel(ControlPanel controlPanel) { - this.controlPanel = controlPanel; - } - - public GridPanel getGridPanel() { - if (mainPanel == null) return null; - return mainPanel.getGridPanel(); - } - - public MainPanel getMainPanel() { - return mainPanel; - } - - public void setMainPanel(MainPanel mainPanel) { - this.mainPanel = mainPanel; - } - - public CreateGamePanel getCreateGamePanel() { - return createGamePanel; - } - - public void setCreateGamePanel(CreateGamePanel createGamePanel) { - this.createGamePanel = createGamePanel; - } - - public void setDiscardedTilesDialog(DiscardedTilesDialog discardedTilesDialog) { - this.discardedTilesDialog = discardedTilesDialog; - } - - public void cleanContentPane() { - Container pane = this.getContentPane(); - pane.setVisible(false); - pane.removeAll(); - this.startPanel = null; - this.mainPanel = null; - this.controlPanel = null; - if (createGamePanel != null) { - createGamePanel.disposePanel(); - } - } - - public void showCreateGamePanel(boolean mutableSlots, PlayerSlot[] slots) { - Container pane = this.getContentPane(); - cleanContentPane(); - createGamePanel = new CreateGamePanel(this, mutableSlots, slots); - JPanel envelope = new BackgroundPanel(); - envelope.setLayout(new GridBagLayout()); //to have centered inner panel - envelope.add(createGamePanel); - - JScrollPane scroll = new JScrollPane(envelope); - pane.add(scroll, BorderLayout.CENTER); - pane.setVisible(true); - } - - public boolean closeGame() { - return closeGame(false); - } - - public boolean closeGame(boolean force) { - boolean isGameRunning = getJMenuBar().isGameRunning(); - if (settings.isConfirmGameClose() && isGameRunning && !(game.getPhase() instanceof GameOverPhase)) { - if (localServer != null) { - String options[] = {_("Close game"), _("Cancel") }; - int result = JOptionPane.showOptionDialog(this, - _("Game is running. Do you really want to quit game and also disconnect all other players?"), - _("Close game"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); - if (JOptionPane.OK_OPTION != result) return false; - } else { - String options[] = {_("Close game"), _("Cancel") }; - int result = JOptionPane.showOptionDialog(this, - _("Game is running. Do you really want to leave it?"), - _("Close game"), - JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); - if (JOptionPane.OK_OPTION != result) return false; - } - } - if (localServer != null) { - localServer.stop(); - localServer = null; - } - server = null; - activePlayer = null; - getJMenuBar().setIsGameRunning(false); - if (controlPanel != null) { - controlPanel.closeGame(); - mainPanel.closeGame(); - } - if (discardedTilesDialog != null) { - discardedTilesDialog.dispose(); - discardedTilesDialog = null; - getJMenuBar().setShowDiscardedEnabled(false); - } - return true; - } - - public void showConnectGamePanel() { - if (!closeGame()) return; - - Container pane = this.getContentPane(); - cleanContentPane(); - - JPanel envelope = new BackgroundPanel(); - envelope.setLayout(new GridBagLayout()); //to have centered inner panel - envelope.add(new ConnectGamePanel(this)); - - pane.add(envelope, BorderLayout.CENTER); - pane.setVisible(true); - } - - public void setGame(Game game) { - this.game = game; - Object clientProxy = Proxy.newProxyInstance(Client.class.getClassLoader(), - new Class[] { UserInterface.class, GameEventListener.class }, new InvokeInSwingUiAdapter(controller)); - game.addUserInterface((UserInterface) clientProxy); - game.addGameListener((GameEventListener) clientProxy); - } - - public void connect(InetAddress ia, int port) { - GuiClientStub handler = new GuiClientStub(this); - server = (ServerIF) Proxy.newProxyInstance(ServerIF.class.getClassLoader(), - new Class[] { ServerIF.class }, handler); - handler.setServerProxy(server); - handler.connect(ia, port); - } - - public void handleSave() { - JFileChooser fc = new JFileChooser(System.getProperty("user.dir") + System.getProperty("file.separator") + "saves"); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - fc.setDialogTitle(_("Save game")); - fc.setDialogType(JFileChooser.SAVE_DIALOG); - fc.setFileFilter(new SavegameFileFilter()); - fc.setLocale(getLocale()); - int returnVal = fc.showSaveDialog(this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - if (file != null) { - if (!file.getName().endsWith(".jcz")) { - file = new File(file.getAbsolutePath() + ".jcz"); - } - try { - Snapshot snapshot = new Snapshot(game, getClientId()); - if ("plain".equals(getConfig().get("debug", "save_format"))) { - snapshot.setGzipOutput(false); - } - snapshot.save(file); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); - } - } - } - } - - private int getServerPort() { - return config.get("server", "port", int.class); - } - - public void createGame() { - if (!closeGame()) return; - try { - localServer = new Server(config); - localServer.start(getServerPort()); - connect(InetAddress.getLocalHost(), getServerPort()); - } catch (IOException e) { - logger.error(e.getMessage(), e); - JOptionPane.showMessageDialog(this, e.getMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); - closeGame(true); - } - } - - public void handleLoad() { - JFileChooser fc = new JFileChooser(System.getProperty("user.dir") + System.getProperty("file.separator") + "saves"); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - fc.setDialogTitle(_("Load game")); - fc.setDialogType(JFileChooser.OPEN_DIALOG); - fc.setFileFilter(new SavegameFileFilter()); - fc.setLocale(getLocale()); - int returnVal = fc.showOpenDialog(this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - if (file != null) { - if (!closeGame()) return; - try { - localServer = new Server(new Snapshot(file)); - localServer.start(getServerPort()); - connect(InetAddress.getLocalHost(), getServerPort()); - } catch (SnapshotVersionException ex1) { - //do not create error.log - JOptionPane.showMessageDialog(this, ex1.getLocalizedMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); - } catch (Exception ex) { - logger.error(ex.getMessage(), ex); - JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); - } - } - } - } - - public void handleQuit() { - if (closeGame() == true) { - System.exit(0); - } - } - - public void handleAbout() { - new AboutDialog(); - } - - public boolean isClientActive() { - if (activePlayer == null) return false; - if (activePlayer.getSlot().getType() != SlotType.PLAYER) return false; - return getClientStub().isLocalPlayer(activePlayer); - } - - public Player getActivePlayer() { - return activePlayer; - } - - public void setActivePlayer(Player activePlayer) { - this.activePlayer = activePlayer; - } - - void beep() { - if (settings.isPlayBeep()) { - try { - BufferedInputStream fileInStream = new BufferedInputStream(Client.class.getClassLoader().getResource("beep.wav").openStream()); - AudioInputStream beepStream = AudioSystem.getAudioInputStream(fileInStream); - Clip c = AudioSystem.getClip(); - c.open(beepStream); - c.start(); - } catch (Exception e) { - logger.error(e.getMessage(), e); - } - } - } - - void clearActions() { - if (controlPanel.getActionPanel().getActions() != null) { - controlPanel.clearActions(); - } - } - - public DiscardedTilesDialog getDiscardedTilesDialog() { - return discardedTilesDialog; - } - - public void showUpdateIsAvailable(final AppUpdate appUpdate) { - if (isVisible() && startPanel != null) { - Color bg = new Color(0.2f, 1.0f, 0.0f, 0.1f); - HelpPanel hp = startPanel.getHelpPanel(); - hp.removeAll(); - hp.setOpaque(true); - hp.setBackground(bg); - Font font = new Font(null, Font.BOLD, 14); - JLabel label; - label = new JLabel(_("JCloisterZone " + appUpdate.getVersion() + " is available for download.")); - label.setFont(font); - hp.add(label, "wrap"); - label = new JLabel(appUpdate.getDescription()); - hp.add(label, "wrap"); - - final JTextField link = new JTextField(appUpdate.getDownloadUrl()); - link.setEditable(false); - link.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); - link.addMouseListener(new MouseAdapter() { - @Override - public void mouseEntered(MouseEvent e) { - link.setSelectionStart(0); - link.setSelectionEnd(link.getText().length()); - } - - @Override - public void mouseExited(MouseEvent e) { - link.setSelectionStart(0); - link.setSelectionEnd(0); - } - }); - - hp.add(link, "wrap, growx"); - hp.repaint(); - } else { - //probably it shouln't happen - System.out.println("JCloisterZone " + appUpdate.getVersion() + " is avaiable for download."); - System.out.println(appUpdate.getDescription()); - System.out.println(appUpdate.getDownloadUrl()); - } - } - - - //------------------- LEGACY: TODO refactor --------------- - //TODO move getColor on player - - - public Color getPlayerSecondTunelColor(Player player) { - int slotNumber = player.getSlot().getNumber(); - return playerColors[(slotNumber + 2) % playerColors.length]; - } - - public Color getPlayerColor(Player player) { - return playerColors[player.getSlot().getNumber()]; - } - - public Color getPlayerColor(PlayerSlot playerSlot) { - return playerColors[playerSlot.getNumber()]; - } - - public Color getPlayerColor() { - Player player = game.getActivePlayer(); - if (player == null) { //awt thread is not synced - return Color.BLACK; - } else { - return playerColors[player.getSlot().getNumber()]; - } - } - +package com.jcloisterzone.ui; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.GridBagLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Proxy; +import java.net.InetAddress; +import java.util.List; +import java.util.Locale; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.swing.ImageIcon; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.UIManager; +import javax.swing.WindowConstants; + +import org.ini4j.Ini; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.AppUpdate; +import com.jcloisterzone.Player; +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.event.GameEventListener; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.GuiClientStub; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.SnapshotVersionException; +import com.jcloisterzone.game.phase.GameOverPhase; +import com.jcloisterzone.rmi.ServerIF; +import com.jcloisterzone.rmi.mina.ClientStub; +import com.jcloisterzone.server.Server; +import com.jcloisterzone.ui.controls.ControlPanel; +import com.jcloisterzone.ui.dialog.AboutDialog; +import com.jcloisterzone.ui.dialog.DiscardedTilesDialog; +import com.jcloisterzone.ui.grid.GridPanel; +import com.jcloisterzone.ui.grid.MainPanel; +import com.jcloisterzone.ui.panel.BackgroundPanel; +import com.jcloisterzone.ui.panel.ConnectGamePanel; +import com.jcloisterzone.ui.panel.CreateGamePanel; +import com.jcloisterzone.ui.panel.HelpPanel; +import com.jcloisterzone.ui.panel.StartPanel; +import com.jcloisterzone.ui.plugin.Plugin; +import com.jcloisterzone.ui.resources.ConvenientResourceManager; +import com.jcloisterzone.ui.resources.PlugableResourceManager; +import com.jcloisterzone.ui.theme.ControlsTheme; +import com.jcloisterzone.ui.theme.FigureTheme; + +@SuppressWarnings("serial") +public class Client extends JFrame { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + public static final String BASE_TITLE = "JCloisterZone"; + + private ClientController controller = new ClientController(this); + + private final Ini config; + private final ClientSettings settings; + private final ConvenientResourceManager resourceManager; + + @Deprecated + private FigureTheme figureTheme; + @Deprecated + private ControlsTheme controlsTheme; + private Color[] playerColors; + + //private MenuBar menuBar; + private StartPanel startPanel; + private ControlPanel controlPanel; + private MainPanel mainPanel; + + + private CreateGamePanel createGamePanel; + private DiscardedTilesDialog discardedTilesDialog; + + private Server localServer; + private ServerIF server; + + + private Game game; + //active player must be cached locally because of game's active player record is changed in other thread immediately + private Player activePlayer; + + protected ClientStub getClientStub() { + return (ClientStub) Proxy.getInvocationHandler(server); + } + + public long getClientId() { + return getClientStub().getClientId(); + } + + private Locale getLocaleFromConfig() { + String language = config.get("ui", "locale"); + if (language == null) { + return Locale.getDefault(); + } + if (language.contains("_")) { + String[] tokens = language.split("_", 2); + return new Locale(tokens[0], tokens[1]); + } + return new Locale(language); + } + + private Color stringToColor(String colorName) { + if (colorName.startsWith("#")) { + //RGB format + int r = Integer.parseInt(colorName.substring(1,3),16); + int g = Integer.parseInt(colorName.substring(3,5),16); + int b = Integer.parseInt(colorName.substring(5,7),16); + return new Color(r,g,b); + } else { + //constant format + java.lang.reflect.Field f; + try { + f = Color.class.getField(colorName); + return (Color) f.get(null); + } catch (Exception e1) { + logger.error("Invalid color name in config file: " + colorName); + return Color.BLACK; + } + } + } + + @Override + public void setLocale(Locale l) { + I18nUtils.setLocale(l); + super.setLocale(l); + } + + public Client(Ini config, List plugins) { + this.config = config; + settings = new ClientSettings(config); + resourceManager = new ConvenientResourceManager(new PlugableResourceManager(this, plugins)); + } + + public void init() { + setLocale(getLocaleFromConfig()); + + List colorNames = config.get("players").getAll("color"); + playerColors = new Color[colorNames.size()]; + for (int i = 0; i < playerColors.length; i++ ) { + playerColors[i] = stringToColor(colorNames.get(i)); + } + figureTheme = new FigureTheme(this); + controlsTheme = new ControlsTheme(this); + + resetWindowIcon(); + + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); //TODO logger + } + + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + this.addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + if (closeGame() == true) { + System.exit(0); + } + } + }); + MenuBar menuBar = new MenuBar(this); + this.setJMenuBar(menuBar); + + //Toolkit.getDefaultToolkit().addAWTEventListener(new GlobalKeyListener(), AWTEvent.KEY_EVENT_MASK); + + Container pane = getContentPane(); + + pane.setLayout(new BorderLayout()); + JPanel envelope = new BackgroundPanel(new GridBagLayout()); + pane.add(envelope, BorderLayout.CENTER); + + startPanel = new StartPanel(); + startPanel.setClient(this); + envelope.add(startPanel); + + this.pack(); + this.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH); + this.setTitle(BASE_TITLE); + this.setVisible(true); + } + + @Override + public MenuBar getJMenuBar() { + return (MenuBar) super.getJMenuBar(); + } + + void resetWindowIcon() { + this.setIconImage(new ImageIcon(Client.class.getClassLoader().getResource("sysimages/ico.png")).getImage()); + } + + public Ini getConfig() { + return config; + } + + public ClientSettings getSettings() { + return settings; + } + + public ConvenientResourceManager getResourceManager() { + return resourceManager; + } + + @Deprecated + public FigureTheme getFigureTheme() { + return figureTheme; + } + + @Deprecated + public ControlsTheme getControlsTheme() { + return controlsTheme; + } + + public ServerIF getServer() { + return server; + } + + public Game getGame() { + return game; + } + + public ControlPanel getControlPanel() { + return controlPanel; + } + + public void setControlPanel(ControlPanel controlPanel) { + this.controlPanel = controlPanel; + } + + public GridPanel getGridPanel() { + if (mainPanel == null) return null; + return mainPanel.getGridPanel(); + } + + public MainPanel getMainPanel() { + return mainPanel; + } + + public void setMainPanel(MainPanel mainPanel) { + this.mainPanel = mainPanel; + } + + public CreateGamePanel getCreateGamePanel() { + return createGamePanel; + } + + public void setCreateGamePanel(CreateGamePanel createGamePanel) { + this.createGamePanel = createGamePanel; + } + + public void setDiscardedTilesDialog(DiscardedTilesDialog discardedTilesDialog) { + this.discardedTilesDialog = discardedTilesDialog; + } + + public void cleanContentPane() { + Container pane = this.getContentPane(); + pane.setVisible(false); + pane.removeAll(); + this.startPanel = null; + this.mainPanel = null; + this.controlPanel = null; + if (createGamePanel != null) { + createGamePanel.disposePanel(); + } + } + + public void showCreateGamePanel(boolean mutableSlots, PlayerSlot[] slots) { + Container pane = this.getContentPane(); + cleanContentPane(); + createGamePanel = new CreateGamePanel(this, mutableSlots, slots); + JPanel envelope = new BackgroundPanel(); + envelope.setLayout(new GridBagLayout()); //to have centered inner panel + envelope.add(createGamePanel); + + JScrollPane scroll = new JScrollPane(envelope); + pane.add(scroll, BorderLayout.CENTER); + pane.setVisible(true); + } + + public boolean closeGame() { + return closeGame(false); + } + + public boolean closeGame(boolean force) { + boolean isGameRunning = getJMenuBar().isGameRunning(); + if (settings.isConfirmGameClose() && isGameRunning && !(game.getPhase() instanceof GameOverPhase)) { + if (localServer != null) { + String options[] = {_("Close game"), _("Cancel") }; + int result = JOptionPane.showOptionDialog(this, + _("Game is running. Do you really want to quit game and also disconnect all other players?"), + _("Close game"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + if (JOptionPane.OK_OPTION != result) return false; + } else { + String options[] = {_("Close game"), _("Cancel") }; + int result = JOptionPane.showOptionDialog(this, + _("Game is running. Do you really want to leave it?"), + _("Close game"), + JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + if (JOptionPane.OK_OPTION != result) return false; + } + } + if (localServer != null) { + localServer.stop(); + localServer = null; + } + server = null; + activePlayer = null; + getJMenuBar().setIsGameRunning(false); + if (controlPanel != null) { + controlPanel.closeGame(); + mainPanel.closeGame(); + } + if (discardedTilesDialog != null) { + discardedTilesDialog.dispose(); + discardedTilesDialog = null; + getJMenuBar().setShowDiscardedEnabled(false); + } + return true; + } + + public void showConnectGamePanel() { + if (!closeGame()) return; + + Container pane = this.getContentPane(); + cleanContentPane(); + + JPanel envelope = new BackgroundPanel(); + envelope.setLayout(new GridBagLayout()); //to have centered inner panel + envelope.add(new ConnectGamePanel(this)); + + pane.add(envelope, BorderLayout.CENTER); + pane.setVisible(true); + } + + public void setGame(Game game) { + this.game = game; + Object clientProxy = Proxy.newProxyInstance(Client.class.getClassLoader(), + new Class[] { UserInterface.class, GameEventListener.class }, new InvokeInSwingUiAdapter(controller)); + game.addUserInterface((UserInterface) clientProxy); + game.addGameListener((GameEventListener) clientProxy); + } + + public void connect(InetAddress ia, int port) { + GuiClientStub handler = new GuiClientStub(this); + server = (ServerIF) Proxy.newProxyInstance(ServerIF.class.getClassLoader(), + new Class[] { ServerIF.class }, handler); + handler.setServerProxy(server); + handler.connect(ia, port); + } + + public void handleSave() { + JFileChooser fc = new JFileChooser(System.getProperty("user.dir") + System.getProperty("file.separator") + "saves"); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.setDialogTitle(_("Save game")); + fc.setDialogType(JFileChooser.SAVE_DIALOG); + fc.setFileFilter(new SavegameFileFilter()); + fc.setLocale(getLocale()); + int returnVal = fc.showSaveDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + if (file != null) { + if (!file.getName().endsWith(".jcz")) { + file = new File(file.getAbsolutePath() + ".jcz"); + } + try { + Snapshot snapshot = new Snapshot(game, getClientId()); + if ("plain".equals(getConfig().get("debug", "save_format"))) { + snapshot.setGzipOutput(false); + } + snapshot.save(file); + } catch (Exception ex) { + logger.error(ex.getMessage(), ex); + JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); + } + } + } + } + + private int getServerPort() { + return config.get("server", "port", int.class); + } + + public void createGame() { + if (!closeGame()) return; + try { + localServer = new Server(config); + localServer.start(getServerPort()); + connect(InetAddress.getLocalHost(), getServerPort()); + } catch (IOException e) { + logger.error(e.getMessage(), e); + JOptionPane.showMessageDialog(this, e.getMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); + closeGame(true); + } + } + + public void handleLoad() { + JFileChooser fc = new JFileChooser(System.getProperty("user.dir") + System.getProperty("file.separator") + "saves"); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.setDialogTitle(_("Load game")); + fc.setDialogType(JFileChooser.OPEN_DIALOG); + fc.setFileFilter(new SavegameFileFilter()); + fc.setLocale(getLocale()); + int returnVal = fc.showOpenDialog(this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + if (file != null) { + if (!closeGame()) return; + try { + localServer = new Server(new Snapshot(file)); + localServer.start(getServerPort()); + connect(InetAddress.getLocalHost(), getServerPort()); + } catch (SnapshotVersionException ex1) { + //do not create error.log + JOptionPane.showMessageDialog(this, ex1.getLocalizedMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); + } catch (Exception ex) { + logger.error(ex.getMessage(), ex); + JOptionPane.showMessageDialog(this, ex.getLocalizedMessage(), _("Error"), JOptionPane.ERROR_MESSAGE); + } + } + } + } + + public void handleQuit() { + if (closeGame() == true) { + System.exit(0); + } + } + + public void handleAbout() { + new AboutDialog(); + } + + public boolean isClientActive() { + if (activePlayer == null) return false; + if (activePlayer.getSlot().getType() != SlotType.PLAYER) return false; + return getClientStub().isLocalPlayer(activePlayer); + } + + public Player getActivePlayer() { + return activePlayer; + } + + public void setActivePlayer(Player activePlayer) { + this.activePlayer = activePlayer; + } + + void beep() { + if (settings.isPlayBeep()) { + try { + BufferedInputStream fileInStream = new BufferedInputStream(Client.class.getClassLoader().getResource("beep.wav").openStream()); + AudioInputStream beepStream = AudioSystem.getAudioInputStream(fileInStream); + Clip c = AudioSystem.getClip(); + c.open(beepStream); + c.start(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + } + } + + void clearActions() { + if (controlPanel.getActionPanel().getActions() != null) { + controlPanel.clearActions(); + } + } + + public DiscardedTilesDialog getDiscardedTilesDialog() { + return discardedTilesDialog; + } + + public void showUpdateIsAvailable(final AppUpdate appUpdate) { + if (isVisible() && startPanel != null) { + Color bg = new Color(0.2f, 1.0f, 0.0f, 0.1f); + HelpPanel hp = startPanel.getHelpPanel(); + hp.removeAll(); + hp.setOpaque(true); + hp.setBackground(bg); + Font font = new Font(null, Font.BOLD, 14); + JLabel label; + label = new JLabel(_("JCloisterZone " + appUpdate.getVersion() + " is available for download.")); + label.setFont(font); + hp.add(label, "wrap"); + label = new JLabel(appUpdate.getDescription()); + hp.add(label, "wrap"); + + final JTextField link = new JTextField(appUpdate.getDownloadUrl()); + link.setEditable(false); + link.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + link.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + link.setSelectionStart(0); + link.setSelectionEnd(link.getText().length()); + } + + @Override + public void mouseExited(MouseEvent e) { + link.setSelectionStart(0); + link.setSelectionEnd(0); + } + }); + + hp.add(link, "wrap, growx"); + hp.repaint(); + } else { + //probably it shouln't happen + System.out.println("JCloisterZone " + appUpdate.getVersion() + " is avaiable for download."); + System.out.println(appUpdate.getDescription()); + System.out.println(appUpdate.getDownloadUrl()); + } + } + + + //------------------- LEGACY: TODO refactor --------------- + //TODO move getColor on player + + + public Color getPlayerSecondTunelColor(Player player) { + int slotNumber = player.getSlot().getNumber(); + return playerColors[(slotNumber + 2) % playerColors.length]; + } + + public Color getPlayerColor(Player player) { + return playerColors[player.getSlot().getNumber()]; + } + + public Color getPlayerColor(PlayerSlot playerSlot) { + return playerColors[playerSlot.getNumber()]; + } + + public Color getPlayerColor() { + Player player = game.getActivePlayer(); + if (player == null) { //awt thread is not synced + return Color.BLACK; + } else { + return playerColors[player.getSlot().getNumber()]; + } + } + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/ClientController.java b/src/main/java/com/jcloisterzone/ui/ClientController.java index 5bc4144d8..63d799dc0 100644 --- a/src/main/java/com/jcloisterzone/ui/ClientController.java +++ b/src/main/java/com/jcloisterzone/ui/ClientController.java @@ -1,384 +1,384 @@ -package com.jcloisterzone.ui; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Container; -import java.awt.Image; -import java.awt.KeyboardFocusManager; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - -import javax.swing.JOptionPane; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.Player; -import com.jcloisterzone.UserInterface; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.event.GameEventListener; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Completable; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.game.capability.BazaarItem; -import com.jcloisterzone.game.capability.FlierCapability; -import com.jcloisterzone.game.phase.Phase; -import com.jcloisterzone.ui.controls.ControlPanel; -import com.jcloisterzone.ui.controls.FakeComponent; -import com.jcloisterzone.ui.dialog.DiscardedTilesDialog; -import com.jcloisterzone.ui.dialog.GameOverDialog; -import com.jcloisterzone.ui.grid.BazaarPanel; -import com.jcloisterzone.ui.grid.BazaarPanel.BazaarPanelState; -import com.jcloisterzone.ui.grid.CornCirclesPanel; -import com.jcloisterzone.ui.grid.FlierPanel; -import com.jcloisterzone.ui.grid.GridPanel; -import com.jcloisterzone.ui.grid.KeyController; -import com.jcloisterzone.ui.grid.MainPanel; -import com.jcloisterzone.ui.grid.layer.DragonAvailableMove; -import com.jcloisterzone.ui.grid.layer.DragonLayer; - -public class ClientController implements GameEventListener, UserInterface { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final Client client; - private KeyController keyController; - - public ClientController(Client client) { - this.client = client; - } - - @Override - public void updateCustomRule(CustomRule rule, Boolean enabled) { - client.getCreateGamePanel().updateCustomRule(rule, enabled); - } - - @Override - public void updateExpansion(Expansion expansion, Boolean enabled) { - client.getCreateGamePanel().updateExpansion(expansion, enabled); - } - - @Override - public void updateSlot(PlayerSlot slot) { - client.getCreateGamePanel().updateSlot(slot); - } - - @Override - public void updateSupportedExpansions(EnumSet expansions) { - client.getCreateGamePanel().updateSupportedExpansions(expansions); - } - - @Override - public void started(Snapshot snapshot) { - client.cleanContentPane(); - - Container pane = client.getContentPane(); - pane.setLayout(new BorderLayout()); - - ControlPanel controlPanel = new ControlPanel(client); - client.setControlPanel(controlPanel); - - MainPanel mainPanel = new MainPanel(client); - client.setMainPanel(mainPanel); - pane.add(mainPanel, BorderLayout.CENTER); - - mainPanel.started(snapshot); - - if (keyController == null) { - // first started game - keyController = new KeyController(client); - KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keyController); - } - - pane.setVisible(true); - - MenuBar menu = client.getJMenuBar(); - menu.setZoomInEnabled(true); - menu.setZoomOutEnabled(true); - menu.setIsGameRunning(true); - } - - @Override - public void playerActivated(Player turnPlayer, Player activePlayer) { - client.setActivePlayer(activePlayer); - client.getControlPanel().playerActivated(turnPlayer, activePlayer); - - if (client.isClientActive()) { - client.beep(); - } - - // TODO better image quality ? - Color c = client.getPlayerColor(activePlayer); - Image image = client.getFigureTheme().getFigureImage(SmallFollower.class, c, null); - client.setIconImage(image); - } - - public void refreshWindowTitle() { - StringBuilder title = new StringBuilder(Client.BASE_TITLE); - Game game = client.getGame(); - if (game != null) { - Player activePlayer = game.getActivePlayer(); - if (activePlayer != null) { - title.append(" ⋅ ").append(activePlayer.getNick()); - } - int packSize = game.getTilePack().totalSize(); - title.append(" ⋅ ").append(String.format(_("%d tiles left"), packSize)); - } - client.setTitle(title.toString()); - } - - @Override - public void tileDrawn(Tile tile) { - client.clearActions(); - refreshWindowTitle(); - } - - @Override - public void tileDiscarded(Tile tile) { - DiscardedTilesDialog discardedTilesDialog = client.getDiscardedTilesDialog(); - if (discardedTilesDialog == null) { - discardedTilesDialog = new DiscardedTilesDialog(client); - client.setDiscardedTilesDialog(discardedTilesDialog); - client.getJMenuBar().setShowDiscardedEnabled(true); - } - discardedTilesDialog.addTile(tile); - discardedTilesDialog.setVisible(true); - } - - @Override - public void tilePlaced(Tile tile) { - client.getMainPanel().tilePlaced(tile); - } - - @Override - public void dragonMoved(Position p) { - client.getMainPanel().dragonMoved(p); - } - - @Override - public void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece) { - client.getMainPanel().tunnelPiecePlaced(player, p, d, isSecondPiece); - } - - @Override - public void gameOver() { - client.setTitle(Client.BASE_TITLE); - client.resetWindowIcon(); - client.closeGame(true); - new GameOverDialog(client); - } - - @Override - public void phaseEntered(Phase phase) { - GridPanel grid = client.getGridPanel(); - if (grid == null) - return; - - FlierCapability flierGame = client.getGame().getCapability(FlierCapability.class); - FlierPanel flierPanel; - boolean rollAllowed = false, rollMade = false; - if (flierGame != null) { - rollAllowed = flierGame.isFlierRollAllowed() && client.isClientActive(); - rollMade = flierGame.getFlierDistance() > 0; - } - if (rollAllowed || rollMade) { - flierPanel = createSecondPanel(FlierPanel.class); - if (rollMade) { - flierPanel.setFlierDistance(flierGame.getFlierDistance()); - } - } else { - if (grid.getSecondPanel() instanceof FlierPanel) { - grid.setSecondPanel(null); - } - } - } - - @Override - public void fairyMoved(Position p) { - client.getMainPanel().fairyMoved(p); - } - - @Override - public void towerIncreased(Position p, Integer height) { - client.clearActions(); - client.getMainPanel().towerIncreased(p, height); - } - - @Override - public void ransomPaid(Player from, Player to, Follower f) { - client.getGridPanel().repaint(); - } - - // ------------------ Meeple events ----------- - - @Override - public void deployed(Meeple m) { - client.getMainPanel().deployed(m); - } - - @Override - public void undeployed(Meeple m) { - client.getMainPanel().undeployed(m); - } - - @Override - public void bridgeDeployed(Position pos, Location loc) { - client.getMainPanel().bridgeDeployed(pos, loc); - } - - @Override - public void castleDeployed(Castle castle1, Castle castle2) { - client.getMainPanel().castleDeployed(castle1, castle2); - } - - // ------------------ Feature evnts ---------- - - @Override - public void completed(Completable feature, CompletableScoreContext ctx) { - } - - @Override - public void scored(Feature feature, int points, String label, Meeple meeple, boolean finalScoring) { - client.getMainPanel().scored(feature, label, meeple, finalScoring); - client.getMainPanel().repaint(); // players only - } - - @Override - public void scored(Position position, Player player, int points, String label, boolean finalScoring) { - client.getMainPanel().scored(position, player, label, finalScoring); - client.getMainPanel().repaint(); // players only - } - - // User interface - - @Override - public void showWarning(String title, String message) { - JOptionPane.showMessageDialog(client, message, title, JOptionPane.WARNING_MESSAGE); - } - - @Override - public void selectDragonMove(Set positions, int movesLeft) { - client.clearActions(); - DragonLayer dragonDecoration = client.getGridPanel().findDecoration(DragonLayer.class); - dragonDecoration.setMoves(movesLeft); - client.getGridPanel().repaint(); - logger.debug("UI selectdragon move, left {}, {}", movesLeft, positions); - if (client.isClientActive()) { - client.getGridPanel().addLayer(new DragonAvailableMove(client.getGridPanel(), positions)); - client.beep(); - } - } - - @Override - public void selectAction(List actions, boolean canPass) { - client.clearActions(); - client.getControlPanel().selectAction(actions, canPass); - client.getGridPanel().repaint(); - } - - @Override - public void selectCornCircleOption() { - client.clearActions(); - createSecondPanel(CornCirclesPanel.class); - client.getGridPanel().repaint(); - } - - @SuppressWarnings("unchecked") - public T createSecondPanel(Class type) { - GridPanel grid = client.getGridPanel(); - FakeComponent panel = grid.getSecondPanel(); - if (type.isInstance(panel)) { - return (T) panel; - } - T newPanel; - try { - newPanel = type.getConstructor(Client.class).newInstance(client); - } catch (Exception e) { - // should never happen; - e.printStackTrace(); - return null; - } - newPanel.registerSwingComponents(grid); - newPanel.layoutSwingComponents(grid); - grid.setSecondPanel(newPanel); - return newPanel; - } - - @Override - public void selectBazaarTile() { - client.clearActions(); - BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); - if (client.isClientActive()) { - ArrayList supply = client.getGame().getCapability(BazaarCapability.class).getBazaarSupply(); - for (int i = 0; i < supply.size(); i++) { - // find first allowed item - if (supply.get(i).getOwner() == null) { - bazaarPanel.setSelectedItem(i); - break; - } - } - bazaarPanel.setState(BazaarPanelState.SELECT_TILE); - } else { - bazaarPanel.setState(BazaarPanelState.INACTIVE); - } - client.getGridPanel().repaint(); - } - - @Override - public void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem) { - BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); - bazaarPanel.setState(BazaarPanelState.INACTIVE); - client.getGridPanel().repaint(); - } - - @Override - public void makeBazaarBid(int supplyIndex) { - BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); - bazaarPanel.setSelectedItem(supplyIndex); - if (client.isClientActive()) { - bazaarPanel.setState(BazaarPanelState.MAKE_BID); - } else { - bazaarPanel.setState(BazaarPanelState.INACTIVE); - } - client.clearActions(); - client.getGridPanel().repaint(); - } - - @Override - public void selectBuyOrSellBazaarOffer(int supplyIndex) { - BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); - bazaarPanel.setSelectedItem(supplyIndex); - if (client.isClientActive()) { - bazaarPanel.setState(BazaarPanelState.BUY_OR_SELL); - } else { - bazaarPanel.setState(BazaarPanelState.INACTIVE); - } - } - - @Override - public void bazaarAuctionsEnded() { - client.getGridPanel().setSecondPanel(null); - } - - @Override - public void plagueSpread() { - client.getGridPanel().repaint(); - } -} +package com.jcloisterzone.ui; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Image; +import java.awt.KeyboardFocusManager; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +import javax.swing.JOptionPane; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.Player; +import com.jcloisterzone.UserInterface; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.event.GameEventListener; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Completable; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.game.capability.BazaarItem; +import com.jcloisterzone.game.capability.FlierCapability; +import com.jcloisterzone.game.phase.Phase; +import com.jcloisterzone.ui.controls.ControlPanel; +import com.jcloisterzone.ui.controls.FakeComponent; +import com.jcloisterzone.ui.dialog.DiscardedTilesDialog; +import com.jcloisterzone.ui.dialog.GameOverDialog; +import com.jcloisterzone.ui.grid.BazaarPanel; +import com.jcloisterzone.ui.grid.BazaarPanel.BazaarPanelState; +import com.jcloisterzone.ui.grid.CornCirclesPanel; +import com.jcloisterzone.ui.grid.FlierPanel; +import com.jcloisterzone.ui.grid.GridPanel; +import com.jcloisterzone.ui.grid.KeyController; +import com.jcloisterzone.ui.grid.MainPanel; +import com.jcloisterzone.ui.grid.layer.DragonAvailableMove; +import com.jcloisterzone.ui.grid.layer.DragonLayer; + +public class ClientController implements GameEventListener, UserInterface { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final Client client; + private KeyController keyController; + + public ClientController(Client client) { + this.client = client; + } + + @Override + public void updateCustomRule(CustomRule rule, Boolean enabled) { + client.getCreateGamePanel().updateCustomRule(rule, enabled); + } + + @Override + public void updateExpansion(Expansion expansion, Boolean enabled) { + client.getCreateGamePanel().updateExpansion(expansion, enabled); + } + + @Override + public void updateSlot(PlayerSlot slot) { + client.getCreateGamePanel().updateSlot(slot); + } + + @Override + public void updateSupportedExpansions(EnumSet expansions) { + client.getCreateGamePanel().updateSupportedExpansions(expansions); + } + + @Override + public void started(Snapshot snapshot) { + client.cleanContentPane(); + + Container pane = client.getContentPane(); + pane.setLayout(new BorderLayout()); + + ControlPanel controlPanel = new ControlPanel(client); + client.setControlPanel(controlPanel); + + MainPanel mainPanel = new MainPanel(client); + client.setMainPanel(mainPanel); + pane.add(mainPanel, BorderLayout.CENTER); + + mainPanel.started(snapshot); + + if (keyController == null) { + // first started game + keyController = new KeyController(client); + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keyController); + } + + pane.setVisible(true); + + MenuBar menu = client.getJMenuBar(); + menu.setZoomInEnabled(true); + menu.setZoomOutEnabled(true); + menu.setIsGameRunning(true); + } + + @Override + public void playerActivated(Player turnPlayer, Player activePlayer) { + client.setActivePlayer(activePlayer); + client.getControlPanel().playerActivated(turnPlayer, activePlayer); + + if (client.isClientActive()) { + client.beep(); + } + + // TODO better image quality ? + Color c = client.getPlayerColor(activePlayer); + Image image = client.getFigureTheme().getFigureImage(SmallFollower.class, c, null); + client.setIconImage(image); + } + + public void refreshWindowTitle() { + StringBuilder title = new StringBuilder(Client.BASE_TITLE); + Game game = client.getGame(); + if (game != null) { + Player activePlayer = game.getActivePlayer(); + if (activePlayer != null) { + title.append(" ⋅ ").append(activePlayer.getNick()); + } + int packSize = game.getTilePack().totalSize(); + title.append(" ⋅ ").append(String.format(_("%d tiles left"), packSize)); + } + client.setTitle(title.toString()); + } + + @Override + public void tileDrawn(Tile tile) { + client.clearActions(); + refreshWindowTitle(); + } + + @Override + public void tileDiscarded(Tile tile) { + DiscardedTilesDialog discardedTilesDialog = client.getDiscardedTilesDialog(); + if (discardedTilesDialog == null) { + discardedTilesDialog = new DiscardedTilesDialog(client); + client.setDiscardedTilesDialog(discardedTilesDialog); + client.getJMenuBar().setShowDiscardedEnabled(true); + } + discardedTilesDialog.addTile(tile); + discardedTilesDialog.setVisible(true); + } + + @Override + public void tilePlaced(Tile tile) { + client.getMainPanel().tilePlaced(tile); + } + + @Override + public void dragonMoved(Position p) { + client.getMainPanel().dragonMoved(p); + } + + @Override + public void tunnelPiecePlaced(Player player, Position p, Location d, boolean isSecondPiece) { + client.getMainPanel().tunnelPiecePlaced(player, p, d, isSecondPiece); + } + + @Override + public void gameOver() { + client.setTitle(Client.BASE_TITLE); + client.resetWindowIcon(); + client.closeGame(true); + new GameOverDialog(client); + } + + @Override + public void phaseEntered(Phase phase) { + GridPanel grid = client.getGridPanel(); + if (grid == null) + return; + + FlierCapability flierGame = client.getGame().getCapability(FlierCapability.class); + FlierPanel flierPanel; + boolean rollAllowed = false, rollMade = false; + if (flierGame != null) { + rollAllowed = flierGame.isFlierRollAllowed() && client.isClientActive(); + rollMade = flierGame.getFlierDistance() > 0; + } + if (rollAllowed || rollMade) { + flierPanel = createSecondPanel(FlierPanel.class); + if (rollMade) { + flierPanel.setFlierDistance(flierGame.getFlierDistance()); + } + } else { + if (grid.getSecondPanel() instanceof FlierPanel) { + grid.setSecondPanel(null); + } + } + } + + @Override + public void fairyMoved(Position p) { + client.getMainPanel().fairyMoved(p); + } + + @Override + public void towerIncreased(Position p, Integer height) { + client.clearActions(); + client.getMainPanel().towerIncreased(p, height); + } + + @Override + public void ransomPaid(Player from, Player to, Follower f) { + client.getGridPanel().repaint(); + } + + // ------------------ Meeple events ----------- + + @Override + public void deployed(Meeple m) { + client.getMainPanel().deployed(m); + } + + @Override + public void undeployed(Meeple m) { + client.getMainPanel().undeployed(m); + } + + @Override + public void bridgeDeployed(Position pos, Location loc) { + client.getMainPanel().bridgeDeployed(pos, loc); + } + + @Override + public void castleDeployed(Castle castle1, Castle castle2) { + client.getMainPanel().castleDeployed(castle1, castle2); + } + + // ------------------ Feature evnts ---------- + + @Override + public void completed(Completable feature, CompletableScoreContext ctx) { + } + + @Override + public void scored(Feature feature, int points, String label, Meeple meeple, boolean finalScoring) { + client.getMainPanel().scored(feature, label, meeple, finalScoring); + client.getMainPanel().repaint(); // players only + } + + @Override + public void scored(Position position, Player player, int points, String label, boolean finalScoring) { + client.getMainPanel().scored(position, player, label, finalScoring); + client.getMainPanel().repaint(); // players only + } + + // User interface + + @Override + public void showWarning(String title, String message) { + JOptionPane.showMessageDialog(client, message, title, JOptionPane.WARNING_MESSAGE); + } + + @Override + public void selectDragonMove(Set positions, int movesLeft) { + client.clearActions(); + DragonLayer dragonDecoration = client.getGridPanel().findDecoration(DragonLayer.class); + dragonDecoration.setMoves(movesLeft); + client.getGridPanel().repaint(); + logger.debug("UI selectdragon move, left {}, {}", movesLeft, positions); + if (client.isClientActive()) { + client.getGridPanel().addLayer(new DragonAvailableMove(client.getGridPanel(), positions)); + client.beep(); + } + } + + @Override + public void selectAction(List actions, boolean canPass) { + client.clearActions(); + client.getControlPanel().selectAction(actions, canPass); + client.getGridPanel().repaint(); + } + + @Override + public void selectCornCircleOption() { + client.clearActions(); + createSecondPanel(CornCirclesPanel.class); + client.getGridPanel().repaint(); + } + + @SuppressWarnings("unchecked") + public T createSecondPanel(Class type) { + GridPanel grid = client.getGridPanel(); + FakeComponent panel = grid.getSecondPanel(); + if (type.isInstance(panel)) { + return (T) panel; + } + T newPanel; + try { + newPanel = type.getConstructor(Client.class).newInstance(client); + } catch (Exception e) { + // should never happen; + e.printStackTrace(); + return null; + } + newPanel.registerSwingComponents(grid); + newPanel.layoutSwingComponents(grid); + grid.setSecondPanel(newPanel); + return newPanel; + } + + @Override + public void selectBazaarTile() { + client.clearActions(); + BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); + if (client.isClientActive()) { + ArrayList supply = client.getGame().getCapability(BazaarCapability.class).getBazaarSupply(); + for (int i = 0; i < supply.size(); i++) { + // find first allowed item + if (supply.get(i).getOwner() == null) { + bazaarPanel.setSelectedItem(i); + break; + } + } + bazaarPanel.setState(BazaarPanelState.SELECT_TILE); + } else { + bazaarPanel.setState(BazaarPanelState.INACTIVE); + } + client.getGridPanel().repaint(); + } + + @Override + public void bazaarTileSelected(int supplyIndex, BazaarItem bazaarItem) { + BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); + bazaarPanel.setState(BazaarPanelState.INACTIVE); + client.getGridPanel().repaint(); + } + + @Override + public void makeBazaarBid(int supplyIndex) { + BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); + bazaarPanel.setSelectedItem(supplyIndex); + if (client.isClientActive()) { + bazaarPanel.setState(BazaarPanelState.MAKE_BID); + } else { + bazaarPanel.setState(BazaarPanelState.INACTIVE); + } + client.clearActions(); + client.getGridPanel().repaint(); + } + + @Override + public void selectBuyOrSellBazaarOffer(int supplyIndex) { + BazaarPanel bazaarPanel = createSecondPanel(BazaarPanel.class); + bazaarPanel.setSelectedItem(supplyIndex); + if (client.isClientActive()) { + bazaarPanel.setState(BazaarPanelState.BUY_OR_SELL); + } else { + bazaarPanel.setState(BazaarPanelState.INACTIVE); + } + } + + @Override + public void bazaarAuctionsEnded() { + client.getGridPanel().setSecondPanel(null); + } + + @Override + public void plagueSpread() { + client.getGridPanel().repaint(); + } +} diff --git a/src/main/java/com/jcloisterzone/ui/ClientSettings.java b/src/main/java/com/jcloisterzone/ui/ClientSettings.java index 7cbb70b8e..3e5f23423 100644 --- a/src/main/java/com/jcloisterzone/ui/ClientSettings.java +++ b/src/main/java/com/jcloisterzone/ui/ClientSettings.java @@ -1,72 +1,72 @@ -package com.jcloisterzone.ui; - -import org.ini4j.Ini; -import org.ini4j.Profile.Section; - - -//TODO possible with merge config - -public class ClientSettings { - - private boolean playBeep; - private boolean confirmFarmPlacement; - private boolean confirmTowerPlacement; - private boolean confirmGameClose; - private boolean confirmRansomPayment; - - private boolean showHistory; - - public ClientSettings(Ini config) { - Section uiConfig = config.get("settings"); - playBeep = uiConfig.get("beep_alert", boolean.class); - confirmFarmPlacement = uiConfig.get("confirm_farm_place", boolean.class); - confirmTowerPlacement = uiConfig.get("confirm_tower_place", boolean.class); - confirmGameClose = uiConfig.get("confirm_game_close", boolean.class); - confirmRansomPayment = uiConfig.get("confirm_ransom_payment", boolean.class); - } - - public boolean isPlayBeep() { - return playBeep; - } - public void setPlayBeep(boolean playBeep) { - this.playBeep = playBeep; - } - public boolean isConfirmFarmPlacement() { - return confirmFarmPlacement; - } - public void setConfirmFarmPlacement(boolean confirmFarmPlacement) { - this.confirmFarmPlacement = confirmFarmPlacement; - } - public boolean isConfirmTowerPlacement() { - return confirmTowerPlacement; - } - public void setConfirmTowerPlacement(boolean confirmTowerPlacement) { - this.confirmTowerPlacement = confirmTowerPlacement; - } - - public boolean isConfirmGameClose() { - return confirmGameClose; - } - - public void setConfirmGameClose(boolean confirmGameClose) { - this.confirmGameClose = confirmGameClose; - } - - public boolean isConfirmRansomPayment() { - return confirmRansomPayment; - } - - public void setConfirmRansomPayment(boolean confirmRansomPayment) { - this.confirmRansomPayment = confirmRansomPayment; - } - - public boolean isShowHistory() { - return showHistory; - } - - public void setShowHistory(boolean showHistory) { - this.showHistory = showHistory; - } - - -} +package com.jcloisterzone.ui; + +import org.ini4j.Ini; +import org.ini4j.Profile.Section; + + +//TODO possible with merge config + +public class ClientSettings { + + private boolean playBeep; + private boolean confirmFarmPlacement; + private boolean confirmTowerPlacement; + private boolean confirmGameClose; + private boolean confirmRansomPayment; + + private boolean showHistory; + + public ClientSettings(Ini config) { + Section uiConfig = config.get("settings"); + playBeep = uiConfig.get("beep_alert", boolean.class); + confirmFarmPlacement = uiConfig.get("confirm_farm_place", boolean.class); + confirmTowerPlacement = uiConfig.get("confirm_tower_place", boolean.class); + confirmGameClose = uiConfig.get("confirm_game_close", boolean.class); + confirmRansomPayment = uiConfig.get("confirm_ransom_payment", boolean.class); + } + + public boolean isPlayBeep() { + return playBeep; + } + public void setPlayBeep(boolean playBeep) { + this.playBeep = playBeep; + } + public boolean isConfirmFarmPlacement() { + return confirmFarmPlacement; + } + public void setConfirmFarmPlacement(boolean confirmFarmPlacement) { + this.confirmFarmPlacement = confirmFarmPlacement; + } + public boolean isConfirmTowerPlacement() { + return confirmTowerPlacement; + } + public void setConfirmTowerPlacement(boolean confirmTowerPlacement) { + this.confirmTowerPlacement = confirmTowerPlacement; + } + + public boolean isConfirmGameClose() { + return confirmGameClose; + } + + public void setConfirmGameClose(boolean confirmGameClose) { + this.confirmGameClose = confirmGameClose; + } + + public boolean isConfirmRansomPayment() { + return confirmRansomPayment; + } + + public void setConfirmRansomPayment(boolean confirmRansomPayment) { + this.confirmRansomPayment = confirmRansomPayment; + } + + public boolean isShowHistory() { + return showHistory; + } + + public void setShowHistory(boolean showHistory) { + this.showHistory = showHistory; + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/I18nUtils.java b/src/main/java/com/jcloisterzone/ui/I18nUtils.java index c38743e7b..5fd75a0e2 100644 --- a/src/main/java/com/jcloisterzone/ui/I18nUtils.java +++ b/src/main/java/com/jcloisterzone/ui/I18nUtils.java @@ -1,30 +1,30 @@ -package com.jcloisterzone.ui; - -import java.util.Locale; -import java.util.MissingResourceException; - -import org.xnap.commons.i18n.I18n; -import org.xnap.commons.i18n.I18nFactory; - -public class I18nUtils { - - private static I18n i18n; - private static Locale locale = Locale.getDefault(); - - public static String _(String s, Object... args) { - if (i18n == null) { - try { - i18n = I18nFactory.getI18n(Client.class, "Messages", locale); - } catch (MissingResourceException ex) { - i18n = I18nFactory.getI18n(Client.class, "Messages", Locale.ENGLISH, I18nFactory.FALLBACK); - } - } - return i18n.tr(s, args); - } - - public static void setLocale(Locale locale) { - I18nUtils.locale = locale; - i18n = null; - } - -} +package com.jcloisterzone.ui; + +import java.util.Locale; +import java.util.MissingResourceException; + +import org.xnap.commons.i18n.I18n; +import org.xnap.commons.i18n.I18nFactory; + +public class I18nUtils { + + private static I18n i18n; + private static Locale locale = Locale.getDefault(); + + public static String _(String s, Object... args) { + if (i18n == null) { + try { + i18n = I18nFactory.getI18n(Client.class, "Messages", locale); + } catch (MissingResourceException ex) { + i18n = I18nFactory.getI18n(Client.class, "Messages", Locale.ENGLISH, I18nFactory.FALLBACK); + } + } + return i18n.tr(s, args); + } + + public static void setLocale(Locale locale) { + I18nUtils.locale = locale; + i18n = null; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/ImmutablePoint.java b/src/main/java/com/jcloisterzone/ui/ImmutablePoint.java index 1fa2b1e4d..f4ec7907d 100644 --- a/src/main/java/com/jcloisterzone/ui/ImmutablePoint.java +++ b/src/main/java/com/jcloisterzone/ui/ImmutablePoint.java @@ -1,91 +1,91 @@ -package com.jcloisterzone.ui; - -import com.jcloisterzone.board.Rotation; - -//import java.util.WeakHashMap; - -public class ImmutablePoint { - - private final int x; - private final int y; - - public ImmutablePoint(int x, int y) { - this.x = x; - this.y = y; - } - - /*static public ImmutablePoint newInstance(int x, int y) { - return new ImmutablePoint(x,y); - }*/ - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public ImmutablePoint scale(int squareSize) { - return scale(squareSize, 0, 0); - } - - public ImmutablePoint scale(int squareSize, int boxSize) { - return scale(squareSize, boxSize,boxSize); - } - - public ImmutablePoint scale(int squareSize, int xSize, int ySize) { - return new ImmutablePoint( - (int) (squareSize * (x / 100.0)) - - xSize / 2, - - (int) (squareSize * (y / 100.0)) - - ySize / 2); - } - - public ImmutablePoint mirrorX() { - return new ImmutablePoint(100-x,y); - } - public ImmutablePoint mirrorY() { - return new ImmutablePoint(x,100-y); - } - public ImmutablePoint rotate() { - return new ImmutablePoint(100-y,x); - } - - /** - * Rotates ImmutablePoint on initial sized tile. - * @param p ImmutablePoint to rotate - * @param d how roatate - * @return rotated ImmutablePoint - */ - //TODO create only one instance - public ImmutablePoint rotate(Rotation r) { - ImmutablePoint ip = this; - for (int i = 0; i < r.ordinal(); i++) { - ip = ip.rotate(); - } - return ip; - } - - public ImmutablePoint translate(int dx, int dy) { - return new ImmutablePoint(x + dx, y + dy); - } - - @Override - public int hashCode() { - return (x << 16) ^ y; - } - @Override - public boolean equals(Object obj) { - if (obj instanceof ImmutablePoint) { - ImmutablePoint p = (ImmutablePoint)obj; - return (x == p.x) && (y == p.y); - } - return false; - } - - public String toString() { - return getClass().getName() + "[x=" + x + ",y=" + y + "]"; - } +package com.jcloisterzone.ui; + +import com.jcloisterzone.board.Rotation; + +//import java.util.WeakHashMap; + +public class ImmutablePoint { + + private final int x; + private final int y; + + public ImmutablePoint(int x, int y) { + this.x = x; + this.y = y; + } + + /*static public ImmutablePoint newInstance(int x, int y) { + return new ImmutablePoint(x,y); + }*/ + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public ImmutablePoint scale(int squareSize) { + return scale(squareSize, 0, 0); + } + + public ImmutablePoint scale(int squareSize, int boxSize) { + return scale(squareSize, boxSize,boxSize); + } + + public ImmutablePoint scale(int squareSize, int xSize, int ySize) { + return new ImmutablePoint( + (int) (squareSize * (x / 100.0)) + - xSize / 2, + + (int) (squareSize * (y / 100.0)) + - ySize / 2); + } + + public ImmutablePoint mirrorX() { + return new ImmutablePoint(100-x,y); + } + public ImmutablePoint mirrorY() { + return new ImmutablePoint(x,100-y); + } + public ImmutablePoint rotate() { + return new ImmutablePoint(100-y,x); + } + + /** + * Rotates ImmutablePoint on initial sized tile. + * @param p ImmutablePoint to rotate + * @param d how roatate + * @return rotated ImmutablePoint + */ + //TODO create only one instance + public ImmutablePoint rotate(Rotation r) { + ImmutablePoint ip = this; + for (int i = 0; i < r.ordinal(); i++) { + ip = ip.rotate(); + } + return ip; + } + + public ImmutablePoint translate(int dx, int dy) { + return new ImmutablePoint(x + dx, y + dy); + } + + @Override + public int hashCode() { + return (x << 16) ^ y; + } + @Override + public boolean equals(Object obj) { + if (obj instanceof ImmutablePoint) { + ImmutablePoint p = (ImmutablePoint)obj; + return (x == p.x) && (y == p.y); + } + return false; + } + + public String toString() { + return getClass().getName() + "[x=" + x + ",y=" + y + "]"; + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/InvokeInSwingUiAdapter.java b/src/main/java/com/jcloisterzone/ui/InvokeInSwingUiAdapter.java index 3ecfd7902..85a5e0b12 100644 --- a/src/main/java/com/jcloisterzone/ui/InvokeInSwingUiAdapter.java +++ b/src/main/java/com/jcloisterzone/ui/InvokeInSwingUiAdapter.java @@ -1,88 +1,88 @@ -package com.jcloisterzone.ui; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.swing.SwingUtilities; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Function; -import com.jcloisterzone.figure.Figure; - - -public class InvokeInSwingUiAdapter implements InvocationHandler { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final ClientController controller; - - public InvokeInSwingUiAdapter(ClientController client) { - this.controller = client; - } - - @Override - public Object invoke(Object proxy, final Method method, final Object[] args) { - freezeArgs(method, args); - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - try { - method.invoke(controller, args); - } catch (InvocationTargetException ie) { - logger.error("Cannot invoke method " + method.toString() + " (probably bug in freezeArgs())", ie.getCause()); - } catch (Exception e) { - logger.error("Method " + method.toString() + " (probably bug in freezeArgs())", e); - } - } - }); - return null; - } - - @SuppressWarnings("rawtypes") - private void freezeArgs(Method method, Object[] args) { - if (args == null) return; - for (int i = 0; i < args.length; i++) { - if (args[i] instanceof Figure) { - args[i] = ((Figure) args[i]).clone(); - } - if (args[i] instanceof Collection) { - if (args[i] instanceof EnumSet) continue; //do not modify Enum set - //Class paramType = method.getParameterTypes()[i]; - FigureCloningFunction func = new FigureCloningFunction(); - if (args[i] instanceof List) { - List list = new ArrayList(((List) args[i]).size()); - for (Object obj : (List) args[i]) { - list.add(func.apply(obj)); - } - args[i] = list; - } else if (args[i] instanceof Set) { - Set set = new HashSet<>(((Set) args[i]).size()); - for (Object obj : (Set) args[i]) { - set.add(func.apply(obj)); - } - args[i] = set; - } - //for map do nothing - } - } - } - - private class FigureCloningFunction implements Function { - @Override - public Object apply(Object from) { - if (from instanceof Figure) { - return ((Figure) from).clone(); - } - return from; - } - } -} +package com.jcloisterzone.ui; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.swing.SwingUtilities; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Function; +import com.jcloisterzone.figure.Figure; + + +public class InvokeInSwingUiAdapter implements InvocationHandler { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final ClientController controller; + + public InvokeInSwingUiAdapter(ClientController client) { + this.controller = client; + } + + @Override + public Object invoke(Object proxy, final Method method, final Object[] args) { + freezeArgs(method, args); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + try { + method.invoke(controller, args); + } catch (InvocationTargetException ie) { + logger.error("Cannot invoke method " + method.toString() + " (probably bug in freezeArgs())", ie.getCause()); + } catch (Exception e) { + logger.error("Method " + method.toString() + " (probably bug in freezeArgs())", e); + } + } + }); + return null; + } + + @SuppressWarnings("rawtypes") + private void freezeArgs(Method method, Object[] args) { + if (args == null) return; + for (int i = 0; i < args.length; i++) { + if (args[i] instanceof Figure) { + args[i] = ((Figure) args[i]).clone(); + } + if (args[i] instanceof Collection) { + if (args[i] instanceof EnumSet) continue; //do not modify Enum set + //Class paramType = method.getParameterTypes()[i]; + FigureCloningFunction func = new FigureCloningFunction(); + if (args[i] instanceof List) { + List list = new ArrayList(((List) args[i]).size()); + for (Object obj : (List) args[i]) { + list.add(func.apply(obj)); + } + args[i] = list; + } else if (args[i] instanceof Set) { + Set set = new HashSet<>(((Set) args[i]).size()); + for (Object obj : (Set) args[i]) { + set.add(func.apply(obj)); + } + args[i] = set; + } + //for map do nothing + } + } + } + + private class FigureCloningFunction implements Function { + @Override + public Object apply(Object from) { + if (from instanceof Figure) { + return ((Figure) from).clone(); + } + return from; + } + } +} diff --git a/src/main/java/com/jcloisterzone/ui/JLabelAntialised.java b/src/main/java/com/jcloisterzone/ui/JLabelAntialised.java index 0403e2de1..449318342 100644 --- a/src/main/java/com/jcloisterzone/ui/JLabelAntialised.java +++ b/src/main/java/com/jcloisterzone/ui/JLabelAntialised.java @@ -1,31 +1,31 @@ -package com.jcloisterzone.ui; - -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; - -import javax.swing.JLabel; - -public class JLabelAntialised extends JLabel { - - private static final long serialVersionUID = -619469286371707527L; - - public JLabelAntialised() { - super(); - } - - public JLabelAntialised(String text) { - super(text); - } - - public JLabelAntialised(String text, int horizontalAlignment) { - super(text, horizontalAlignment); - } - - @Override - public void paint(Graphics g) { - ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - super.paint(g); - } - -} +package com.jcloisterzone.ui; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; + +import javax.swing.JLabel; + +public class JLabelAntialised extends JLabel { + + private static final long serialVersionUID = -619469286371707527L; + + public JLabelAntialised() { + super(); + } + + public JLabelAntialised(String text) { + super(text); + } + + public JLabelAntialised(String text, int horizontalAlignment) { + super(text, horizontalAlignment); + } + + @Override + public void paint(Graphics g) { + ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + super.paint(g); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/MenuBar.java b/src/main/java/com/jcloisterzone/ui/MenuBar.java index 132c73e76..be04c3a7d 100644 --- a/src/main/java/com/jcloisterzone/ui/MenuBar.java +++ b/src/main/java/com/jcloisterzone/ui/MenuBar.java @@ -1,287 +1,287 @@ -package com.jcloisterzone.ui; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; - -import javax.swing.JCheckBoxMenuItem; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.KeyStroke; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.ui.dialog.HelpDialog; -import com.jcloisterzone.ui.grid.layer.PlacementHistory; - -@SuppressWarnings("serial") -public class MenuBar extends JMenuBar { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final Client client; - private boolean isGameRunning = false; - - private JMenuItem create, connect, close, showDiscard, save, load; - private JMenuItem zoomIn, zoomOut; - private JMenuItem history; - - public MenuBar(Client client2) { - this.client = client2; - - boolean isMac = Bootstrap.isMac(); - - JMenu menu; - JMenuItem menuItem; - - //menu.getAccessibleContext().setAccessibleDescription( - //"The only menu in this program that has menu items"); - - menu = new JMenu(_("Game")); - menu.setMnemonic(KeyEvent.VK_G); - create = new JMenuItem(_("New game")); - create.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - create.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.createGame(); - } - }); - menu.add(create); - - connect = new JMenuItem(_("Connect")); - connect.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - connect.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.showConnectGamePanel(); - } - }); - menu.add(connect); - - close = new JMenuItem(_("Close game")); - close.setEnabled(false); - close.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.closeGame(); - } - }); - menu.add(close); - - - menu.addSeparator(); - - save = new JMenuItem(_("Save")); - save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - save.setEnabled(false); - save.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.handleSave(); - } - }); - menu.add(save); - - load = new JMenuItem(_("Load")); - load.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - load.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.handleLoad(); - } - }); - menu.add(load); - - if (!isMac) { - menu.addSeparator(); - - menuItem = new JMenuItem(_("Quit")); - menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.handleQuit(); - } - }); - menu.add(menuItem); - } - - this.add(menu); - - - menu = new JMenu(_("Window")); - zoomIn = new JMenuItem(_("Zoom in")); - zoomIn.setAccelerator(KeyStroke.getKeyStroke('+')); //only show key code, handled by KeyController - zoomIn.setEnabled(false); - zoomIn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.getGridPanel().zoom(2.0); - } - }); - menu.add(zoomIn); - zoomOut = new JMenuItem(_("Zoom out")); - zoomOut.setAccelerator(KeyStroke.getKeyStroke('-')); //only show key code, handled by KeyController - zoomOut.setEnabled(false); - zoomOut.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.getGridPanel().zoom(-2.0); - } - }); - menu.add(zoomOut); - -// menuItem = new JMenuItem(_("FullScreen")); -// menuItem.addActionListener(new ActionListener() { -// public void actionPerformed(ActionEvent e) { -// //fullScreen(); -// throw new UnsupportedOperationException(); -// } -// }); -// /*if (!GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isFullScreenSupported()) { -// menuItem.setEnabled(false); -// }*/ -// menuItem.setEnabled(false); -// menu.add(menuItem); - - menu.addSeparator(); - history = new JCheckBoxMenuItem(_("Show last placements")); - history.setAccelerator(KeyStroke.getKeyStroke('x')); - history.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JCheckBoxMenuItem ch = (JCheckBoxMenuItem) e.getSource(); - client.getSettings().setShowHistory(ch.isSelected()); - if (ch.isSelected()) { - client.getGridPanel().showRecentHistory(); - } else { - client.getGridPanel().removeLayer(PlacementHistory.class); - } - } - }); - menu.add(history); - - - showDiscard = new JMenuItem(_("Show discarded tiles")); - showDiscard.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); - showDiscard.setEnabled(false); - showDiscard.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.getDiscardedTilesDialog().setVisible(true); - } - }); - menu.add(showDiscard); - - - this.add(menu); - - menu = new JMenu(_("Settings")); - menuItem = new JCheckBoxMenuItem(_("Beep alert at player turn")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); - client.getSettings().setPlayBeep(state); - } - }); - ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isPlayBeep()); - menu.add(menuItem); - - menu.addSeparator(); - - menuItem = new JCheckBoxMenuItem(_("Confirm placement on a farm")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); - client.getSettings().setConfirmFarmPlacement(state); - } - }); - ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmFarmPlacement()); - menu.add(menuItem); - menuItem = new JCheckBoxMenuItem(_("Confirm placement on a tower")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); - client.getSettings().setConfirmTowerPlacement(state); - } - }); - ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmTowerPlacement()); - menu.add(menuItem); - menuItem = new JCheckBoxMenuItem(_("Confirm ransom payment")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); - client.getSettings().setConfirmRansomPayment(state); - } - }); - ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmTowerPlacement()); - menu.add(menuItem); - - menu.addSeparator(); - - menuItem = new JCheckBoxMenuItem(_("Confirm game close")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); - client.getSettings().setConfirmGameClose(state); - } - }); - ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmGameClose()); - menu.add(menuItem); - - this.add(menu); - - menu = new JMenu(_("Help")); - - if (!isMac) { - - menuItem = new JMenuItem(_("About")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.handleAbout(); - } - }); - menu.add(menuItem); - - } - - menuItem = new JMenuItem(_("Controls")); - menuItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - new HelpDialog(); - } - }); - menu.add(menuItem); - - this.add(menu); - - } - - //legacy methods - TODO refactor - - public void setZoomInEnabled(boolean state) { - zoomIn.setEnabled(state); - } - public void setZoomOutEnabled(boolean state) { - zoomOut.setEnabled(state); - } - - public void setIsGameRunning(boolean isGameRunning) { - this.isGameRunning = isGameRunning; - create.setEnabled(!isGameRunning); - connect.setEnabled(!isGameRunning); - close.setEnabled(isGameRunning); - if (!isGameRunning) { - showDiscard.setEnabled(false); - } - save.setEnabled(isGameRunning); - } - - public boolean isGameRunning() { - return isGameRunning; - } - - public void setShowDiscardedEnabled(boolean enabled) { - showDiscard.setEnabled(enabled); - } - - - - -} +package com.jcloisterzone.ui; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.KeyStroke; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.ui.dialog.HelpDialog; +import com.jcloisterzone.ui.grid.layer.PlacementHistory; + +@SuppressWarnings("serial") +public class MenuBar extends JMenuBar { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final Client client; + private boolean isGameRunning = false; + + private JMenuItem create, connect, close, showDiscard, save, load; + private JMenuItem zoomIn, zoomOut; + private JMenuItem history; + + public MenuBar(Client client2) { + this.client = client2; + + boolean isMac = Bootstrap.isMac(); + + JMenu menu; + JMenuItem menuItem; + + //menu.getAccessibleContext().setAccessibleDescription( + //"The only menu in this program that has menu items"); + + menu = new JMenu(_("Game")); + menu.setMnemonic(KeyEvent.VK_G); + create = new JMenuItem(_("New game")); + create.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + create.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.createGame(); + } + }); + menu.add(create); + + connect = new JMenuItem(_("Connect")); + connect.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + connect.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.showConnectGamePanel(); + } + }); + menu.add(connect); + + close = new JMenuItem(_("Close game")); + close.setEnabled(false); + close.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.closeGame(); + } + }); + menu.add(close); + + + menu.addSeparator(); + + save = new JMenuItem(_("Save")); + save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + save.setEnabled(false); + save.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.handleSave(); + } + }); + menu.add(save); + + load = new JMenuItem(_("Load")); + load.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + load.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.handleLoad(); + } + }); + menu.add(load); + + if (!isMac) { + menu.addSeparator(); + + menuItem = new JMenuItem(_("Quit")); + menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.handleQuit(); + } + }); + menu.add(menuItem); + } + + this.add(menu); + + + menu = new JMenu(_("Window")); + zoomIn = new JMenuItem(_("Zoom in")); + zoomIn.setAccelerator(KeyStroke.getKeyStroke('+')); //only show key code, handled by KeyController + zoomIn.setEnabled(false); + zoomIn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.getGridPanel().zoom(2.0); + } + }); + menu.add(zoomIn); + zoomOut = new JMenuItem(_("Zoom out")); + zoomOut.setAccelerator(KeyStroke.getKeyStroke('-')); //only show key code, handled by KeyController + zoomOut.setEnabled(false); + zoomOut.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.getGridPanel().zoom(-2.0); + } + }); + menu.add(zoomOut); + +// menuItem = new JMenuItem(_("FullScreen")); +// menuItem.addActionListener(new ActionListener() { +// public void actionPerformed(ActionEvent e) { +// //fullScreen(); +// throw new UnsupportedOperationException(); +// } +// }); +// /*if (!GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isFullScreenSupported()) { +// menuItem.setEnabled(false); +// }*/ +// menuItem.setEnabled(false); +// menu.add(menuItem); + + menu.addSeparator(); + history = new JCheckBoxMenuItem(_("Show last placements")); + history.setAccelerator(KeyStroke.getKeyStroke('x')); + history.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + JCheckBoxMenuItem ch = (JCheckBoxMenuItem) e.getSource(); + client.getSettings().setShowHistory(ch.isSelected()); + if (ch.isSelected()) { + client.getGridPanel().showRecentHistory(); + } else { + client.getGridPanel().removeLayer(PlacementHistory.class); + } + } + }); + menu.add(history); + + + showDiscard = new JMenuItem(_("Show discarded tiles")); + showDiscard.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + showDiscard.setEnabled(false); + showDiscard.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.getDiscardedTilesDialog().setVisible(true); + } + }); + menu.add(showDiscard); + + + this.add(menu); + + menu = new JMenu(_("Settings")); + menuItem = new JCheckBoxMenuItem(_("Beep alert at player turn")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); + client.getSettings().setPlayBeep(state); + } + }); + ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isPlayBeep()); + menu.add(menuItem); + + menu.addSeparator(); + + menuItem = new JCheckBoxMenuItem(_("Confirm placement on a farm")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); + client.getSettings().setConfirmFarmPlacement(state); + } + }); + ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmFarmPlacement()); + menu.add(menuItem); + menuItem = new JCheckBoxMenuItem(_("Confirm placement on a tower")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); + client.getSettings().setConfirmTowerPlacement(state); + } + }); + ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmTowerPlacement()); + menu.add(menuItem); + menuItem = new JCheckBoxMenuItem(_("Confirm ransom payment")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); + client.getSettings().setConfirmRansomPayment(state); + } + }); + ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmTowerPlacement()); + menu.add(menuItem); + + menu.addSeparator(); + + menuItem = new JCheckBoxMenuItem(_("Confirm game close")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + boolean state = ((JCheckBoxMenuItem) e.getSource()).getState(); + client.getSettings().setConfirmGameClose(state); + } + }); + ((JCheckBoxMenuItem)menuItem).setSelected(client.getSettings().isConfirmGameClose()); + menu.add(menuItem); + + this.add(menu); + + menu = new JMenu(_("Help")); + + if (!isMac) { + + menuItem = new JMenuItem(_("About")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.handleAbout(); + } + }); + menu.add(menuItem); + + } + + menuItem = new JMenuItem(_("Controls")); + menuItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + new HelpDialog(); + } + }); + menu.add(menuItem); + + this.add(menu); + + } + + //legacy methods - TODO refactor + + public void setZoomInEnabled(boolean state) { + zoomIn.setEnabled(state); + } + public void setZoomOutEnabled(boolean state) { + zoomOut.setEnabled(state); + } + + public void setIsGameRunning(boolean isGameRunning) { + this.isGameRunning = isGameRunning; + create.setEnabled(!isGameRunning); + connect.setEnabled(!isGameRunning); + close.setEnabled(isGameRunning); + if (!isGameRunning) { + showDiscard.setEnabled(false); + } + save.setEnabled(isGameRunning); + } + + public boolean isGameRunning() { + return isGameRunning; + } + + public void setShowDiscardedEnabled(boolean enabled) { + showDiscard.setEnabled(enabled); + } + + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/MultiLineLabel.java b/src/main/java/com/jcloisterzone/ui/MultiLineLabel.java index e58d7f18f..daa576626 100644 --- a/src/main/java/com/jcloisterzone/ui/MultiLineLabel.java +++ b/src/main/java/com/jcloisterzone/ui/MultiLineLabel.java @@ -1,32 +1,32 @@ -package com.jcloisterzone.ui; - -import java.awt.Font; - -import javax.swing.JLabel; -import javax.swing.JTextArea; - -public class MultiLineLabel extends JTextArea { - - private static final long serialVersionUID = 3195043205605956817L; - - private static Font font = (new JLabel()).getFont(); //TODO without label - - public MultiLineLabel() { - super(); - initialize(); - } - - public MultiLineLabel(String text) { - super(text); - initialize(); - } - - private void initialize() { - setEditable(false); - setOpaque(false); - setFont(font); - setLineWrap(true); - setWrapStyleWord(true); - } - -} +package com.jcloisterzone.ui; + +import java.awt.Font; + +import javax.swing.JLabel; +import javax.swing.JTextArea; + +public class MultiLineLabel extends JTextArea { + + private static final long serialVersionUID = 3195043205605956817L; + + private static Font font = (new JLabel()).getFont(); //TODO without label + + public MultiLineLabel() { + super(); + initialize(); + } + + public MultiLineLabel(String text) { + super(text); + initialize(); + } + + private void initialize() { + setEditable(false); + setOpaque(false); + setFont(font); + setLineWrap(true); + setWrapStyleWord(true); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/SavegameFileFilter.java b/src/main/java/com/jcloisterzone/ui/SavegameFileFilter.java index 5cb39f794..a478c89d8 100644 --- a/src/main/java/com/jcloisterzone/ui/SavegameFileFilter.java +++ b/src/main/java/com/jcloisterzone/ui/SavegameFileFilter.java @@ -1,22 +1,22 @@ -package com.jcloisterzone.ui; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.io.File; - -import javax.swing.filechooser.FileFilter; - -public class SavegameFileFilter extends FileFilter { - - @Override - public boolean accept(File f) { - return f.getName().toLowerCase().endsWith(".jcz") || f.isDirectory(); - } - - @Override - public String getDescription() { - return _("JCloisterZone saved games"); - } - - -} +package com.jcloisterzone.ui; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.io.File; + +import javax.swing.filechooser.FileFilter; + +public class SavegameFileFilter extends FileFilter { + + @Override + public boolean accept(File f) { + return f.getName().toLowerCase().endsWith(".jcz") || f.isDirectory(); + } + + @Override + public String getDescription() { + return _("JCloisterZone saved games"); + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/UiUtils.java b/src/main/java/com/jcloisterzone/ui/UiUtils.java index 88983f156..48d49097b 100644 --- a/src/main/java/com/jcloisterzone/ui/UiUtils.java +++ b/src/main/java/com/jcloisterzone/ui/UiUtils.java @@ -1,25 +1,25 @@ -package com.jcloisterzone.ui; - -import java.awt.Color; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsEnvironment; -import java.awt.Transparency; -import java.awt.image.BufferedImage; - -public final class UiUtils { - - private static GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment - .getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); - - private UiUtils() {} - - public static BufferedImage newTransparentImage(int w, int h) { - return graphicsConfiguration.createCompatibleImage(w, h, Transparency.TRANSLUCENT); - } - - public static boolean isBrightColor(Color c) { - return c.getRed() > 192 && c.getGreen() > 192 && c.getBlue() < 64; - } - - -} +package com.jcloisterzone.ui; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Transparency; +import java.awt.image.BufferedImage; + +public final class UiUtils { + + private static GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment + .getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + + private UiUtils() {} + + public static BufferedImage newTransparentImage(int w, int h) { + return graphicsConfiguration.createCompatibleImage(w, h, Transparency.TRANSLUCENT); + } + + public static boolean isBrightColor(Color c) { + return c.getRed() > 192 && c.getGreen() > 192 && c.getBlue() < 64; + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/animation/AbstractAnimation.java b/src/main/java/com/jcloisterzone/ui/animation/AbstractAnimation.java index 71eb5d52e..116d5dbf5 100644 --- a/src/main/java/com/jcloisterzone/ui/animation/AbstractAnimation.java +++ b/src/main/java/com/jcloisterzone/ui/animation/AbstractAnimation.java @@ -1,34 +1,34 @@ -package com.jcloisterzone.ui.animation; - -import java.util.concurrent.Delayed; -import java.util.concurrent.TimeUnit; - - -public abstract class AbstractAnimation implements Animation { - - protected long nextFrame; - - public long getDelay(TimeUnit unit) { - assert unit == TimeUnit.NANOSECONDS; - return (nextFrame - System.currentTimeMillis()) * 1000000 ; - } - - public long getNextFrameTs() { - return nextFrame; - } - - public int compareTo(Delayed o) { - long aTs = ((Animation) o).getNextFrameTs(); - if (nextFrame < aTs) return -1; - if (nextFrame > aTs) return 1; - return 0; - } - - @Override - public boolean switchFrame() { - return false; - } - - - -} +package com.jcloisterzone.ui.animation; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + + +public abstract class AbstractAnimation implements Animation { + + protected long nextFrame; + + public long getDelay(TimeUnit unit) { + assert unit == TimeUnit.NANOSECONDS; + return (nextFrame - System.currentTimeMillis()) * 1000000 ; + } + + public long getNextFrameTs() { + return nextFrame; + } + + public int compareTo(Delayed o) { + long aTs = ((Animation) o).getNextFrameTs(); + if (nextFrame < aTs) return -1; + if (nextFrame > aTs) return 1; + return 0; + } + + @Override + public boolean switchFrame() { + return false; + } + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/animation/Animation.java b/src/main/java/com/jcloisterzone/ui/animation/Animation.java index fcee76329..afefd8ae4 100644 --- a/src/main/java/com/jcloisterzone/ui/animation/Animation.java +++ b/src/main/java/com/jcloisterzone/ui/animation/Animation.java @@ -1,16 +1,16 @@ -package com.jcloisterzone.ui.animation; - -import java.awt.Graphics2D; -import java.util.concurrent.Delayed; - -import com.jcloisterzone.ui.grid.layer.AnimationLayer; - - -public interface Animation extends Delayed { - - long getNextFrameTs(); - boolean switchFrame(); - - void paint(AnimationLayer service, Graphics2D g2); - -} +package com.jcloisterzone.ui.animation; + +import java.awt.Graphics2D; +import java.util.concurrent.Delayed; + +import com.jcloisterzone.ui.grid.layer.AnimationLayer; + + +public interface Animation extends Delayed { + + long getNextFrameTs(); + boolean switchFrame(); + + void paint(AnimationLayer service, Graphics2D g2); + +} diff --git a/src/main/java/com/jcloisterzone/ui/animation/AnimationService.java b/src/main/java/com/jcloisterzone/ui/animation/AnimationService.java index cf00afe2b..f6c31eaa5 100644 --- a/src/main/java/com/jcloisterzone/ui/animation/AnimationService.java +++ b/src/main/java/com/jcloisterzone/ui/animation/AnimationService.java @@ -1,60 +1,60 @@ -package com.jcloisterzone.ui.animation; - -import java.util.concurrent.DelayQueue; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class AnimationService extends Thread { - - private DelayQueue animations = new DelayQueue(); - - public static final int SLEEP = 200; - - private GridPanel gridPanel; - - public AnimationService() { - super("AnimationService"); - setDaemon(true); - } - - public void registerAnimation(Position pos, Animation a) { - animations.add(a); - gridPanel.repaint(); - - } - - public DelayQueue getAnimations() { - return animations; - } - - - public void clearAll() { - animations.clear(); - } - - public void run() { - for (;;) { - try { - Animation an = animations.take(); - if (an.switchFrame()) { - animations.add(an); - } - if (gridPanel != null) { - gridPanel.repaint(); - } - } catch (InterruptedException e) { - //empty - } - } - } - - public void setGridPanel(GridPanel gridPanel) { - this.gridPanel = gridPanel; - } - - - - -} +package com.jcloisterzone.ui.animation; + +import java.util.concurrent.DelayQueue; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class AnimationService extends Thread { + + private DelayQueue animations = new DelayQueue(); + + public static final int SLEEP = 200; + + private GridPanel gridPanel; + + public AnimationService() { + super("AnimationService"); + setDaemon(true); + } + + public void registerAnimation(Position pos, Animation a) { + animations.add(a); + gridPanel.repaint(); + + } + + public DelayQueue getAnimations() { + return animations; + } + + + public void clearAll() { + animations.clear(); + } + + public void run() { + for (;;) { + try { + Animation an = animations.take(); + if (an.switchFrame()) { + animations.add(an); + } + if (gridPanel != null) { + gridPanel.repaint(); + } + } catch (InterruptedException e) { + //empty + } + } + } + + public void setGridPanel(GridPanel gridPanel) { + this.gridPanel = gridPanel; + } + + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/animation/RecentPlacement.java b/src/main/java/com/jcloisterzone/ui/animation/RecentPlacement.java index e7ea49b24..b8ce3f4bb 100644 --- a/src/main/java/com/jcloisterzone/ui/animation/RecentPlacement.java +++ b/src/main/java/com/jcloisterzone/ui/animation/RecentPlacement.java @@ -1,45 +1,45 @@ -package com.jcloisterzone.ui.animation; - -import java.awt.Color; -import java.awt.Graphics2D; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.layer.AnimationLayer; - -public class RecentPlacement extends AbstractAnimation { - - private static final int FRAME_DURATION = 75; - private static final int ALPHA_STEP = 8; - - private int alpha = 24 * ALPHA_STEP; - private Color color; - - private Position position; - - - public RecentPlacement(Position position) { - this.position = position; - nextFrame = System.currentTimeMillis() + FRAME_DURATION; - color = createColor(); - } - - private Color createColor() { - return new Color(0,0,0,alpha); - } - - public boolean switchFrame() { - alpha -= ALPHA_STEP; - if (alpha <= 0) { - return false; - } - color = createColor(); - nextFrame += FRAME_DURATION; - return true; - } - - @Override - public void paint(AnimationLayer l, Graphics2D g) { - g.setColor(color); - g.fillRect(l.getOffsetX(position), l.getOffsetY(position), l.getSquareSize(), l.getSquareSize()); - } -} +package com.jcloisterzone.ui.animation; + +import java.awt.Color; +import java.awt.Graphics2D; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.layer.AnimationLayer; + +public class RecentPlacement extends AbstractAnimation { + + private static final int FRAME_DURATION = 75; + private static final int ALPHA_STEP = 8; + + private int alpha = 24 * ALPHA_STEP; + private Color color; + + private Position position; + + + public RecentPlacement(Position position) { + this.position = position; + nextFrame = System.currentTimeMillis() + FRAME_DURATION; + color = createColor(); + } + + private Color createColor() { + return new Color(0,0,0,alpha); + } + + public boolean switchFrame() { + alpha -= ALPHA_STEP; + if (alpha <= 0) { + return false; + } + color = createColor(); + nextFrame += FRAME_DURATION; + return true; + } + + @Override + public void paint(AnimationLayer l, Graphics2D g) { + g.setColor(color); + g.fillRect(l.getOffsetX(position), l.getOffsetY(position), l.getSquareSize(), l.getSquareSize()); + } +} diff --git a/src/main/java/com/jcloisterzone/ui/animation/ScoreAnimation.java b/src/main/java/com/jcloisterzone/ui/animation/ScoreAnimation.java index 76b70e6ef..60664f6f1 100644 --- a/src/main/java/com/jcloisterzone/ui/animation/ScoreAnimation.java +++ b/src/main/java/com/jcloisterzone/ui/animation/ScoreAnimation.java @@ -1,48 +1,48 @@ -package com.jcloisterzone.ui.animation; - -import java.awt.Color; -import java.awt.Graphics2D; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.UiUtils; -import com.jcloisterzone.ui.grid.layer.AnimationLayer; - - -public class ScoreAnimation extends AbstractAnimation { - - private static final Color POINTS_BLACK_BACKGROUND_COLOR = new Color(0.0f, 0.0f, 0.0f, 0.7f); - private static final Color POINTS_BACKGROUND_COLOR = new Color(1.0f, 1.0f, 1.0f, 0.7f); - - private Position tilePosition; - private String points; - private ImmutablePoint offset; - private Color color; - - //fuuuuj tolik parametru - public ScoreAnimation(Position tilePosition, String points, ImmutablePoint point, Color color, Integer duration) { - this.tilePosition = tilePosition; - this.points = points; - this.offset = point; - this.color = color; - if (duration == null) { - nextFrame = Long.MAX_VALUE >> 20; //divisior greater then 1000000 - } else { - nextFrame = System.currentTimeMillis() + duration * 1000; - } - } - - - @Override - public void paint(AnimationLayer l, Graphics2D g) { - Color bgColor; - if (UiUtils.isBrightColor(color)) { - bgColor = POINTS_BLACK_BACKGROUND_COLOR; - } else { - bgColor = POINTS_BACKGROUND_COLOR; - } - l.drawAntialiasedTextCentered(g, points, 22, tilePosition, offset, color, bgColor); - } - - -} +package com.jcloisterzone.ui.animation; + +import java.awt.Color; +import java.awt.Graphics2D; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.UiUtils; +import com.jcloisterzone.ui.grid.layer.AnimationLayer; + + +public class ScoreAnimation extends AbstractAnimation { + + private static final Color POINTS_BLACK_BACKGROUND_COLOR = new Color(0.0f, 0.0f, 0.0f, 0.7f); + private static final Color POINTS_BACKGROUND_COLOR = new Color(1.0f, 1.0f, 1.0f, 0.7f); + + private Position tilePosition; + private String points; + private ImmutablePoint offset; + private Color color; + + //fuuuuj tolik parametru + public ScoreAnimation(Position tilePosition, String points, ImmutablePoint point, Color color, Integer duration) { + this.tilePosition = tilePosition; + this.points = points; + this.offset = point; + this.color = color; + if (duration == null) { + nextFrame = Long.MAX_VALUE >> 20; //divisior greater then 1000000 + } else { + nextFrame = System.currentTimeMillis() + duration * 1000; + } + } + + + @Override + public void paint(AnimationLayer l, Graphics2D g) { + Color bgColor; + if (UiUtils.isBrightColor(color)) { + bgColor = POINTS_BLACK_BACKGROUND_COLOR; + } else { + bgColor = POINTS_BACKGROUND_COLOR; + } + l.drawAntialiasedTextCentered(g, points, 22, tilePosition, offset, color, bgColor); + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/controls/ActionPanel.java b/src/main/java/com/jcloisterzone/ui/controls/ActionPanel.java index 2f841e1a9..beadf6d4d 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/ActionPanel.java +++ b/src/main/java/com/jcloisterzone/ui/controls/ActionPanel.java @@ -1,205 +1,205 @@ -package com.jcloisterzone.ui.controls; - -import static com.jcloisterzone.ui.controls.ControlPanel.CORNER_DIAMETER; -import static com.jcloisterzone.ui.controls.ControlPanel.PANEL_WIDTH; - -import java.awt.Cursor; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.event.MouseEvent; - -import javax.swing.ImageIcon; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.AbbeyPlacementAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.TilePlacementAction; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.grid.ForwardBackwardListener; - -public class ActionPanel extends FakeComponent implements RegionMouseListener, ForwardBackwardListener { - - public static final int LINE_HEIGHT = 30; - public static final int PADDING = 3; - public static final int LEFT_MARGIN = 10; - public static final double ACTIVE_SIZE_RATIO = 1.375; - - private PlayerAction[] actions; - private int selectedActionIndex = -1; - - //cached scaled smooth images - private Image[] selected, deselected; - private int imgOffset = 0; - private boolean refreshImages, refreshMouseRegions; - - public ActionPanel(Client client) { - super(client); - } - - private void repaint() { - client.getGridPanel().repaint(); - } - - public PlayerAction[] getActions() { - return actions; - } - - public void setActions(PlayerAction[] actions) { - selected = new Image[actions.length]; - deselected = new Image[actions.length]; - refreshImages = true; - refreshMouseRegions = true; - this.actions = actions; - if (actions.length > 0 && client.isClientActive()) { - setSelectedActionIndex(0); - } - repaint(); - } - - - public void refreshImageCache() { - //refresh is executed in AWT thread - refreshImages = true; - repaint(); - } - - private void doRefreshImageCache() { - if (actions == null || actions.length == 0) { - selected = null; - deselected = null; - } - - int maxIconSize = 40; - imgOffset = 0; - - if (actions[0] instanceof TilePlacementAction) { - imgOffset = -10; - maxIconSize = 62; - } else if (actions[0] instanceof AbbeyPlacementAction) { - imgOffset = 4; - maxIconSize = 52; - } else { - maxIconSize = 40; - } - - int availableWidth = ControlPanel.PANEL_WIDTH - LEFT_MARGIN - (actions.length-1)*PADDING; - double units = actions.length + (ACTIVE_SIZE_RATIO-1.0); - int baseSize = Math.min(maxIconSize, (int) Math.floor(availableWidth / units)); - int activeSize = (int) (baseSize * ACTIVE_SIZE_RATIO); - - Player activePlayer = client.getGame().getActivePlayer(); - for (int i = 0; i < actions.length; i++) { - selected[i] = new ImageIcon( - actions[i].getImage(activePlayer, true).getScaledInstance(activeSize, activeSize, Image.SCALE_SMOOTH) - ).getImage(); - deselected[i] = new ImageIcon( - actions[i].getImage(activePlayer, false).getScaledInstance(baseSize, baseSize, Image.SCALE_SMOOTH) - ).getImage(); - } - } - - public void clearActions() { - deselectAction(); - this.actions = null; - this.selectedActionIndex = -1; - refreshImages = true; - refreshMouseRegions = true; - repaint(); - } - - public void forward() { - if (selectedActionIndex != -1) getSelectedAction().forward(); - } - - public void backward() { - if (selectedActionIndex != -1) getSelectedAction().backward(); - } - - public void rollAction(int change) { - if (client.isClientActive()) { - if (actions.length == 0) return; - int idx = (selectedActionIndex + change + actions.length) % actions.length; - setSelectedActionIndex(idx); - repaint(); - } - } - - private void deselectAction() { - if (this.selectedActionIndex != -1) { - PlayerAction prev = actions[this.selectedActionIndex]; - prev.deselect(); - } - } - - private void setSelectedActionIndex(int selectedActionIndex) { - deselectAction(); - this.selectedActionIndex = selectedActionIndex; - PlayerAction action = actions[selectedActionIndex]; - action.select(); - } - - public PlayerAction getSelectedAction() { - return actions[selectedActionIndex]; - } - - @Override - public void paintComponent(Graphics2D g2) { - super.paintComponent(g2); - - g2.setColor(ControlPanel.PLAYER_BG_COLOR); - g2.fillRoundRect(0, 0, PANEL_WIDTH+CORNER_DIAMETER, LINE_HEIGHT, CORNER_DIAMETER, CORNER_DIAMETER); - - if (actions == null || actions.length == 0) return; - - //possible race condition - (but AtomBoolean cannot be used, too slow for painting) - boolean refreshImages = this.refreshImages; - this.refreshImages = false; - boolean refreshMouseRegions = this.refreshMouseRegions; - this.refreshMouseRegions = false; - - if (refreshImages) { - doRefreshImageCache(); - } - - int x = LEFT_MARGIN; - - if (refreshMouseRegions) { - getMouseRegions().clear(); - } - for (int i = 0; i < actions.length; i++) { - boolean active = (i == selectedActionIndex); - - Image img = active ? selected[i] : deselected[i]; - int size = img.getWidth(null); - int iy = (LINE_HEIGHT-size) / 2; - - if (refreshMouseRegions && selectedActionIndex != -1) { - getMouseRegions().add(new MouseListeningRegion(new Rectangle(x, iy+imgOffset, size, size), this, i)); - } - g2.drawImage(img, x, iy+imgOffset, size, size, null); - x += size + PADDING; - } - } - - @Override - public void mouseClicked(MouseEvent e, MouseListeningRegion origin) { - if (e.getButton() == MouseEvent.BUTTON1) { - Integer i = (Integer) origin.getData(); - setSelectedActionIndex(i); - } - } - - @Override - public void mouseEntered(MouseEvent e, MouseListeningRegion origin) { - Integer i = (Integer) origin.getData(); - if (i != selectedActionIndex) { - client.getGridPanel().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - } - - @Override - public void mouseExited(MouseEvent e, MouseListeningRegion origin) { - client.getGridPanel().setCursor(Cursor.getDefaultCursor()); - } -} +package com.jcloisterzone.ui.controls; + +import static com.jcloisterzone.ui.controls.ControlPanel.CORNER_DIAMETER; +import static com.jcloisterzone.ui.controls.ControlPanel.PANEL_WIDTH; + +import java.awt.Cursor; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; + +import javax.swing.ImageIcon; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.AbbeyPlacementAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.TilePlacementAction; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.grid.ForwardBackwardListener; + +public class ActionPanel extends FakeComponent implements RegionMouseListener, ForwardBackwardListener { + + public static final int LINE_HEIGHT = 30; + public static final int PADDING = 3; + public static final int LEFT_MARGIN = 10; + public static final double ACTIVE_SIZE_RATIO = 1.375; + + private PlayerAction[] actions; + private int selectedActionIndex = -1; + + //cached scaled smooth images + private Image[] selected, deselected; + private int imgOffset = 0; + private boolean refreshImages, refreshMouseRegions; + + public ActionPanel(Client client) { + super(client); + } + + private void repaint() { + client.getGridPanel().repaint(); + } + + public PlayerAction[] getActions() { + return actions; + } + + public void setActions(PlayerAction[] actions) { + selected = new Image[actions.length]; + deselected = new Image[actions.length]; + refreshImages = true; + refreshMouseRegions = true; + this.actions = actions; + if (actions.length > 0 && client.isClientActive()) { + setSelectedActionIndex(0); + } + repaint(); + } + + + public void refreshImageCache() { + //refresh is executed in AWT thread + refreshImages = true; + repaint(); + } + + private void doRefreshImageCache() { + if (actions == null || actions.length == 0) { + selected = null; + deselected = null; + } + + int maxIconSize = 40; + imgOffset = 0; + + if (actions[0] instanceof TilePlacementAction) { + imgOffset = -10; + maxIconSize = 62; + } else if (actions[0] instanceof AbbeyPlacementAction) { + imgOffset = 4; + maxIconSize = 52; + } else { + maxIconSize = 40; + } + + int availableWidth = ControlPanel.PANEL_WIDTH - LEFT_MARGIN - (actions.length-1)*PADDING; + double units = actions.length + (ACTIVE_SIZE_RATIO-1.0); + int baseSize = Math.min(maxIconSize, (int) Math.floor(availableWidth / units)); + int activeSize = (int) (baseSize * ACTIVE_SIZE_RATIO); + + Player activePlayer = client.getGame().getActivePlayer(); + for (int i = 0; i < actions.length; i++) { + selected[i] = new ImageIcon( + actions[i].getImage(activePlayer, true).getScaledInstance(activeSize, activeSize, Image.SCALE_SMOOTH) + ).getImage(); + deselected[i] = new ImageIcon( + actions[i].getImage(activePlayer, false).getScaledInstance(baseSize, baseSize, Image.SCALE_SMOOTH) + ).getImage(); + } + } + + public void clearActions() { + deselectAction(); + this.actions = null; + this.selectedActionIndex = -1; + refreshImages = true; + refreshMouseRegions = true; + repaint(); + } + + public void forward() { + if (selectedActionIndex != -1) getSelectedAction().forward(); + } + + public void backward() { + if (selectedActionIndex != -1) getSelectedAction().backward(); + } + + public void rollAction(int change) { + if (client.isClientActive()) { + if (actions.length == 0) return; + int idx = (selectedActionIndex + change + actions.length) % actions.length; + setSelectedActionIndex(idx); + repaint(); + } + } + + private void deselectAction() { + if (this.selectedActionIndex != -1) { + PlayerAction prev = actions[this.selectedActionIndex]; + prev.deselect(); + } + } + + private void setSelectedActionIndex(int selectedActionIndex) { + deselectAction(); + this.selectedActionIndex = selectedActionIndex; + PlayerAction action = actions[selectedActionIndex]; + action.select(); + } + + public PlayerAction getSelectedAction() { + return actions[selectedActionIndex]; + } + + @Override + public void paintComponent(Graphics2D g2) { + super.paintComponent(g2); + + g2.setColor(ControlPanel.PLAYER_BG_COLOR); + g2.fillRoundRect(0, 0, PANEL_WIDTH+CORNER_DIAMETER, LINE_HEIGHT, CORNER_DIAMETER, CORNER_DIAMETER); + + if (actions == null || actions.length == 0) return; + + //possible race condition - (but AtomBoolean cannot be used, too slow for painting) + boolean refreshImages = this.refreshImages; + this.refreshImages = false; + boolean refreshMouseRegions = this.refreshMouseRegions; + this.refreshMouseRegions = false; + + if (refreshImages) { + doRefreshImageCache(); + } + + int x = LEFT_MARGIN; + + if (refreshMouseRegions) { + getMouseRegions().clear(); + } + for (int i = 0; i < actions.length; i++) { + boolean active = (i == selectedActionIndex); + + Image img = active ? selected[i] : deselected[i]; + int size = img.getWidth(null); + int iy = (LINE_HEIGHT-size) / 2; + + if (refreshMouseRegions && selectedActionIndex != -1) { + getMouseRegions().add(new MouseListeningRegion(new Rectangle(x, iy+imgOffset, size, size), this, i)); + } + g2.drawImage(img, x, iy+imgOffset, size, size, null); + x += size + PADDING; + } + } + + @Override + public void mouseClicked(MouseEvent e, MouseListeningRegion origin) { + if (e.getButton() == MouseEvent.BUTTON1) { + Integer i = (Integer) origin.getData(); + setSelectedActionIndex(i); + } + } + + @Override + public void mouseEntered(MouseEvent e, MouseListeningRegion origin) { + Integer i = (Integer) origin.getData(); + if (i != selectedActionIndex) { + client.getGridPanel().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + } + + @Override + public void mouseExited(MouseEvent e, MouseListeningRegion origin) { + client.getGridPanel().setCursor(Cursor.getDefaultCursor()); + } +} diff --git a/src/main/java/com/jcloisterzone/ui/controls/ControlPanel.java b/src/main/java/com/jcloisterzone/ui/controls/ControlPanel.java index 06484f370..0c81b0e74 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/ControlPanel.java +++ b/src/main/java/com/jcloisterzone/ui/controls/ControlPanel.java @@ -1,268 +1,266 @@ -package com.jcloisterzone.ui.controls; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Insets; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ComponentEvent; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.util.Arrays; -import java.util.List; - -import javax.swing.JButton; -import javax.swing.JComponent; - -import com.jcloisterzone.Player; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.board.TilePack; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.grid.BazaarPanel; -import com.jcloisterzone.ui.grid.GridPanel; - -public class ControlPanel extends FakeComponent { - - private static Font FONT_PACK_SIZE = new Font(null, Font.PLAIN, 20); - - public static final Color HEADER_FONT_COLOR = new Color(170, 170, 170, 200); - public static final Color PLAYER_BG_COLOR = new Color(210, 210, 210, 200); - public static final Color PANEL_BG_COLOR = new Color(255, 255, 255, 225); - public static final Color PANEL_BG_COLOR_SHADOW = new Color(255, 255, 255, 158); - - - @Deprecated - public static final Color FONT_SHADOW_COLOR = new Color(0, 0, 0, 60); - - public static final int CORNER_DIAMETER = 16; - public static final int PANEL_WIDTH = 220; - public static final int PANEL_SHADOW_WIDTH = 3; - public static final int LEFT_PADDING = 20; - public static final int ACTIVE_MARKER_SIZE = 25; - public static final int ACTIVE_MARKER_PADDING = 6; - - private JButton passButton; - private boolean canPass; - - private ActionPanel actionPanel; - private PlayerPanel[] playerPanels; - - public ControlPanel(final Client client) { - super(client); - - actionPanel = new ActionPanel(client); - - Player[] players = client.getGame().getAllPlayers(); - PlayerPanelImageCache cache = new PlayerPanelImageCache(client); - playerPanels = new PlayerPanel[players.length]; - - for (int i = 0; i < players.length; i++) { - playerPanels[i] = new PlayerPanel(client, players[i], cache); - } - } - - @Override - public void componentResized(ComponentEvent e) { - refreshComponents(); - client.getGridPanel().repaint(); - } - - @Override - public void registerSwingComponents(JComponent parent) { - passButton = new JButton(_("Skip")); - passButton.setMargin(new Insets(1,1,1,1)); - passButton.setVisible(false); - passButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - pass(); - } - }); - parent.add(passButton); - } - - @Override - public void destroySwingComponents(JComponent parent) { - parent.remove(passButton); - } - - private void refreshComponents() { - passButton.setVisible(canPass); - if (canPass) { - //TODO hardcoded offset - but no better solution for now - int x = client.getGridPanel().getWidth()-PANEL_WIDTH; - passButton.setBounds(x, 4, 90, 19); - } - } - - @Override - public void dispatchMouseEvent(MouseEvent e) { - super.dispatchMouseEvent(e); - if (e.isConsumed()) return; - actionPanel.dispatchMouseEvent(e); - for (PlayerPanel pp : playerPanels) { - if (e.isConsumed()) return; - pp.dispatchMouseEvent(e); - } - } - - private void paintBackgroundBody(Graphics2D g2) { - GridPanel gp = client.getGridPanel(); - int h = gp.getHeight(); - - g2.setColor(PANEL_BG_COLOR); - g2.fillRect(0 , 0, PANEL_WIDTH, h); - } - - private void paintBackgroundShadow(Graphics2D g2) { - GridPanel gp = client.getGridPanel(); - int h = gp.getHeight(); - - Player player = client.getGame().getTurnPlayer(); - if (player == null) { - g2.setColor(PANEL_BG_COLOR); - g2.fillRect(-LEFT_PADDING , 0, LEFT_PADDING, h); - g2.setColor(PANEL_BG_COLOR_SHADOW); - g2.fillRect(-LEFT_PADDING-3, 0, 3, h); - } else { - int y = playerPanels[player.getIndex()].getCenterY(); - - g2.setColor(PANEL_BG_COLOR); - g2.fillRect(-LEFT_PADDING , 0, LEFT_PADDING, y-ACTIVE_MARKER_SIZE); - g2.fillRect(-LEFT_PADDING , y+ACTIVE_MARKER_SIZE, LEFT_PADDING, h-y-ACTIVE_MARKER_SIZE); - g2.fillPolygon( - new int[] { -LEFT_PADDING, 0, 0, -ACTIVE_MARKER_PADDING }, - new int[] { y-ACTIVE_MARKER_SIZE, y-ACTIVE_MARKER_SIZE, y, y}, 4 - ); - g2.fillPolygon( - new int[] { -LEFT_PADDING, 0, 0, -ACTIVE_MARKER_PADDING }, - new int[] { y+ACTIVE_MARKER_SIZE, y+ACTIVE_MARKER_SIZE, y, y}, 4 - ); - g2.setColor(PANEL_BG_COLOR_SHADOW); - //g2.setColor(Color.RED); - g2.fillRect(-LEFT_PADDING-PANEL_SHADOW_WIDTH, 0, PANEL_SHADOW_WIDTH, y-ACTIVE_MARKER_SIZE); - g2.fillRect(-LEFT_PADDING-PANEL_SHADOW_WIDTH, y+ACTIVE_MARKER_SIZE, PANEL_SHADOW_WIDTH, h-y+ACTIVE_MARKER_SIZE); - g2.fillPolygon( - new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH, -LEFT_PADDING, -ACTIVE_MARKER_PADDING, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING}, - new int[] { y-ACTIVE_MARKER_SIZE, y-ACTIVE_MARKER_SIZE, y, y}, 4 - ); - g2.fillPolygon( - new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH, -LEFT_PADDING, -ACTIVE_MARKER_PADDING, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING }, - new int[] { y+ACTIVE_MARKER_SIZE, y+ACTIVE_MARKER_SIZE, y, y}, 4 - ); - } - - player = client.getGame().getActivePlayer(); - if (player != null) { - g2.setColor(Color.BLACK); - int y = playerPanels[player.getIndex()].getCenterY(); -// g2.fillPolygon( -// new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING, -LEFT_PADDING-PANEL_SHADOW_WIDTH}, -// new int[] { y-ACTIVE_MARKER_SIZE, y, y+ACTIVE_MARKER_SIZE,}, 3 -// ); - g2.fillPolygon( - new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH-3, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING, -LEFT_PADDING-PANEL_SHADOW_WIDTH-3}, - new int[] { y-ACTIVE_MARKER_SIZE-4, y, y+ACTIVE_MARKER_SIZE+4,}, 3 - ); - } - } - - @Override - public void paintComponent(Graphics2D g2) { - super.paintComponent(g2); - AffineTransform origTransform = g2.getTransform(); - -// GridPanel gp = client.getGridPanel(); - - paintBackgroundBody(g2); - - TilePack tilePack = client.getGame().getTilePack(); - if (tilePack != null) { //null is possible for just loaded game - g2.setFont(FONT_PACK_SIZE); - g2.setColor(HEADER_FONT_COLOR); - int packSize = tilePack.totalSize(); - g2.drawString("" + packSize, PANEL_WIDTH - 42, 24); - } - - g2.translate(0, 46); - actionPanel.paintComponent(g2); -// gp.profile("action panel"); - - g2.translate(0, 60); - - BazaarCapability bcb = client.getGame().getCapability(BazaarCapability.class); - if (bcb != null && !(client.getGridPanel().getSecondPanel() instanceof BazaarPanel)) { //show bazaar supply only if panel is hidden - List queue = bcb.getDrawQueue(); - if (!queue.isEmpty()) { - int x = 0; - for (Tile tile : queue) { - Image img = client.getResourceManager().getTileImage(tile); - g2.drawImage(img, x, 0, 40, 40, null); - x += 45; - } - - g2.translate(0, 50); - } - } - - - for (PlayerPanel pp : playerPanels) { - pp.paintComponent(g2); - g2.translate(0, 12); - } - -// gp.profile("players"); - - g2.setTransform(origTransform); - - paintBackgroundShadow(g2); - - } - - public void pass() { - if (canPass) { - client.getServer().pass(); - } - } - - public ActionPanel getActionPanel() { - return actionPanel; - } - - public void selectAction(List actions, boolean canPass) { - // direct collection sort can be unsupported - so copy to array first! - int i = 0; - PlayerAction[] arr = new PlayerAction[actions.size()]; - for (PlayerAction pa : actions) { - pa.setClient(client); - arr[i++] = pa; - } - Arrays.sort(arr); - actionPanel.setActions(arr); - this.canPass = client.isClientActive() ? canPass : false; - refreshComponents(); - } - - public void clearActions() { - actionPanel.clearActions(); - canPass = false; - refreshComponents(); - } - - public void playerActivated(Player turn, Player active) { - client.getGridPanel().repaint(); // players only - } - - public void closeGame() { - clearActions(); - canPass = false; - refreshComponents(); - } - -} +package com.jcloisterzone.ui.controls; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JButton; +import javax.swing.JComponent; + +import com.jcloisterzone.Player; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.board.TilePack; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.grid.BazaarPanel; +import com.jcloisterzone.ui.grid.GridPanel; + +public class ControlPanel extends FakeComponent { + + private static Font FONT_PACK_SIZE = new Font(null, Font.PLAIN, 20); + + public static final Color HEADER_FONT_COLOR = new Color(170, 170, 170, 200); + public static final Color PLAYER_BG_COLOR = new Color(210, 210, 210, 200); + public static final Color PANEL_BG_COLOR = new Color(255, 255, 255, 225); + public static final Color PANEL_BG_COLOR_SHADOW = new Color(255, 255, 255, 158); + + @Deprecated + public static final Color FONT_SHADOW_COLOR = new Color(0, 0, 0, 60); + public static final int CORNER_DIAMETER = 16; + public static final int PANEL_WIDTH = 220; + public static final int PANEL_SHADOW_WIDTH = 3; + public static final int LEFT_PADDING = 20; + public static final int ACTIVE_MARKER_SIZE = 25; + public static final int ACTIVE_MARKER_PADDING = 6; + + private JButton passButton; + private boolean canPass; + + private ActionPanel actionPanel; + private PlayerPanel[] playerPanels; + + public ControlPanel(final Client client) { + super(client); + + actionPanel = new ActionPanel(client); + + Player[] players = client.getGame().getAllPlayers(); + PlayerPanelImageCache cache = new PlayerPanelImageCache(client); + playerPanels = new PlayerPanel[players.length]; + + for (int i = 0; i < players.length; i++) { + playerPanels[i] = new PlayerPanel(client, players[i], cache); + } + } + + @Override + public void componentResized(ComponentEvent e) { + refreshComponents(); + client.getGridPanel().repaint(); + } + + @Override + public void registerSwingComponents(JComponent parent) { + passButton = new JButton(_("Skip")); + passButton.setMargin(new Insets(1,1,1,1)); + passButton.setVisible(false); + passButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + pass(); + } + }); + parent.add(passButton); + } + + @Override + public void destroySwingComponents(JComponent parent) { + parent.remove(passButton); + } + + private void refreshComponents() { + passButton.setVisible(canPass); + if (canPass) { + //TODO hardcoded offset - but no better solution for now + int x = client.getGridPanel().getWidth()-PANEL_WIDTH; + passButton.setBounds(x, 4, 90, 19); + } + } + + @Override + public void dispatchMouseEvent(MouseEvent e) { + super.dispatchMouseEvent(e); + if (e.isConsumed()) return; + actionPanel.dispatchMouseEvent(e); + for (PlayerPanel pp : playerPanels) { + if (e.isConsumed()) return; + pp.dispatchMouseEvent(e); + } + } + + private void paintBackgroundBody(Graphics2D g2) { + GridPanel gp = client.getGridPanel(); + int h = gp.getHeight(); + + g2.setColor(PANEL_BG_COLOR); + g2.fillRect(0 , 0, PANEL_WIDTH, h); + } + + private void paintBackgroundShadow(Graphics2D g2) { + GridPanel gp = client.getGridPanel(); + int h = gp.getHeight(); + + Player player = client.getGame().getTurnPlayer(); + if (player == null) { + g2.setColor(PANEL_BG_COLOR); + g2.fillRect(-LEFT_PADDING , 0, LEFT_PADDING, h); + g2.setColor(PANEL_BG_COLOR_SHADOW); + g2.fillRect(-LEFT_PADDING-3, 0, 3, h); + } else { + int y = playerPanels[player.getIndex()].getCenterY(); + + g2.setColor(PANEL_BG_COLOR); + g2.fillRect(-LEFT_PADDING , 0, LEFT_PADDING, y-ACTIVE_MARKER_SIZE); + g2.fillRect(-LEFT_PADDING , y+ACTIVE_MARKER_SIZE, LEFT_PADDING, h-y-ACTIVE_MARKER_SIZE); + g2.fillPolygon( + new int[] { -LEFT_PADDING, 0, 0, -ACTIVE_MARKER_PADDING }, + new int[] { y-ACTIVE_MARKER_SIZE, y-ACTIVE_MARKER_SIZE, y, y}, 4 + ); + g2.fillPolygon( + new int[] { -LEFT_PADDING, 0, 0, -ACTIVE_MARKER_PADDING }, + new int[] { y+ACTIVE_MARKER_SIZE, y+ACTIVE_MARKER_SIZE, y, y}, 4 + ); + g2.setColor(PANEL_BG_COLOR_SHADOW); + //g2.setColor(Color.RED); + g2.fillRect(-LEFT_PADDING-PANEL_SHADOW_WIDTH, 0, PANEL_SHADOW_WIDTH, y-ACTIVE_MARKER_SIZE); + g2.fillRect(-LEFT_PADDING-PANEL_SHADOW_WIDTH, y+ACTIVE_MARKER_SIZE, PANEL_SHADOW_WIDTH, h-y+ACTIVE_MARKER_SIZE); + g2.fillPolygon( + new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH, -LEFT_PADDING, -ACTIVE_MARKER_PADDING, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING}, + new int[] { y-ACTIVE_MARKER_SIZE, y-ACTIVE_MARKER_SIZE, y, y}, 4 + ); + g2.fillPolygon( + new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH, -LEFT_PADDING, -ACTIVE_MARKER_PADDING, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING }, + new int[] { y+ACTIVE_MARKER_SIZE, y+ACTIVE_MARKER_SIZE, y, y}, 4 + ); + } + + player = client.getGame().getActivePlayer(); + if (player != null) { + g2.setColor(Color.BLACK); + int y = playerPanels[player.getIndex()].getCenterY(); +// g2.fillPolygon( +// new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING, -LEFT_PADDING-PANEL_SHADOW_WIDTH}, +// new int[] { y-ACTIVE_MARKER_SIZE, y, y+ACTIVE_MARKER_SIZE,}, 3 +// ); + g2.fillPolygon( + new int[] { -LEFT_PADDING-PANEL_SHADOW_WIDTH-3, -PANEL_SHADOW_WIDTH-ACTIVE_MARKER_PADDING, -LEFT_PADDING-PANEL_SHADOW_WIDTH-3}, + new int[] { y-ACTIVE_MARKER_SIZE-4, y, y+ACTIVE_MARKER_SIZE+4,}, 3 + ); + } + } + + @Override + public void paintComponent(Graphics2D g2) { + super.paintComponent(g2); + AffineTransform origTransform = g2.getTransform(); + +// GridPanel gp = client.getGridPanel(); + + paintBackgroundBody(g2); + + TilePack tilePack = client.getGame().getTilePack(); + if (tilePack != null) { //null is possible for just loaded game + g2.setFont(FONT_PACK_SIZE); + g2.setColor(HEADER_FONT_COLOR); + int packSize = tilePack.totalSize(); + g2.drawString("" + packSize, PANEL_WIDTH - 42, 24); + } + + g2.translate(0, 46); + actionPanel.paintComponent(g2); +// gp.profile("action panel"); + + g2.translate(0, 60); + + BazaarCapability bcb = client.getGame().getCapability(BazaarCapability.class); + if (bcb != null && !(client.getGridPanel().getSecondPanel() instanceof BazaarPanel)) { //show bazaar supply only if panel is hidden + List queue = bcb.getDrawQueue(); + if (!queue.isEmpty()) { + int x = 0; + for (Tile tile : queue) { + Image img = client.getResourceManager().getTileImage(tile); + g2.drawImage(img, x, 0, 40, 40, null); + x += 45; + } + + g2.translate(0, 50); + } + } + + + for (PlayerPanel pp : playerPanels) { + pp.paintComponent(g2); + g2.translate(0, 12); + } + +// gp.profile("players"); + + g2.setTransform(origTransform); + + paintBackgroundShadow(g2); + + } + + public void pass() { + if (canPass) { + client.getServer().pass(); + } + } + + public ActionPanel getActionPanel() { + return actionPanel; + } + + public void selectAction(List actions, boolean canPass) { + // direct collection sort can be unsupported - so copy to array first! + int i = 0; + PlayerAction[] arr = new PlayerAction[actions.size()]; + for (PlayerAction pa : actions) { + pa.setClient(client); + arr[i++] = pa; + } + Arrays.sort(arr); + actionPanel.setActions(arr); + this.canPass = client.isClientActive() ? canPass : false; + refreshComponents(); + } + + public void clearActions() { + actionPanel.clearActions(); + canPass = false; + refreshComponents(); + } + + public void playerActivated(Player turn, Player active) { + client.getGridPanel().repaint(); // players only + } + + public void closeGame() { + clearActions(); + canPass = false; + refreshComponents(); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/controls/FakeComponent.java b/src/main/java/com/jcloisterzone/ui/controls/FakeComponent.java index 4541f055b..aba251517 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/FakeComponent.java +++ b/src/main/java/com/jcloisterzone/ui/controls/FakeComponent.java @@ -1,113 +1,113 @@ -package com.jcloisterzone.ui.controls; - -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.event.ComponentAdapter; -import java.awt.event.ComponentEvent; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.JComponent; - -import com.jcloisterzone.ui.Client; - -public abstract class FakeComponent extends ComponentAdapter { - - private static final int DEFAULT_PANEL_WIDTH = 250; - - protected final Client client; - private List mouseRegions = new ArrayList<>(); - private MouseListeningRegion mouseOver = null; - private AffineTransform transform; - - public FakeComponent(Client client) { - this.client = client; - } - - public int getWidth() { - return DEFAULT_PANEL_WIDTH; - } - - public void paintComponent(Graphics2D g) { - transform = g.getTransform(); - } - - @Override - public void componentResized(ComponentEvent e) { - layoutSwingComponents((JComponent) e.getComponent()); - e.getComponent().repaint(); - } - - public void registerSwingComponents(JComponent parent) { - } - - public void destroySwingComponents(JComponent parent) { - } - - public void layoutSwingComponents(JComponent parent) { - } - - protected List getMouseRegions() { - return mouseRegions; - } - - public void dispatchMouseEvent(MouseEvent e) { - switch (e.getID()) { - case MouseEvent.MOUSE_CLICKED: - dispatchMouseClick(e); - break; - case MouseEvent.MOUSE_MOVED: - dispatchMouseMove(e); - break; - } - } - - public void dispatchMouseClick(MouseEvent e) { - for (MouseListeningRegion mlr : mouseRegions) { - Area a = transformRegion(mlr.getRegion()); - if (a.contains(e.getX(), e.getY())) { - mlr.getListener().mouseClicked(e, mlr); - e.consume(); - break; - } - } - } - - public void dispatchMouseMove(MouseEvent e) { - if (mouseOver == null) { - for (MouseListeningRegion mlr : mouseRegions) { - Area a = transformRegion(mlr.getRegion()); - if (a.contains(e.getX(), e.getY())) { - mouseOver = mlr; - mouseOver.getListener().mouseEntered(e, mouseOver); - e.consume(); - break; - } - } - } else { - Area a = transformRegion(mouseOver.getRegion()); - if (a.contains(e.getX(), e.getY())) { - e.consume(); - return; - } else { - mouseOver.getListener().mouseExited(e, mouseOver); - mouseOver = null; - } - } - - } - - protected Area transformRegion(Rectangle r) { - Area a = new Area(r); - a.transform(transform); - return a; - } - -// protected Rectangle computeBounds(int x, int y, int width, int height) { -// return transformRegion(new Rectangle(x, y, width, height)).getBounds(); -// } - -} +package com.jcloisterzone.ui.controls; + +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JComponent; + +import com.jcloisterzone.ui.Client; + +public abstract class FakeComponent extends ComponentAdapter { + + private static final int DEFAULT_PANEL_WIDTH = 250; + + protected final Client client; + private List mouseRegions = new ArrayList<>(); + private MouseListeningRegion mouseOver = null; + private AffineTransform transform; + + public FakeComponent(Client client) { + this.client = client; + } + + public int getWidth() { + return DEFAULT_PANEL_WIDTH; + } + + public void paintComponent(Graphics2D g) { + transform = g.getTransform(); + } + + @Override + public void componentResized(ComponentEvent e) { + layoutSwingComponents((JComponent) e.getComponent()); + e.getComponent().repaint(); + } + + public void registerSwingComponents(JComponent parent) { + } + + public void destroySwingComponents(JComponent parent) { + } + + public void layoutSwingComponents(JComponent parent) { + } + + protected List getMouseRegions() { + return mouseRegions; + } + + public void dispatchMouseEvent(MouseEvent e) { + switch (e.getID()) { + case MouseEvent.MOUSE_CLICKED: + dispatchMouseClick(e); + break; + case MouseEvent.MOUSE_MOVED: + dispatchMouseMove(e); + break; + } + } + + public void dispatchMouseClick(MouseEvent e) { + for (MouseListeningRegion mlr : mouseRegions) { + Area a = transformRegion(mlr.getRegion()); + if (a.contains(e.getX(), e.getY())) { + mlr.getListener().mouseClicked(e, mlr); + e.consume(); + break; + } + } + } + + public void dispatchMouseMove(MouseEvent e) { + if (mouseOver == null) { + for (MouseListeningRegion mlr : mouseRegions) { + Area a = transformRegion(mlr.getRegion()); + if (a.contains(e.getX(), e.getY())) { + mouseOver = mlr; + mouseOver.getListener().mouseEntered(e, mouseOver); + e.consume(); + break; + } + } + } else { + Area a = transformRegion(mouseOver.getRegion()); + if (a.contains(e.getX(), e.getY())) { + e.consume(); + return; + } else { + mouseOver.getListener().mouseExited(e, mouseOver); + mouseOver = null; + } + } + + } + + protected Area transformRegion(Rectangle r) { + Area a = new Area(r); + a.transform(transform); + return a; + } + +// protected Rectangle computeBounds(int x, int y, int width, int height) { +// return transformRegion(new Rectangle(x, y, width, height)).getBounds(); +// } + +} diff --git a/src/main/java/com/jcloisterzone/ui/controls/MouseListeningRegion.java b/src/main/java/com/jcloisterzone/ui/controls/MouseListeningRegion.java index 6e0b25a51..c0374fe29 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/MouseListeningRegion.java +++ b/src/main/java/com/jcloisterzone/ui/controls/MouseListeningRegion.java @@ -1,29 +1,29 @@ -package com.jcloisterzone.ui.controls; - -import java.awt.Rectangle; - -public class MouseListeningRegion { - - private final Rectangle region; - private final RegionMouseListener listener; - private final Object data; - - public MouseListeningRegion(Rectangle region, RegionMouseListener listener, Object data) { - this.region = region; - this.listener = listener; - this.data = data; - } - - public RegionMouseListener getListener() { - return listener; - } - - public Rectangle getRegion() { - return region; - } - - public Object getData() { - return data; - } - -} +package com.jcloisterzone.ui.controls; + +import java.awt.Rectangle; + +public class MouseListeningRegion { + + private final Rectangle region; + private final RegionMouseListener listener; + private final Object data; + + public MouseListeningRegion(Rectangle region, RegionMouseListener listener, Object data) { + this.region = region; + this.listener = listener; + this.data = data; + } + + public RegionMouseListener getListener() { + return listener; + } + + public Rectangle getRegion() { + return region; + } + + public Object getData() { + return data; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/controls/PlayerPanel.java b/src/main/java/com/jcloisterzone/ui/controls/PlayerPanel.java index 5bd69f443..a1460c74f 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/PlayerPanel.java +++ b/src/main/java/com/jcloisterzone/ui/controls/PlayerPanel.java @@ -1,341 +1,341 @@ -package com.jcloisterzone.ui.controls; - -import static com.jcloisterzone.ui.I18nUtils._; -import static com.jcloisterzone.ui.controls.ControlPanel.CORNER_DIAMETER; -import static com.jcloisterzone.ui.controls.ControlPanel.PANEL_WIDTH; -import static com.jcloisterzone.ui.controls.ControlPanel.PLAYER_BG_COLOR; - -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.swing.JOptionPane; - -import com.google.common.collect.Iterables; -import com.jcloisterzone.Player; -import com.jcloisterzone.TradeResource; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.figure.Special; -import com.jcloisterzone.figure.predicate.MeeplePredicates; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.capability.AbbeyCapability; -import com.jcloisterzone.game.capability.BridgeCapability; -import com.jcloisterzone.game.capability.CastleCapability; -import com.jcloisterzone.game.capability.ClothWineGrainCapability; -import com.jcloisterzone.game.capability.KingScoutCapability; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.UiUtils; - -public class PlayerPanel extends FakeComponent implements RegionMouseListener { - - private static final Color DELIM_TOP_COLOR = new Color(250,250,250); - private static final Color DELIM_BOTTOM_COLOR = new Color(220,220,220); - private static final Color KING_SCOUT_OVERLAY = new Color(0f,0f,0f,0.4f); - //private static final Color ACTIVE_TOWER_BG = new Color(255, 255, 70); - - private static Font FONT_POINTS = new Font("Georgia", Font.BOLD, 30); - private static Font FONT_MEEPLE = new Font("Georgia", Font.BOLD, 18); - private static Font FONT_KING_SCOUT_OVERLAY = new Font("Georgia", Font.BOLD, 22); - private static Font FONT_NICKNAME = new Font(null, Font.BOLD, 18); - - private static final int PADDING_L = 9; - private static final int PADDING_R = 11; - private static final int LINE_HEIGHT = 32; - private static final int DELIMITER_Y = 34; - - private final Player player; - private final Color color; - - private final PlayerPanelImageCache cache; - - private int centerY; - - //paint context variables - private Graphics2D g2; - private int bx, by; - - private String mouseOverKey = null; - - public PlayerPanel(Client client, Player player, PlayerPanelImageCache cache) { - super(client); - this.player = player; - this.cache = cache; - this.color = client.getPlayerColor(player); - } - - private void drawDelimiter(int y) { - g2.setColor(DELIM_TOP_COLOR); - g2.drawLine(PADDING_L, y, PANEL_WIDTH /*-PADDING_R*/, y); - g2.setColor(DELIM_BOTTOM_COLOR); - g2.drawLine(PADDING_L, y+1, PANEL_WIDTH /*-PADDING_R*/, y+1); - } - - private void drawTextShadow(String text, int x, int y) { - //TODO shadow color based on color ?? - /*g2.setColor(Color.DARK_GRAY); - g2.drawString(text, x+0.8f, y+0.7f);*/ - g2.setColor(ControlPanel.FONT_SHADOW_COLOR); - g2.drawString(text, x+0.6f, y+0.5f); - g2.setColor(color); - g2.drawString(text, x, y); - } - - private Rectangle drawMeepleBox(Player playerKey, String imgKey, int count, boolean showOne) { - return drawMeepleBox(playerKey, imgKey, count, showOne, null, false); - } - - private Rectangle drawMeepleBox(Player playerKey, String imgKey, int count, boolean showOne, Object regionData) { - return drawMeepleBox(playerKey, imgKey, count, showOne, regionData, false); - } - - private Rectangle drawMeepleBox(Player playerKey, String imgKey, int count, boolean showOne, Object regionData, boolean active) { - if (count == 0) return null; - - int w = 30; - if (count > 1 || (count == 1 && showOne)) { - w = count < 10 ? 47 : 60; - } - int h = 22; - if (bx+w > PANEL_WIDTH-PADDING_R) { - bx = PADDING_L; - by += LINE_HEIGHT; - } - g2.setColor(active ? Color.BLACK : Color.WHITE); - g2.fillRoundRect(bx, by, w, h, 8, 8); - g2.drawImage(cache.get(playerKey, imgKey), bx, by-4, null); - - Rectangle rect = null; - if (regionData != null) { - rect = new Rectangle(bx, by-4, w, h+8); - getMouseRegions().add(new MouseListeningRegion(rect, this, regionData)); - } - - if (count > 1 || (count == 1 && showOne)) { - g2.setColor(active ? Color.WHITE : Color.BLACK); - g2.drawString(""+count, bx+LINE_HEIGHT, by+17); - } - bx += w + 8; - return rect; - } - - /* - * translates parentGraphics, which is not much clean! - */ - @Override - public void paintComponent(Graphics2D parentGraphics) { - super.paintComponent(parentGraphics); - - Game game = client.getGame(); - -// GridPanel gp = client.getGridPanel(); - -// boolean isActive = game.getActivePlayer() == player; -// boolean playerTurn = game.getTurnPlayer() == player; - -// gp.profile(" > get flags"); - - BufferedImage bimg = UiUtils.newTransparentImage(PANEL_WIDTH, 200); - g2 = bimg.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - -// gp.profile(" > create buffer"); - - drawDelimiter(DELIMITER_Y); - - g2.setFont(FONT_POINTS); - drawTextShadow(""+player.getPoints(), PADDING_L, 27); - - g2.setFont(FONT_NICKNAME); - drawTextShadow(player.getNick(), 78, 27); - -// gp.profile(" > nick & score"); - - g2.setFont(FONT_MEEPLE); - bx = PADDING_L; - by = 43; - - int small = 0; - String smallImgKey = SmallFollower.class.getSimpleName(); - for (Follower f : Iterables.filter(player.getFollowers(), MeeplePredicates.inSupply())) { - //instanceof cannot be used because of Phantom - if (f.getClass().equals(SmallFollower.class)) { - small++; - } else { //all small followers are at beginning of collection - drawMeepleBox(player, smallImgKey, small, true); - small = 0; - drawMeepleBox(player, f.getClass().getSimpleName(), 1, false); - } - } - drawMeepleBox(player, smallImgKey, small, true); //case when only small followers are in collection (not drawn yet) - -// gp.profile(" > followers"); - - for (Special meeple : Iterables.filter(player.getSpecialMeeples(), MeeplePredicates.inSupply())) { - drawMeepleBox(player, meeple.getClass().getSimpleName(), 1, false); - } - -// gp.profile(" > special"); - - AbbeyCapability abbeyCap = game.getCapability(AbbeyCapability.class); - TowerCapability towerCap = game.getCapability(TowerCapability.class); - BridgeCapability bridgeCap = game.getCapability(BridgeCapability.class); - CastleCapability castleCap = game.getCapability(CastleCapability.class); - KingScoutCapability kingScoutCap = game.getCapability(KingScoutCapability.class); - ClothWineGrainCapability cwgCap = game.getCapability(ClothWineGrainCapability.class); - - if (abbeyCap != null) { - drawMeepleBox(null, "abbey", abbeyCap.hasUnusedAbbey(player) ? 1 : 0, false); - } - - if (towerCap != null) { - drawMeepleBox(null, "towerpiece", towerCap.getTowerPieces(player), true); - getMouseRegions().clear(); - } - - if (bridgeCap != null) { - drawMeepleBox(null, "bridge", bridgeCap.getPlayerBridges(player), true); - } - if (castleCap != null) { - drawMeepleBox(null, "castle", castleCap.getPlayerCastles(player), true); - } - - if (kingScoutCap != null) { - if (kingScoutCap.getKing() == player) { - Rectangle r = drawMeepleBox(null, "king", 1, false, "king"); - if ("king".equals(mouseOverKey)) { - g2.setFont(FONT_KING_SCOUT_OVERLAY); - g2.setColor(KING_SCOUT_OVERLAY); - g2.fillRect(r.x, r.y, r.width, r.height); - g2.setColor(Color.WHITE); - int size = kingScoutCap.getBiggestCitySize(); - g2.drawString((size < 10 ? " " : "") + size, r.x+2, r.y+20); - g2.setFont(FONT_MEEPLE); - } - } - if (kingScoutCap.getRobberBaron() == player) { - Rectangle r = drawMeepleBox(null, "robber", 1, false, "robber"); - if ("robber".equals(mouseOverKey)) { - g2.setFont(FONT_KING_SCOUT_OVERLAY); - g2.setColor(KING_SCOUT_OVERLAY); - g2.fillRect(r.x, r.y, r.width, r.height); - g2.setColor(Color.WHITE); - int size = kingScoutCap.getLongestRoadLength(); - g2.drawString((size < 10 ? " " : "") + size, r.x+2, r.y+20); - g2.setFont(FONT_MEEPLE); - } - } - } - if (cwgCap != null) { - drawMeepleBox(null, "cloth", cwgCap.getTradeResources(player, TradeResource.CLOTH), true); - drawMeepleBox(null, "grain", cwgCap.getTradeResources(player, TradeResource.GRAIN), true); - drawMeepleBox(null, "wine", cwgCap.getTradeResources(player, TradeResource.WINE), true); - } - if (towerCap != null) { - List capturedFigures = towerCap.getPrisoners().get(player); - Map, Integer> groupedByType; - if (!capturedFigures.isEmpty()) { - groupedByType = new HashMap<>(); - for (Player opponent : game.getAllPlayers()) { - if (opponent == player) continue; - boolean isOpponentActive = game.getActivePlayer() == opponent; - boolean clickable = isOpponentActive && !towerCap.isRansomPaidThisTurn(); - for (Follower f : capturedFigures) { - if (f.getPlayer() == opponent) { - Integer prevVal = groupedByType.get(f.getClass()); - groupedByType.put(f.getClass(), prevVal == null ? 1 : prevVal+1); - } - } - for (Entry, Integer> entry : groupedByType.entrySet()) { - drawMeepleBox(opponent, entry.getKey().getSimpleName(), entry.getValue(), false, - clickable ? entry.getKey() : null, clickable - ); - } - groupedByType.clear(); - } - } - } - -// gp.profile(" > expansions"); - - - int realHeight = by + (bx > PADDING_L ? LINE_HEIGHT : 0); - -// if (isActive) { -// //TODO -// //parentGraphics.setColor(Color.BLACK); -// //parentGraphics.fillRoundRect(0, -5, PANEL_WIDTH+CORNER_DIAMETER, realHeight+10, CORNER_DIAMETER, CORNER_DIAMETER); -// } - - parentGraphics.setColor(PLAYER_BG_COLOR); - parentGraphics.fillRoundRect(0, 0, PANEL_WIDTH+CORNER_DIAMETER, realHeight, CORNER_DIAMETER, CORNER_DIAMETER); - - centerY = (int) parentGraphics.getTransform().getTranslateY() + realHeight/2; - - parentGraphics.drawImage(bimg, 0, 0, PANEL_WIDTH, realHeight, 0, 0, PANEL_WIDTH, realHeight, null); - parentGraphics.translate(0, realHeight); //add also padding - - g2 = null; - -// gp.profile(" > complete"); - } - - public int getCenterY() { - return centerY; - } - - @SuppressWarnings("unchecked") - @Override - public void mouseClicked(MouseEvent e, MouseListeningRegion origin) { - if (!(origin.getData() instanceof Class)) return; - Class followerClass = (Class) origin.getData(); - TowerCapability tg = client.getGame().getCapability(TowerCapability.class); - if (!tg.isRansomPaidThisTurn()) { - if (client.getSettings().isConfirmRansomPayment()) { - String options[] = {_("Pay ransom"), _("Cancel") }; - int result = JOptionPane.showOptionDialog(client, - _("Do you really want to pay 3 points to release prisoner?"), - _("Confirm ransom payment"), - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); - if (JOptionPane.YES_OPTION != result) return; - } - client.getServer().payRansom(player.getIndex(), followerClass); - } - } - - @Override - public void mouseEntered(MouseEvent e, MouseListeningRegion origin) { - if (origin.getData() instanceof String) { - mouseOverKey = (String) origin.getData(); - client.getGridPanel().repaint(); - } else { - TowerCapability tg = client.getGame().getCapability(TowerCapability.class); - if (!tg.isRansomPaidThisTurn()) { - client.getGridPanel().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } - } - } - - @Override - public void mouseExited(MouseEvent e, MouseListeningRegion origin) { - if (mouseOverKey != null) { - mouseOverKey = null; - client.getGridPanel().repaint(); - } else { - client.getGridPanel().setCursor(Cursor.getDefaultCursor()); - } - } - -} - +package com.jcloisterzone.ui.controls; + +import static com.jcloisterzone.ui.I18nUtils._; +import static com.jcloisterzone.ui.controls.ControlPanel.CORNER_DIAMETER; +import static com.jcloisterzone.ui.controls.ControlPanel.PANEL_WIDTH; +import static com.jcloisterzone.ui.controls.ControlPanel.PLAYER_BG_COLOR; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.swing.JOptionPane; + +import com.google.common.collect.Iterables; +import com.jcloisterzone.Player; +import com.jcloisterzone.TradeResource; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.figure.Special; +import com.jcloisterzone.figure.predicate.MeeplePredicates; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.capability.AbbeyCapability; +import com.jcloisterzone.game.capability.BridgeCapability; +import com.jcloisterzone.game.capability.CastleCapability; +import com.jcloisterzone.game.capability.ClothWineGrainCapability; +import com.jcloisterzone.game.capability.KingScoutCapability; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.UiUtils; + +public class PlayerPanel extends FakeComponent implements RegionMouseListener { + + private static final Color DELIM_TOP_COLOR = new Color(250,250,250); + private static final Color DELIM_BOTTOM_COLOR = new Color(220,220,220); + private static final Color KING_SCOUT_OVERLAY = new Color(0f,0f,0f,0.4f); + //private static final Color ACTIVE_TOWER_BG = new Color(255, 255, 70); + + private static Font FONT_POINTS = new Font("Georgia", Font.BOLD, 30); + private static Font FONT_MEEPLE = new Font("Georgia", Font.BOLD, 18); + private static Font FONT_KING_SCOUT_OVERLAY = new Font("Georgia", Font.BOLD, 22); + private static Font FONT_NICKNAME = new Font(null, Font.BOLD, 18); + + private static final int PADDING_L = 9; + private static final int PADDING_R = 11; + private static final int LINE_HEIGHT = 32; + private static final int DELIMITER_Y = 34; + + private final Player player; + private final Color color; + + private final PlayerPanelImageCache cache; + + private int centerY; + + //paint context variables + private Graphics2D g2; + private int bx, by; + + private String mouseOverKey = null; + + public PlayerPanel(Client client, Player player, PlayerPanelImageCache cache) { + super(client); + this.player = player; + this.cache = cache; + this.color = client.getPlayerColor(player); + } + + private void drawDelimiter(int y) { + g2.setColor(DELIM_TOP_COLOR); + g2.drawLine(PADDING_L, y, PANEL_WIDTH /*-PADDING_R*/, y); + g2.setColor(DELIM_BOTTOM_COLOR); + g2.drawLine(PADDING_L, y+1, PANEL_WIDTH /*-PADDING_R*/, y+1); + } + + private void drawTextShadow(String text, int x, int y) { + //TODO shadow color based on color ?? + /*g2.setColor(Color.DARK_GRAY); + g2.drawString(text, x+0.8f, y+0.7f);*/ + g2.setColor(ControlPanel.FONT_SHADOW_COLOR); + g2.drawString(text, x+0.6f, y+0.5f); + g2.setColor(color); + g2.drawString(text, x, y); + } + + private Rectangle drawMeepleBox(Player playerKey, String imgKey, int count, boolean showOne) { + return drawMeepleBox(playerKey, imgKey, count, showOne, null, false); + } + + private Rectangle drawMeepleBox(Player playerKey, String imgKey, int count, boolean showOne, Object regionData) { + return drawMeepleBox(playerKey, imgKey, count, showOne, regionData, false); + } + + private Rectangle drawMeepleBox(Player playerKey, String imgKey, int count, boolean showOne, Object regionData, boolean active) { + if (count == 0) return null; + + int w = 30; + if (count > 1 || (count == 1 && showOne)) { + w = count < 10 ? 47 : 60; + } + int h = 22; + if (bx+w > PANEL_WIDTH-PADDING_R) { + bx = PADDING_L; + by += LINE_HEIGHT; + } + g2.setColor(active ? Color.BLACK : Color.WHITE); + g2.fillRoundRect(bx, by, w, h, 8, 8); + g2.drawImage(cache.get(playerKey, imgKey), bx, by-4, null); + + Rectangle rect = null; + if (regionData != null) { + rect = new Rectangle(bx, by-4, w, h+8); + getMouseRegions().add(new MouseListeningRegion(rect, this, regionData)); + } + + if (count > 1 || (count == 1 && showOne)) { + g2.setColor(active ? Color.WHITE : Color.BLACK); + g2.drawString(""+count, bx+LINE_HEIGHT, by+17); + } + bx += w + 8; + return rect; + } + + /* + * translates parentGraphics, which is not much clean! + */ + @Override + public void paintComponent(Graphics2D parentGraphics) { + super.paintComponent(parentGraphics); + + Game game = client.getGame(); + +// GridPanel gp = client.getGridPanel(); + +// boolean isActive = game.getActivePlayer() == player; +// boolean playerTurn = game.getTurnPlayer() == player; + +// gp.profile(" > get flags"); + + BufferedImage bimg = UiUtils.newTransparentImage(PANEL_WIDTH, 200); + g2 = bimg.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + +// gp.profile(" > create buffer"); + + drawDelimiter(DELIMITER_Y); + + g2.setFont(FONT_POINTS); + drawTextShadow(""+player.getPoints(), PADDING_L, 27); + + g2.setFont(FONT_NICKNAME); + drawTextShadow(player.getNick(), 78, 27); + +// gp.profile(" > nick & score"); + + g2.setFont(FONT_MEEPLE); + bx = PADDING_L; + by = 43; + + int small = 0; + String smallImgKey = SmallFollower.class.getSimpleName(); + for (Follower f : Iterables.filter(player.getFollowers(), MeeplePredicates.inSupply())) { + //instanceof cannot be used because of Phantom + if (f.getClass().equals(SmallFollower.class)) { + small++; + } else { //all small followers are at beginning of collection + drawMeepleBox(player, smallImgKey, small, true); + small = 0; + drawMeepleBox(player, f.getClass().getSimpleName(), 1, false); + } + } + drawMeepleBox(player, smallImgKey, small, true); //case when only small followers are in collection (not drawn yet) + +// gp.profile(" > followers"); + + for (Special meeple : Iterables.filter(player.getSpecialMeeples(), MeeplePredicates.inSupply())) { + drawMeepleBox(player, meeple.getClass().getSimpleName(), 1, false); + } + +// gp.profile(" > special"); + + AbbeyCapability abbeyCap = game.getCapability(AbbeyCapability.class); + TowerCapability towerCap = game.getCapability(TowerCapability.class); + BridgeCapability bridgeCap = game.getCapability(BridgeCapability.class); + CastleCapability castleCap = game.getCapability(CastleCapability.class); + KingScoutCapability kingScoutCap = game.getCapability(KingScoutCapability.class); + ClothWineGrainCapability cwgCap = game.getCapability(ClothWineGrainCapability.class); + + if (abbeyCap != null) { + drawMeepleBox(null, "abbey", abbeyCap.hasUnusedAbbey(player) ? 1 : 0, false); + } + + if (towerCap != null) { + drawMeepleBox(null, "towerpiece", towerCap.getTowerPieces(player), true); + getMouseRegions().clear(); + } + + if (bridgeCap != null) { + drawMeepleBox(null, "bridge", bridgeCap.getPlayerBridges(player), true); + } + if (castleCap != null) { + drawMeepleBox(null, "castle", castleCap.getPlayerCastles(player), true); + } + + if (kingScoutCap != null) { + if (kingScoutCap.getKing() == player) { + Rectangle r = drawMeepleBox(null, "king", 1, false, "king"); + if ("king".equals(mouseOverKey)) { + g2.setFont(FONT_KING_SCOUT_OVERLAY); + g2.setColor(KING_SCOUT_OVERLAY); + g2.fillRect(r.x, r.y, r.width, r.height); + g2.setColor(Color.WHITE); + int size = kingScoutCap.getBiggestCitySize(); + g2.drawString((size < 10 ? " " : "") + size, r.x+2, r.y+20); + g2.setFont(FONT_MEEPLE); + } + } + if (kingScoutCap.getRobberBaron() == player) { + Rectangle r = drawMeepleBox(null, "robber", 1, false, "robber"); + if ("robber".equals(mouseOverKey)) { + g2.setFont(FONT_KING_SCOUT_OVERLAY); + g2.setColor(KING_SCOUT_OVERLAY); + g2.fillRect(r.x, r.y, r.width, r.height); + g2.setColor(Color.WHITE); + int size = kingScoutCap.getLongestRoadLength(); + g2.drawString((size < 10 ? " " : "") + size, r.x+2, r.y+20); + g2.setFont(FONT_MEEPLE); + } + } + } + if (cwgCap != null) { + drawMeepleBox(null, "cloth", cwgCap.getTradeResources(player, TradeResource.CLOTH), true); + drawMeepleBox(null, "grain", cwgCap.getTradeResources(player, TradeResource.GRAIN), true); + drawMeepleBox(null, "wine", cwgCap.getTradeResources(player, TradeResource.WINE), true); + } + if (towerCap != null) { + List capturedFigures = towerCap.getPrisoners().get(player); + Map, Integer> groupedByType; + if (!capturedFigures.isEmpty()) { + groupedByType = new HashMap<>(); + for (Player opponent : game.getAllPlayers()) { + if (opponent == player) continue; + boolean isOpponentActive = game.getActivePlayer() == opponent; + boolean clickable = isOpponentActive && !towerCap.isRansomPaidThisTurn(); + for (Follower f : capturedFigures) { + if (f.getPlayer() == opponent) { + Integer prevVal = groupedByType.get(f.getClass()); + groupedByType.put(f.getClass(), prevVal == null ? 1 : prevVal+1); + } + } + for (Entry, Integer> entry : groupedByType.entrySet()) { + drawMeepleBox(opponent, entry.getKey().getSimpleName(), entry.getValue(), false, + clickable ? entry.getKey() : null, clickable + ); + } + groupedByType.clear(); + } + } + } + +// gp.profile(" > expansions"); + + + int realHeight = by + (bx > PADDING_L ? LINE_HEIGHT : 0); + +// if (isActive) { +// //TODO +// //parentGraphics.setColor(Color.BLACK); +// //parentGraphics.fillRoundRect(0, -5, PANEL_WIDTH+CORNER_DIAMETER, realHeight+10, CORNER_DIAMETER, CORNER_DIAMETER); +// } + + parentGraphics.setColor(PLAYER_BG_COLOR); + parentGraphics.fillRoundRect(0, 0, PANEL_WIDTH+CORNER_DIAMETER, realHeight, CORNER_DIAMETER, CORNER_DIAMETER); + + centerY = (int) parentGraphics.getTransform().getTranslateY() + realHeight/2; + + parentGraphics.drawImage(bimg, 0, 0, PANEL_WIDTH, realHeight, 0, 0, PANEL_WIDTH, realHeight, null); + parentGraphics.translate(0, realHeight); //add also padding + + g2 = null; + +// gp.profile(" > complete"); + } + + public int getCenterY() { + return centerY; + } + + @SuppressWarnings("unchecked") + @Override + public void mouseClicked(MouseEvent e, MouseListeningRegion origin) { + if (!(origin.getData() instanceof Class)) return; + Class followerClass = (Class) origin.getData(); + TowerCapability tg = client.getGame().getCapability(TowerCapability.class); + if (!tg.isRansomPaidThisTurn()) { + if (client.getSettings().isConfirmRansomPayment()) { + String options[] = {_("Pay ransom"), _("Cancel") }; + int result = JOptionPane.showOptionDialog(client, + _("Do you really want to pay 3 points to release prisoner?"), + _("Confirm ransom payment"), + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + if (JOptionPane.YES_OPTION != result) return; + } + client.getServer().payRansom(player.getIndex(), followerClass); + } + } + + @Override + public void mouseEntered(MouseEvent e, MouseListeningRegion origin) { + if (origin.getData() instanceof String) { + mouseOverKey = (String) origin.getData(); + client.getGridPanel().repaint(); + } else { + TowerCapability tg = client.getGame().getCapability(TowerCapability.class); + if (!tg.isRansomPaidThisTurn()) { + client.getGridPanel().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + } + } + + @Override + public void mouseExited(MouseEvent e, MouseListeningRegion origin) { + if (mouseOverKey != null) { + mouseOverKey = null; + client.getGridPanel().repaint(); + } else { + client.getGridPanel().setCursor(Cursor.getDefaultCursor()); + } + } + +} + diff --git a/src/main/java/com/jcloisterzone/ui/controls/PlayerPanelImageCache.java b/src/main/java/com/jcloisterzone/ui/controls/PlayerPanelImageCache.java index 7988c1cfa..c701bdb8d 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/PlayerPanelImageCache.java +++ b/src/main/java/com/jcloisterzone/ui/controls/PlayerPanelImageCache.java @@ -1,87 +1,87 @@ -package com.jcloisterzone.ui.controls; - -import java.awt.Color; -import java.awt.Image; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.ImageIcon; - -import com.jcloisterzone.Player; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.capability.BarnCapability; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.game.capability.ClothWineGrainCapability; -import com.jcloisterzone.game.capability.KingScoutCapability; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.theme.FigureTheme; - -public class PlayerPanelImageCache { - - private final Client client; - private Map scaledImages = new HashMap<>(); - - public PlayerPanelImageCache(Client client) { - this.client = client; - scaleImages(); - } - - public Image get(Player player, String key) { - if (player == null) { - return scaledImages.get(key); - } else { - return scaledImages.get(player.getIndex() + key); - } - } - - private Image scaleImage(Image img) { - return new ImageIcon(img.getScaledInstance(30, 30, Image.SCALE_SMOOTH)).getImage(); - } - - private void scaleFigureImages(Player player, Color color, Collection meeples) { - FigureTheme theme = client.getFigureTheme(); - //Image img = theme.getFigureImage(type, color, null); - for (Meeple f : meeples) { - String key = player.getIndex() + f.getClass().getSimpleName(); - if (!scaledImages.containsKey(key)) { - scaledImages.put(key, scaleImage(theme.getFigureImage(f.getClass(), color, null))); - } - } - } - - private void scaleImages() { - FigureTheme theme = client.getFigureTheme(); - for (Player player : client.getGame().getAllPlayers()) { - Color color = client.getPlayerColor(player); - scaleFigureImages(player, color, player.getFollowers()); - scaleFigureImages(player, color, player.getSpecialMeeples()); - } - TowerCapability tower = client.getGame().getCapability(TowerCapability.class); - if (tower != null) { - scaledImages.put("towerpiece", scaleImage(theme.getNeutralImage("towerpiece"))); - } - KingScoutCapability ks = client.getGame().getCapability(KingScoutCapability.class); - if (ks != null) { - scaledImages.put("king", scaleImage(theme.getNeutralImage("king"))); - scaledImages.put("robber", scaleImage(theme.getNeutralImage("robber"))); - } - BazaarCapability bcb = client.getGame().getCapability(BazaarCapability.class); - if (bcb != null) { - scaledImages.put("bridge", scaleImage(theme.getNeutralImage("bridge"))); - scaledImages.put("castle", scaleImage(theme.getNeutralImage("castle"))); - } - ClothWineGrainCapability cwg = client.getGame().getCapability(ClothWineGrainCapability.class); - if (cwg != null) { - scaledImages.put("cloth", theme.getNeutralImage("cloth")); - scaledImages.put("grain", theme.getNeutralImage("grain")); - scaledImages.put("wine", theme.getNeutralImage("wine")); - } - BarnCapability ab = client.getGame().getCapability(BarnCapability.class); - if (ab != null) { - scaledImages.put("abbey", scaleImage(client.getResourceManager().getAbbeyImage())); - } - } - -} +package com.jcloisterzone.ui.controls; + +import java.awt.Color; +import java.awt.Image; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.ImageIcon; + +import com.jcloisterzone.Player; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.capability.BarnCapability; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.game.capability.ClothWineGrainCapability; +import com.jcloisterzone.game.capability.KingScoutCapability; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.theme.FigureTheme; + +public class PlayerPanelImageCache { + + private final Client client; + private Map scaledImages = new HashMap<>(); + + public PlayerPanelImageCache(Client client) { + this.client = client; + scaleImages(); + } + + public Image get(Player player, String key) { + if (player == null) { + return scaledImages.get(key); + } else { + return scaledImages.get(player.getIndex() + key); + } + } + + private Image scaleImage(Image img) { + return new ImageIcon(img.getScaledInstance(30, 30, Image.SCALE_SMOOTH)).getImage(); + } + + private void scaleFigureImages(Player player, Color color, Collection meeples) { + FigureTheme theme = client.getFigureTheme(); + //Image img = theme.getFigureImage(type, color, null); + for (Meeple f : meeples) { + String key = player.getIndex() + f.getClass().getSimpleName(); + if (!scaledImages.containsKey(key)) { + scaledImages.put(key, scaleImage(theme.getFigureImage(f.getClass(), color, null))); + } + } + } + + private void scaleImages() { + FigureTheme theme = client.getFigureTheme(); + for (Player player : client.getGame().getAllPlayers()) { + Color color = client.getPlayerColor(player); + scaleFigureImages(player, color, player.getFollowers()); + scaleFigureImages(player, color, player.getSpecialMeeples()); + } + TowerCapability tower = client.getGame().getCapability(TowerCapability.class); + if (tower != null) { + scaledImages.put("towerpiece", scaleImage(theme.getNeutralImage("towerpiece"))); + } + KingScoutCapability ks = client.getGame().getCapability(KingScoutCapability.class); + if (ks != null) { + scaledImages.put("king", scaleImage(theme.getNeutralImage("king"))); + scaledImages.put("robber", scaleImage(theme.getNeutralImage("robber"))); + } + BazaarCapability bcb = client.getGame().getCapability(BazaarCapability.class); + if (bcb != null) { + scaledImages.put("bridge", scaleImage(theme.getNeutralImage("bridge"))); + scaledImages.put("castle", scaleImage(theme.getNeutralImage("castle"))); + } + ClothWineGrainCapability cwg = client.getGame().getCapability(ClothWineGrainCapability.class); + if (cwg != null) { + scaledImages.put("cloth", theme.getNeutralImage("cloth")); + scaledImages.put("grain", theme.getNeutralImage("grain")); + scaledImages.put("wine", theme.getNeutralImage("wine")); + } + BarnCapability ab = client.getGame().getCapability(BarnCapability.class); + if (ab != null) { + scaledImages.put("abbey", scaleImage(client.getResourceManager().getAbbeyImage())); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/controls/RegionMouseListener.java b/src/main/java/com/jcloisterzone/ui/controls/RegionMouseListener.java index 63f767392..c43678d98 100644 --- a/src/main/java/com/jcloisterzone/ui/controls/RegionMouseListener.java +++ b/src/main/java/com/jcloisterzone/ui/controls/RegionMouseListener.java @@ -1,11 +1,11 @@ -package com.jcloisterzone.ui.controls; - -import java.awt.event.MouseEvent; - -public interface RegionMouseListener { - - public void mouseClicked(MouseEvent e, MouseListeningRegion origin); - public void mouseEntered(MouseEvent e, MouseListeningRegion origin); - public void mouseExited(MouseEvent e, MouseListeningRegion origin); - +package com.jcloisterzone.ui.controls; + +import java.awt.event.MouseEvent; + +public interface RegionMouseListener { + + public void mouseClicked(MouseEvent e, MouseListeningRegion origin); + public void mouseEntered(MouseEvent e, MouseListeningRegion origin); + public void mouseExited(MouseEvent e, MouseListeningRegion origin); + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/dialog/AboutDialog.java b/src/main/java/com/jcloisterzone/ui/dialog/AboutDialog.java index e8c375819..da6b94df9 100644 --- a/src/main/java/com/jcloisterzone/ui/dialog/AboutDialog.java +++ b/src/main/java/com/jcloisterzone/ui/dialog/AboutDialog.java @@ -1,90 +1,90 @@ -package com.jcloisterzone.ui.dialog; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Toolkit; - -import javax.swing.ImageIcon; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; - -import com.jcloisterzone.Application; -import com.jcloisterzone.ui.MultiLineLabel; - - -public class AboutDialog extends JDialog { - - private static final long serialVersionUID = 4697784648983290492L; - - private final JPanel contentPanel = new JPanel(); - - /** - * Launch the application. - */ - public static void main(String[] args) { - try { - AboutDialog dialog = new AboutDialog(); - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * Create the dialog. - */ - public AboutDialog() { - setTitle(_("About application")); - centerDialog(450, 199); - contentPanel.setBounds(0, 0, 434, 167); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); - getContentPane().add(contentPanel); - contentPanel.setLayout(null); - - JLabel header = new JLabel("JCloisterZone"); - header.setBounds(167, 11, 235, 43); - header.setFont(new Font(null, Font.BOLD, 27)); - contentPanel.add(header); - - JLabel icon = new JLabel(""); - icon.setIcon(new ImageIcon(AboutDialog.class.getResource("/sysimages/ico.png"))); - icon.setBounds(10, 11, 119, 120); - contentPanel.add(icon); - - JLabel url = new JLabel("http://www.jcloisterzone.com/"); - url.setBounds(167, 46, 235, 26); - contentPanel.add(url); - - JLabel version = new JLabel(_("Version") + ": " + Application.VERSION + " (" + Application.BUILD_DATE + ")"); - version.setBounds(167, 77, 235, 21); - contentPanel.add(version); - - MultiLineLabel license = new MultiLineLabel(_("Distributed under the terms of GNU Affero General Public License version 3")); - license.setBounds(167, 123, 235, 37); - license.setRows(3); - contentPanel.add(license); - - JLabel lblAuthor = new JLabel("Roman Krejčík "); - lblAuthor.setVerticalAlignment(SwingConstants.TOP); - lblAuthor.setBounds(167, 98, 267, 26); - contentPanel.add(lblAuthor); - - setResizable(false); - setVisible(true); - } - - private void centerDialog(int width, int height) { - Toolkit tk = Toolkit.getDefaultToolkit(); - Dimension screenSize = tk.getScreenSize(); - int screenHeight = screenSize.height; - int screenWidth = screenSize.width; - setBounds(screenWidth / 2 - width / 2, screenHeight / 3 - height / 2, width, height); - - } -} +package com.jcloisterzone.ui.dialog; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Toolkit; + +import javax.swing.ImageIcon; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; + +import com.jcloisterzone.Application; +import com.jcloisterzone.ui.MultiLineLabel; + + +public class AboutDialog extends JDialog { + + private static final long serialVersionUID = 4697784648983290492L; + + private final JPanel contentPanel = new JPanel(); + + /** + * Launch the application. + */ + public static void main(String[] args) { + try { + AboutDialog dialog = new AboutDialog(); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Create the dialog. + */ + public AboutDialog() { + setTitle(_("About application")); + centerDialog(450, 199); + contentPanel.setBounds(0, 0, 434, 167); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + getContentPane().add(contentPanel); + contentPanel.setLayout(null); + + JLabel header = new JLabel("JCloisterZone"); + header.setBounds(167, 11, 235, 43); + header.setFont(new Font(null, Font.BOLD, 27)); + contentPanel.add(header); + + JLabel icon = new JLabel(""); + icon.setIcon(new ImageIcon(AboutDialog.class.getResource("/sysimages/ico.png"))); + icon.setBounds(10, 11, 119, 120); + contentPanel.add(icon); + + JLabel url = new JLabel("http://www.jcloisterzone.com/"); + url.setBounds(167, 46, 235, 26); + contentPanel.add(url); + + JLabel version = new JLabel(_("Version") + ": " + Application.VERSION + " (" + Application.BUILD_DATE + ")"); + version.setBounds(167, 77, 235, 21); + contentPanel.add(version); + + MultiLineLabel license = new MultiLineLabel(_("Distributed under the terms of GNU Affero General Public License version 3")); + license.setBounds(167, 123, 235, 37); + license.setRows(3); + contentPanel.add(license); + + JLabel lblAuthor = new JLabel("Roman Krejčík "); + lblAuthor.setVerticalAlignment(SwingConstants.TOP); + lblAuthor.setBounds(167, 98, 267, 26); + contentPanel.add(lblAuthor); + + setResizable(false); + setVisible(true); + } + + private void centerDialog(int width, int height) { + Toolkit tk = Toolkit.getDefaultToolkit(); + Dimension screenSize = tk.getScreenSize(); + int screenHeight = screenSize.height; + int screenWidth = screenSize.width; + setBounds(screenWidth / 2 - width / 2, screenHeight / 3 - height / 2, width, height); + + } +} diff --git a/src/main/java/com/jcloisterzone/ui/dialog/AmbiguousUndeployDialog.java b/src/main/java/com/jcloisterzone/ui/dialog/AmbiguousUndeployDialog.java index 1fe1678cc..c005a450b 100644 --- a/src/main/java/com/jcloisterzone/ui/dialog/AmbiguousUndeployDialog.java +++ b/src/main/java/com/jcloisterzone/ui/dialog/AmbiguousUndeployDialog.java @@ -1,78 +1,78 @@ -package com.jcloisterzone.ui.dialog; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.List; - -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JLabel; - -import net.miginfocom.swing.MigLayout; - -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.Client; - -public class AmbiguousUndeployDialog extends JDialog { - - //private final Client client; - - private final int ICON_SIZE = 80; - - public AmbiguousUndeployDialog(Client client, List meeples, final AmbiguousUndeployDialogEvent handler) { - super(client); - //this.client = client; - - setTitle(_("Undeploy meeple")); - setModal(true); - setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - - Container pane = getContentPane(); - pane.setLayout(new MigLayout("nogrid", "", "")); - - pane.add(new JLabel(_("Select meeple to undeploy")), "wrap, gapbottom 15"); - - int gridx = 0; - for (final Meeple meeple : meeples) { - Color color = client.getPlayerColor(meeple.getPlayer()); - Image img = client.getFigureTheme().getFigureImage(meeple.getClass(), color, null); - img = img.getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH); - JButton button = new JButton(new ImageIcon(img)); - button.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent ev) { - dispose(); - handler.meepleTypeSelected(meeple); - } - }); - pane.add(button, "cell " + (gridx++) + " 1, height ::" + ICON_SIZE + ", width ::" + ICON_SIZE); - } - - pack(); - centerDialog(getWidth(), getHeight()); - setVisible(true); - } - - public static abstract class AmbiguousUndeployDialogEvent { - public abstract void meepleTypeSelected(Meeple meeple); - } - - //TODO copy&paste from About dialog - private void centerDialog(int width, int height) { - Toolkit tk = Toolkit.getDefaultToolkit(); - Dimension screenSize = tk.getScreenSize(); - int screenHeight = screenSize.height; - int screenWidth = screenSize.width; - setBounds(screenWidth / 2 - width / 2, screenHeight / 3 - height / 2, width, height); - - } - -} +package com.jcloisterzone.ui.dialog; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.List; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; + +import net.miginfocom.swing.MigLayout; + +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.Client; + +public class AmbiguousUndeployDialog extends JDialog { + + //private final Client client; + + private final int ICON_SIZE = 80; + + public AmbiguousUndeployDialog(Client client, List meeples, final AmbiguousUndeployDialogEvent handler) { + super(client); + //this.client = client; + + setTitle(_("Undeploy meeple")); + setModal(true); + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + + Container pane = getContentPane(); + pane.setLayout(new MigLayout("nogrid", "", "")); + + pane.add(new JLabel(_("Select meeple to undeploy")), "wrap, gapbottom 15"); + + int gridx = 0; + for (final Meeple meeple : meeples) { + Color color = client.getPlayerColor(meeple.getPlayer()); + Image img = client.getFigureTheme().getFigureImage(meeple.getClass(), color, null); + img = img.getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH); + JButton button = new JButton(new ImageIcon(img)); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ev) { + dispose(); + handler.meepleTypeSelected(meeple); + } + }); + pane.add(button, "cell " + (gridx++) + " 1, height ::" + ICON_SIZE + ", width ::" + ICON_SIZE); + } + + pack(); + centerDialog(getWidth(), getHeight()); + setVisible(true); + } + + public static abstract class AmbiguousUndeployDialogEvent { + public abstract void meepleTypeSelected(Meeple meeple); + } + + //TODO copy&paste from About dialog + private void centerDialog(int width, int height) { + Toolkit tk = Toolkit.getDefaultToolkit(); + Dimension screenSize = tk.getScreenSize(); + int screenHeight = screenSize.height; + int screenWidth = screenSize.width; + setBounds(screenWidth / 2 - width / 2, screenHeight / 3 - height / 2, width, height); + + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/dialog/DiscardedTilesDialog.java b/src/main/java/com/jcloisterzone/ui/dialog/DiscardedTilesDialog.java index 471dc72ac..00183ed6d 100644 --- a/src/main/java/com/jcloisterzone/ui/dialog/DiscardedTilesDialog.java +++ b/src/main/java/com/jcloisterzone/ui/dialog/DiscardedTilesDialog.java @@ -1,59 +1,59 @@ -package com.jcloisterzone.ui.dialog; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Container; -import java.awt.Image; -import java.awt.Point; - -import javax.swing.ImageIcon; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JScrollPane; - -import net.miginfocom.swing.MigLayout; - -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.ui.Client; - -public class DiscardedTilesDialog extends JDialog { - - public static final int ICON_SIZE = 120; - - private final Client client; - private JPanel panel; - private JScrollPane scroll; - - public DiscardedTilesDialog(Client client) { - super(client); - this.client = client; - - setTitle(_("Discarded tiles")); - Point p = client.getLocation(); - setLocation(p.x+200,p.y+150); - - setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - - Container pane = getContentPane(); - pane.setLayout(new MigLayout("", "[grow]", "[][]")); - pane.add(new JLabel(_("These tiles have been discarded during the game")), "wrap, growx, gapbottom 10"); - - panel = new JPanel(); - scroll = new JScrollPane(panel); - pane.add(scroll, "wrap, grow, width 400::, height 150::"); - scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); - scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); - - panel.setLayout(new MigLayout("", "[]", "")); - pack(); - } - - public void addTile(Tile tile) { - Image icon = client.getResourceManager().getTileImage(tile).getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_FAST); - panel.add(new JLabel(new ImageIcon(icon)), ""); - scroll.getViewport().setViewPosition(new Point(panel.getWidth(), 0)); - } - -} - +package com.jcloisterzone.ui.dialog; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Container; +import java.awt.Image; +import java.awt.Point; + +import javax.swing.ImageIcon; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import net.miginfocom.swing.MigLayout; + +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.ui.Client; + +public class DiscardedTilesDialog extends JDialog { + + public static final int ICON_SIZE = 120; + + private final Client client; + private JPanel panel; + private JScrollPane scroll; + + public DiscardedTilesDialog(Client client) { + super(client); + this.client = client; + + setTitle(_("Discarded tiles")); + Point p = client.getLocation(); + setLocation(p.x+200,p.y+150); + + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + + Container pane = getContentPane(); + pane.setLayout(new MigLayout("", "[grow]", "[][]")); + pane.add(new JLabel(_("These tiles have been discarded during the game")), "wrap, growx, gapbottom 10"); + + panel = new JPanel(); + scroll = new JScrollPane(panel); + pane.add(scroll, "wrap, grow, width 400::, height 150::"); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); + + panel.setLayout(new MigLayout("", "[]", "")); + pack(); + } + + public void addTile(Tile tile) { + Image icon = client.getResourceManager().getTileImage(tile).getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_FAST); + panel.add(new JLabel(new ImageIcon(icon)), ""); + scroll.getViewport().setViewPosition(new Point(panel.getWidth(), 0)); + } + +} + diff --git a/src/main/java/com/jcloisterzone/ui/dialog/GameOverDialog.java b/src/main/java/com/jcloisterzone/ui/dialog/GameOverDialog.java index ca7894031..d984e9cf4 100644 --- a/src/main/java/com/jcloisterzone/ui/dialog/GameOverDialog.java +++ b/src/main/java/com/jcloisterzone/ui/dialog/GameOverDialog.java @@ -1,130 +1,130 @@ -package com.jcloisterzone.ui.dialog; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.Container; -import java.awt.Image; -import java.awt.Point; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import javax.swing.Icon; -import javax.swing.ImageIcon; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.SwingConstants; - -import net.miginfocom.swing.MigLayout; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PointCategory; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.ui.Client; - -public class GameOverDialog extends JDialog { - - private final Client client; - - public GameOverDialog(Client client) { - super(client); - this.client = client; - - setTitle(_("Game overview")); - Point p = client.getLocation(); - setLocation(p.x+200,p.y+150); - setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - - Container pane = getContentPane(); - pane.setLayout(new MigLayout("", "[]", "[][]10[]10[]20[][][][][]20[][]20[][][]")); - int gridx = 0, gridy = 1; - - pane.add(new JLabel(_("Player")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Rank")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Total points")), getLegendSpec(0, gridy++)); - - pane.add(new JLabel(_("Roads")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Cities")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Cloisters")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Farms")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Castles")), getLegendSpec(0, gridy++)); - - pane.add(new JLabel(_("The biggest city")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("The longest road")), getLegendSpec(0, gridy++)); - - pane.add(new JLabel(_("Trade goods")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Fairy")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Tower ransom")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Bazaars")), getLegendSpec(0, gridy++)); - pane.add(new JLabel(_("Wind rose")), getLegendSpec(0, gridy++)); - - Player[] players = getSortedPlayers().toArray(new Player[client.getGame().getAllPlayers().length]); - for (Player player : players) { - gridy = 0; - Color color = client.getPlayerColor(player); - Image img = client.getFigureTheme().getFigureImage(SmallFollower.class, color, null); - Icon icon = new ImageIcon(img.getScaledInstance(32, 32, Image.SCALE_SMOOTH)); - pane.add(new JLabel(icon, SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel(player.getNick(), SwingConstants.CENTER), getSpec(gridx, gridy++)); - - pane.add(new JLabel(getRank(players, gridx), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPoints(), SwingConstants.CENTER), getSpec(gridx, gridy++)); - - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.ROAD), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.CITY), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.CLOISTER), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.FARM), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.CASTLE), SwingConstants.CENTER), getSpec(gridx, gridy++)); - - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.BIGGEST_CITY), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.LONGEST_ROAD), SwingConstants.CENTER), getSpec(gridx, gridy++)); - - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.TRADE_GOODS), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.FAIRY), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.TOWER_RANSOM), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.BAZAAR_AUCTION), SwingConstants.CENTER), getSpec(gridx, gridy++)); - pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.WIND_ROSE), SwingConstants.CENTER), getSpec(gridx, gridy++)); - gridx++; - } - - pack(); - setVisible(true); - } - - private String getRank(Player[] players, int i) { - int endrank = i+1; - while(i > 0 && players[i-1].getPoints() == players[i].getPoints()) i--; //find start of group - while(endrank < players.length) { - if (players[endrank].getPoints() != players[i].getPoints()) break; - endrank++; - } - if (endrank == i+1) { - return "" + endrank; - } - return (i+1) + " - " + (endrank); - } - - private String getLegendSpec(int x, int y) { - return "cell " + x + " " + y + ", width 170::"; - } - - private String getSpec(int x, int y) { - return "cell " + x + " " + y + ", width 120::, right"; - } - - private List getSortedPlayers() { - List players = Arrays.asList(client.getGame().getAllPlayers()); - Collections.sort(players, new Comparator() { - @Override - public int compare(Player o1, Player o2) { - if (o1.getPoints() < o2.getPoints()) return 1; - if (o1.getPoints() > o2.getPoints()) return -1; - return o1.getNick().compareToIgnoreCase(o2.getNick()); - } - }); - return players; - } - -} +package com.jcloisterzone.ui.dialog; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Image; +import java.awt.Point; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.SwingConstants; + +import net.miginfocom.swing.MigLayout; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PointCategory; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.ui.Client; + +public class GameOverDialog extends JDialog { + + private final Client client; + + public GameOverDialog(Client client) { + super(client); + this.client = client; + + setTitle(_("Game overview")); + Point p = client.getLocation(); + setLocation(p.x+200,p.y+150); + setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + + Container pane = getContentPane(); + pane.setLayout(new MigLayout("", "[]", "[][]10[]10[]20[][][][][]20[][]20[][][]")); + int gridx = 0, gridy = 1; + + pane.add(new JLabel(_("Player")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Rank")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Total points")), getLegendSpec(0, gridy++)); + + pane.add(new JLabel(_("Roads")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Cities")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Cloisters")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Farms")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Castles")), getLegendSpec(0, gridy++)); + + pane.add(new JLabel(_("The biggest city")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("The longest road")), getLegendSpec(0, gridy++)); + + pane.add(new JLabel(_("Trade goods")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Fairy")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Tower ransom")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Bazaars")), getLegendSpec(0, gridy++)); + pane.add(new JLabel(_("Wind rose")), getLegendSpec(0, gridy++)); + + Player[] players = getSortedPlayers().toArray(new Player[client.getGame().getAllPlayers().length]); + for (Player player : players) { + gridy = 0; + Color color = client.getPlayerColor(player); + Image img = client.getFigureTheme().getFigureImage(SmallFollower.class, color, null); + Icon icon = new ImageIcon(img.getScaledInstance(32, 32, Image.SCALE_SMOOTH)); + pane.add(new JLabel(icon, SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel(player.getNick(), SwingConstants.CENTER), getSpec(gridx, gridy++)); + + pane.add(new JLabel(getRank(players, gridx), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPoints(), SwingConstants.CENTER), getSpec(gridx, gridy++)); + + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.ROAD), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.CITY), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.CLOISTER), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.FARM), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.CASTLE), SwingConstants.CENTER), getSpec(gridx, gridy++)); + + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.BIGGEST_CITY), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.LONGEST_ROAD), SwingConstants.CENTER), getSpec(gridx, gridy++)); + + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.TRADE_GOODS), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.FAIRY), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.TOWER_RANSOM), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.BAZAAR_AUCTION), SwingConstants.CENTER), getSpec(gridx, gridy++)); + pane.add(new JLabel("" +player.getPointsInCategory(PointCategory.WIND_ROSE), SwingConstants.CENTER), getSpec(gridx, gridy++)); + gridx++; + } + + pack(); + setVisible(true); + } + + private String getRank(Player[] players, int i) { + int endrank = i+1; + while(i > 0 && players[i-1].getPoints() == players[i].getPoints()) i--; //find start of group + while(endrank < players.length) { + if (players[endrank].getPoints() != players[i].getPoints()) break; + endrank++; + } + if (endrank == i+1) { + return "" + endrank; + } + return (i+1) + " - " + (endrank); + } + + private String getLegendSpec(int x, int y) { + return "cell " + x + " " + y + ", width 170::"; + } + + private String getSpec(int x, int y) { + return "cell " + x + " " + y + ", width 120::, right"; + } + + private List getSortedPlayers() { + List players = Arrays.asList(client.getGame().getAllPlayers()); + Collections.sort(players, new Comparator() { + @Override + public int compare(Player o1, Player o2) { + if (o1.getPoints() < o2.getPoints()) return 1; + if (o1.getPoints() > o2.getPoints()) return -1; + return o1.getNick().compareToIgnoreCase(o2.getNick()); + } + }); + return players; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/dialog/HelpDialog.java b/src/main/java/com/jcloisterzone/ui/dialog/HelpDialog.java index a87da97b9..1f10fa7db 100644 --- a/src/main/java/com/jcloisterzone/ui/dialog/HelpDialog.java +++ b/src/main/java/com/jcloisterzone/ui/dialog/HelpDialog.java @@ -1,58 +1,58 @@ -package com.jcloisterzone.ui.dialog; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Toolkit; - -import javax.swing.JDialog; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; - -import com.jcloisterzone.ui.panel.HelpPanel; - - -public class HelpDialog extends JDialog { - - private static final long serialVersionUID = 4697784648983290492L; - - private final JPanel contentPanel = new JPanel(); - - /** - * Launch the application. - */ - public static void main(String[] args) { - try { - HelpDialog dialog = new HelpDialog(); - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * Create the dialog. - */ - public HelpDialog() { - setTitle(_("Controls")); - centerDialog(480, 300); - contentPanel.setBounds(0, 0, 480, 30); - contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); - contentPanel.setLayout(new BorderLayout()); - getContentPane().add(new HelpPanel()); - - setResizable(false); - setVisible(true); - } - - private void centerDialog(int width, int height) { - Toolkit tk = Toolkit.getDefaultToolkit(); - Dimension screenSize = tk.getScreenSize(); - int screenHeight = screenSize.height; - int screenWidth = screenSize.width; - setBounds(screenWidth / 2 - width / 2, screenHeight / 3 - height / 2, width, height); - - } -} +package com.jcloisterzone.ui.dialog; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Toolkit; + +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; + +import com.jcloisterzone.ui.panel.HelpPanel; + + +public class HelpDialog extends JDialog { + + private static final long serialVersionUID = 4697784648983290492L; + + private final JPanel contentPanel = new JPanel(); + + /** + * Launch the application. + */ + public static void main(String[] args) { + try { + HelpDialog dialog = new HelpDialog(); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Create the dialog. + */ + public HelpDialog() { + setTitle(_("Controls")); + centerDialog(480, 300); + contentPanel.setBounds(0, 0, 480, 30); + contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + contentPanel.setLayout(new BorderLayout()); + getContentPane().add(new HelpPanel()); + + setResizable(false); + setVisible(true); + } + + private void centerDialog(int width, int height) { + Toolkit tk = Toolkit.getDefaultToolkit(); + Dimension screenSize = tk.getScreenSize(); + int screenHeight = screenSize.height; + int screenWidth = screenSize.width; + setBounds(screenWidth / 2 - width / 2, screenHeight / 3 - height / 2, width, height); + + } +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/BazaarPanel.java b/src/main/java/com/jcloisterzone/ui/grid/BazaarPanel.java index f6584ca52..7f6e90e45 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/BazaarPanel.java +++ b/src/main/java/com/jcloisterzone/ui/grid/BazaarPanel.java @@ -1,372 +1,372 @@ -package com.jcloisterzone.ui.grid; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Insets; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ComponentEvent; -import java.awt.event.MouseEvent; -import java.util.ArrayList; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JSpinner; -import javax.swing.SpinnerNumberModel; - -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.capability.BazaarCapability; -import com.jcloisterzone.game.capability.BazaarItem; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.controls.ControlPanel; -import com.jcloisterzone.ui.controls.FakeComponent; -import com.jcloisterzone.ui.controls.MouseListeningRegion; -import com.jcloisterzone.ui.controls.RegionMouseListener; - -public class BazaarPanel extends FakeComponent implements RegionMouseListener, ForwardBackwardListener { - - private static Font FONT_HEADER = new Font(null, Font.BOLD, 18); - private static Font FONT_BUTTON = new Font(null, Font.BOLD, 12); - private static Font FONT_ACTION = new Font(null, Font.PLAIN, 12); - - public static enum BazaarPanelState { INACTIVE, SELECT_TILE, MAKE_BID, BUY_OR_SELL}; - - final BazaarCapability bcb; - - private int selectedItem = -1; - private BazaarPanelState state = BazaarPanelState.INACTIVE; - - private boolean refreshMouseRegions; - private final boolean noAuction; - - private JLabel hint, bidAmountLabel; - private JButton leftButton, rightButton; - private JSpinner bidAmount; - private SpinnerNumberModel bidAmountModel; - - - public BazaarPanel(Client client) { - super(client); - noAuction = client.getGame().hasRule(CustomRule.BAZAAR_NO_AUCTION); - bcb = client.getGame().getCapability(BazaarCapability.class); - bidAmountModel = new SpinnerNumberModel(0,0,1,1); - } - - @Override - public void componentResized(ComponentEvent e) { - refreshMouseRegions = true; - super.componentResized(e); - } - - @Override - public void registerSwingComponents(JComponent parent) { - hint = new JLabel(); - hint.setFont(FONT_ACTION); - parent.add(hint); - - leftButton = new JButton(); - leftButton.setFont(FONT_BUTTON); - leftButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - switch (state) { - case SELECT_TILE: - case MAKE_BID: - client.getServer().bazaarBid(selectedItem, bidAmountModel.getNumber().intValue()); - break; - case BUY_OR_SELL: - client.getServer().bazaarBuyOrSell(true); - break; - } - - } - }); - leftButton.setMargin(new Insets(1,1,1,1)); - leftButton.setVisible(false); - parent.add(leftButton); - - rightButton = new JButton(); - rightButton.setFont(FONT_BUTTON); - rightButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent arg0) { - switch (state) { - case SELECT_TILE: - case MAKE_BID: - client.getServer().pass(); - break; - case BUY_OR_SELL: - client.getServer().bazaarBuyOrSell(false); - break; - } - } - }); - rightButton.setMargin(new Insets(1,1,1,1)); - rightButton.setVisible(false); - parent.add(rightButton); - - if (!noAuction) { - bidAmount = new JSpinner(bidAmountModel); - bidAmount.setFont(new Font(null, Font.BOLD, 14)); - bidAmount.setVisible(false); - parent.add(bidAmount); - - bidAmountLabel = new JLabel(); - parent.add(bidAmountLabel); - } - } - - @Override - public void destroySwingComponents(JComponent parent) { - parent.remove(hint); - parent.remove(leftButton); - parent.remove(rightButton); - if (bidAmount != null) { - parent.remove(bidAmount); - parent.remove(bidAmountLabel); - } - } - - - public BazaarPanelState getState() { - return state; - } - - public void setState(BazaarPanelState state) { - this.state = state; - refreshMouseRegions = true; - switch (state) { - case INACTIVE: - hint.setText(""); - break; - case SELECT_TILE: - if (noAuction) { - hint.setText( _("Choose your tile.")); - } else { - hint.setText( _("Choose tile for next auction
and make initial offer.")); - updateBidRange(); - } - break; - case MAKE_BID: - hint.setText( _("Raise bid or pass.")); - updateBidRange(); - break; - case BUY_OR_SELL: - hint.setText(_("Buy or sell tile from latest bidder.")); - break; - } - if (bidAmountLabel != null) { - if (state == BazaarPanelState.BUY_OR_SELL) { - bidAmountLabel.setText(bcb.getCurrentBazaarAuction().getCurrentPrice() + " " + _("points")); - } else { - bidAmountLabel.setText(_("points")); - } - } - - layoutSwingComponents(client.getGridPanel()); - } - - - @Override - public void layoutSwingComponents(JComponent parent) { - //TODO hardcoded offset - but no better solution for now - int bazaarPanelX = parent.getWidth()-ControlPanel.PANEL_WIDTH-getWidth()-60; - int y = getRowY(selectedItem); - - hint.setBounds(bazaarPanelX+20, 24, ControlPanel.PANEL_WIDTH-10, 50); - - if (state == BazaarPanelState.SELECT_TILE) { - leftButton.setBounds(bazaarPanelX+130, y+55, 100, 25); - } else { - leftButton.setBounds(bazaarPanelX+118, y+55, 60, 25); - rightButton.setBounds(bazaarPanelX+182, y+55, 60, 25); - } - - if (bidAmount != null) { - //bidAmount.setBounds(bazaarPanelX+170, y+10, BazaarPanel.PANEL_WIDTH-190, 25); - bidAmount.setBounds(bazaarPanelX+130, y+15, 50, 24); - if (state == BazaarPanelState.BUY_OR_SELL) { - bidAmountLabel.setBounds(bazaarPanelX+130, y+15, 130, 24); - } else { - bidAmountLabel.setBounds(bazaarPanelX+190, y+15, 70, 24); - } - } - - switch (state) { - case BUY_OR_SELL: - leftButton.setText(_("Buy")); - rightButton.setText(_("Sell")); - leftButton.setVisible(true); - rightButton.setVisible(true); - if (bidAmount != null) { - bidAmount.setVisible(false); - bidAmountLabel.setVisible(true); - } - break; - case SELECT_TILE: - leftButton.setText(_("Select")); - leftButton.setVisible(true); - rightButton.setVisible(false); - if (bidAmount != null) { - bidAmount.setVisible(true); - bidAmountLabel.setVisible(true); - } - break; - case MAKE_BID: - leftButton.setText(_("Bid")); - rightButton.setText(_("Pass")); - leftButton.setVisible(true); - rightButton.setVisible(true); - if (bidAmount != null) { - bidAmount.setVisible(true); - bidAmountLabel.setVisible(true); - } - break; - default: - leftButton.setVisible(false); - rightButton.setVisible(false); - if (bidAmount != null) { - bidAmount.setVisible(false); - bidAmountLabel.setVisible(false); - } - break; - } - } - - - private void updateBidRange() { - //int points = client.getGame().getActivePlayer().getPoints(); - //bidAmountModel.setMaximum(points); - bidAmountModel.setMaximum(999); - - if (bcb.getCurrentBazaarAuction() == null) { - bidAmountModel.setMinimum(0); - bidAmountModel.setValue(0); - } else { - int min = bcb.getCurrentBazaarAuction().getCurrentPrice()+1; - bidAmountModel.setMinimum(min); - bidAmountModel.setValue(min); - } - } - - - public void setSelectedItem(int selectedItem) { - this.selectedItem = selectedItem; - layoutSwingComponents(client.getGridPanel()); - } - - public int getSelectedItem() { - return selectedItem; - } - - public void forward() { - if (state == BazaarPanelState.SELECT_TILE) { - ArrayList supply = bcb.getBazaarSupply(); - do { - selectedItem++; - if (selectedItem == supply.size()) { - selectedItem = 0; - } - } while (supply.get(selectedItem).getOwner() != null); - layoutSwingComponents(client.getGridPanel()); - client.getGridPanel().repaint(); - } - } - - public void backward() { - if (state == BazaarPanelState.SELECT_TILE) { - ArrayList supply = bcb.getBazaarSupply(); - do { - selectedItem--; - if (selectedItem == 0) { - selectedItem = supply.size()-1; - } - } while (supply.get(selectedItem).getOwner() != null); - layoutSwingComponents(client.getGridPanel()); - client.getGridPanel().repaint(); - } - } - - private int getRowY(int item) { - return 75 + 110 * item; - } - - @Override - public void paintComponent(Graphics2D g2) { - super.paintComponent(g2); - - if (bcb.getBazaarSupply() == null) return; - - GridPanel gp = client.getGridPanel(); - int h = gp.getHeight(); - - g2.setColor(ControlPanel.PANEL_BG_COLOR); - g2.fillRect(0 , 0, getWidth(), h); - - g2.setColor(ControlPanel.HEADER_FONT_COLOR); - g2.setFont(FONT_HEADER); - g2.drawString(_("Bazaar supply"), 20, 24); - - int y = 75; - - if (refreshMouseRegions) { - getMouseRegions().clear(); - } - - int i = 0; - for (BazaarItem bi : bcb.getBazaarSupply()) { - //TOOD cache supply images ?? - Image img = client.getResourceManager().getTileImage(bi.getTile()); - - if (selectedItem == i) { - g2.setColor(ControlPanel.PLAYER_BG_COLOR); - g2.fillRect(0, y-1, getWidth(), 92); - } - - if (refreshMouseRegions && state == BazaarPanelState.SELECT_TILE && bi.getOwner() == null) { - getMouseRegions().add(new MouseListeningRegion(new Rectangle(0, y-1, getWidth(), 102), this, i)); - } - - g2.drawImage(img, 20, y, 90, 90, null); - - if (bi.getCurrentBidder() == null && bi.getOwner() != null) { - Image playerImage = client.getFigureTheme().getFigureImage(SmallFollower.class, client.getPlayerColor(bi.getOwner()), null); - //TODO smooth image - g2.drawImage(playerImage, 140, y+12, 64, 64, null); - } - - i++; - y += 110; - } - this.refreshMouseRegions = false; - } - - @Override - public void mouseClicked(MouseEvent e, MouseListeningRegion origin) { - Object data = origin.getData(); - if (data instanceof Integer) { - int idx = (Integer) data; - if (selectedItem != -1 && selectedItem != idx) { - selectedItem = idx; - layoutSwingComponents(client.getGridPanel()); - client.getGridPanel().repaint(); - } - return; - } - throw new IllegalStateException(); - } - - @Override - public void mouseEntered(MouseEvent e, MouseListeningRegion origin) { - } - - @Override - public void mouseExited(MouseEvent e, MouseListeningRegion origin) { - } -} +package com.jcloisterzone.ui.grid; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.capability.BazaarCapability; +import com.jcloisterzone.game.capability.BazaarItem; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.controls.ControlPanel; +import com.jcloisterzone.ui.controls.FakeComponent; +import com.jcloisterzone.ui.controls.MouseListeningRegion; +import com.jcloisterzone.ui.controls.RegionMouseListener; + +public class BazaarPanel extends FakeComponent implements RegionMouseListener, ForwardBackwardListener { + + private static Font FONT_HEADER = new Font(null, Font.BOLD, 18); + private static Font FONT_BUTTON = new Font(null, Font.BOLD, 12); + private static Font FONT_ACTION = new Font(null, Font.PLAIN, 12); + + public static enum BazaarPanelState { INACTIVE, SELECT_TILE, MAKE_BID, BUY_OR_SELL}; + + final BazaarCapability bcb; + + private int selectedItem = -1; + private BazaarPanelState state = BazaarPanelState.INACTIVE; + + private boolean refreshMouseRegions; + private final boolean noAuction; + + private JLabel hint, bidAmountLabel; + private JButton leftButton, rightButton; + private JSpinner bidAmount; + private SpinnerNumberModel bidAmountModel; + + + public BazaarPanel(Client client) { + super(client); + noAuction = client.getGame().hasRule(CustomRule.BAZAAR_NO_AUCTION); + bcb = client.getGame().getCapability(BazaarCapability.class); + bidAmountModel = new SpinnerNumberModel(0,0,1,1); + } + + @Override + public void componentResized(ComponentEvent e) { + refreshMouseRegions = true; + super.componentResized(e); + } + + @Override + public void registerSwingComponents(JComponent parent) { + hint = new JLabel(); + hint.setFont(FONT_ACTION); + parent.add(hint); + + leftButton = new JButton(); + leftButton.setFont(FONT_BUTTON); + leftButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + switch (state) { + case SELECT_TILE: + case MAKE_BID: + client.getServer().bazaarBid(selectedItem, bidAmountModel.getNumber().intValue()); + break; + case BUY_OR_SELL: + client.getServer().bazaarBuyOrSell(true); + break; + } + + } + }); + leftButton.setMargin(new Insets(1,1,1,1)); + leftButton.setVisible(false); + parent.add(leftButton); + + rightButton = new JButton(); + rightButton.setFont(FONT_BUTTON); + rightButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + switch (state) { + case SELECT_TILE: + case MAKE_BID: + client.getServer().pass(); + break; + case BUY_OR_SELL: + client.getServer().bazaarBuyOrSell(false); + break; + } + } + }); + rightButton.setMargin(new Insets(1,1,1,1)); + rightButton.setVisible(false); + parent.add(rightButton); + + if (!noAuction) { + bidAmount = new JSpinner(bidAmountModel); + bidAmount.setFont(new Font(null, Font.BOLD, 14)); + bidAmount.setVisible(false); + parent.add(bidAmount); + + bidAmountLabel = new JLabel(); + parent.add(bidAmountLabel); + } + } + + @Override + public void destroySwingComponents(JComponent parent) { + parent.remove(hint); + parent.remove(leftButton); + parent.remove(rightButton); + if (bidAmount != null) { + parent.remove(bidAmount); + parent.remove(bidAmountLabel); + } + } + + + public BazaarPanelState getState() { + return state; + } + + public void setState(BazaarPanelState state) { + this.state = state; + refreshMouseRegions = true; + switch (state) { + case INACTIVE: + hint.setText(""); + break; + case SELECT_TILE: + if (noAuction) { + hint.setText( _("Choose your tile.")); + } else { + hint.setText( _("Choose tile for next auction
and make initial offer.")); + updateBidRange(); + } + break; + case MAKE_BID: + hint.setText( _("Raise bid or pass.")); + updateBidRange(); + break; + case BUY_OR_SELL: + hint.setText(_("Buy or sell tile from latest bidder.")); + break; + } + if (bidAmountLabel != null) { + if (state == BazaarPanelState.BUY_OR_SELL) { + bidAmountLabel.setText(bcb.getCurrentBazaarAuction().getCurrentPrice() + " " + _("points")); + } else { + bidAmountLabel.setText(_("points")); + } + } + + layoutSwingComponents(client.getGridPanel()); + } + + + @Override + public void layoutSwingComponents(JComponent parent) { + //TODO hardcoded offset - but no better solution for now + int bazaarPanelX = parent.getWidth()-ControlPanel.PANEL_WIDTH-getWidth()-60; + int y = getRowY(selectedItem); + + hint.setBounds(bazaarPanelX+20, 24, ControlPanel.PANEL_WIDTH-10, 50); + + if (state == BazaarPanelState.SELECT_TILE) { + leftButton.setBounds(bazaarPanelX+130, y+55, 100, 25); + } else { + leftButton.setBounds(bazaarPanelX+118, y+55, 60, 25); + rightButton.setBounds(bazaarPanelX+182, y+55, 60, 25); + } + + if (bidAmount != null) { + //bidAmount.setBounds(bazaarPanelX+170, y+10, BazaarPanel.PANEL_WIDTH-190, 25); + bidAmount.setBounds(bazaarPanelX+130, y+15, 50, 24); + if (state == BazaarPanelState.BUY_OR_SELL) { + bidAmountLabel.setBounds(bazaarPanelX+130, y+15, 130, 24); + } else { + bidAmountLabel.setBounds(bazaarPanelX+190, y+15, 70, 24); + } + } + + switch (state) { + case BUY_OR_SELL: + leftButton.setText(_("Buy")); + rightButton.setText(_("Sell")); + leftButton.setVisible(true); + rightButton.setVisible(true); + if (bidAmount != null) { + bidAmount.setVisible(false); + bidAmountLabel.setVisible(true); + } + break; + case SELECT_TILE: + leftButton.setText(_("Select")); + leftButton.setVisible(true); + rightButton.setVisible(false); + if (bidAmount != null) { + bidAmount.setVisible(true); + bidAmountLabel.setVisible(true); + } + break; + case MAKE_BID: + leftButton.setText(_("Bid")); + rightButton.setText(_("Pass")); + leftButton.setVisible(true); + rightButton.setVisible(true); + if (bidAmount != null) { + bidAmount.setVisible(true); + bidAmountLabel.setVisible(true); + } + break; + default: + leftButton.setVisible(false); + rightButton.setVisible(false); + if (bidAmount != null) { + bidAmount.setVisible(false); + bidAmountLabel.setVisible(false); + } + break; + } + } + + + private void updateBidRange() { + //int points = client.getGame().getActivePlayer().getPoints(); + //bidAmountModel.setMaximum(points); + bidAmountModel.setMaximum(999); + + if (bcb.getCurrentBazaarAuction() == null) { + bidAmountModel.setMinimum(0); + bidAmountModel.setValue(0); + } else { + int min = bcb.getCurrentBazaarAuction().getCurrentPrice()+1; + bidAmountModel.setMinimum(min); + bidAmountModel.setValue(min); + } + } + + + public void setSelectedItem(int selectedItem) { + this.selectedItem = selectedItem; + layoutSwingComponents(client.getGridPanel()); + } + + public int getSelectedItem() { + return selectedItem; + } + + public void forward() { + if (state == BazaarPanelState.SELECT_TILE) { + ArrayList supply = bcb.getBazaarSupply(); + do { + selectedItem++; + if (selectedItem == supply.size()) { + selectedItem = 0; + } + } while (supply.get(selectedItem).getOwner() != null); + layoutSwingComponents(client.getGridPanel()); + client.getGridPanel().repaint(); + } + } + + public void backward() { + if (state == BazaarPanelState.SELECT_TILE) { + ArrayList supply = bcb.getBazaarSupply(); + do { + selectedItem--; + if (selectedItem == 0) { + selectedItem = supply.size()-1; + } + } while (supply.get(selectedItem).getOwner() != null); + layoutSwingComponents(client.getGridPanel()); + client.getGridPanel().repaint(); + } + } + + private int getRowY(int item) { + return 75 + 110 * item; + } + + @Override + public void paintComponent(Graphics2D g2) { + super.paintComponent(g2); + + if (bcb.getBazaarSupply() == null) return; + + GridPanel gp = client.getGridPanel(); + int h = gp.getHeight(); + + g2.setColor(ControlPanel.PANEL_BG_COLOR); + g2.fillRect(0 , 0, getWidth(), h); + + g2.setColor(ControlPanel.HEADER_FONT_COLOR); + g2.setFont(FONT_HEADER); + g2.drawString(_("Bazaar supply"), 20, 24); + + int y = 75; + + if (refreshMouseRegions) { + getMouseRegions().clear(); + } + + int i = 0; + for (BazaarItem bi : bcb.getBazaarSupply()) { + //TOOD cache supply images ?? + Image img = client.getResourceManager().getTileImage(bi.getTile()); + + if (selectedItem == i) { + g2.setColor(ControlPanel.PLAYER_BG_COLOR); + g2.fillRect(0, y-1, getWidth(), 92); + } + + if (refreshMouseRegions && state == BazaarPanelState.SELECT_TILE && bi.getOwner() == null) { + getMouseRegions().add(new MouseListeningRegion(new Rectangle(0, y-1, getWidth(), 102), this, i)); + } + + g2.drawImage(img, 20, y, 90, 90, null); + + if (bi.getCurrentBidder() == null && bi.getOwner() != null) { + Image playerImage = client.getFigureTheme().getFigureImage(SmallFollower.class, client.getPlayerColor(bi.getOwner()), null); + //TODO smooth image + g2.drawImage(playerImage, 140, y+12, 64, 64, null); + } + + i++; + y += 110; + } + this.refreshMouseRegions = false; + } + + @Override + public void mouseClicked(MouseEvent e, MouseListeningRegion origin) { + Object data = origin.getData(); + if (data instanceof Integer) { + int idx = (Integer) data; + if (selectedItem != -1 && selectedItem != idx) { + selectedItem = idx; + layoutSwingComponents(client.getGridPanel()); + client.getGridPanel().repaint(); + } + return; + } + throw new IllegalStateException(); + } + + @Override + public void mouseEntered(MouseEvent e, MouseListeningRegion origin) { + } + + @Override + public void mouseExited(MouseEvent e, MouseListeningRegion origin) { + } +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/CornCirclesPanel.java b/src/main/java/com/jcloisterzone/ui/grid/CornCirclesPanel.java index 3f7df5102..831f2421b 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/CornCirclesPanel.java +++ b/src/main/java/com/jcloisterzone/ui/grid/CornCirclesPanel.java @@ -1,101 +1,101 @@ -package com.jcloisterzone.ui.grid; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JLabel; - -import com.jcloisterzone.feature.TileFeature; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.controls.ControlPanel; -import com.jcloisterzone.ui.controls.FakeComponent; - -public class CornCirclesPanel extends FakeComponent { - - private static Font FONT_HEADER = new Font(null, Font.BOLD, 18); - - private JLabel header, footer; - private JButton deploymentOption, removalOption; - - public CornCirclesPanel(Client client) { - super(client); - } - - @Override - public void registerSwingComponents(JComponent parent) { - - - header = new JLabel(_("Each player…")); - parent.add(header); - - deploymentOption = new JButton(); - //deploymentOption.setFont(FONT_BUTTON); - deploymentOption.setText(_("may deploy additional follower")); - deploymentOption.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - client.getServer().cornCiclesRemoveOrDeploy(false); - client.getGridPanel().setSecondPanel(null); - } - }); - parent.add(deploymentOption); - - removalOption = new JButton(); - removalOption.setText(_("must remove follower")); - removalOption.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - client.getServer().cornCiclesRemoveOrDeploy(true); - client.getGridPanel().setSecondPanel(null); - } - }); - - - parent.add(removalOption); - - String feature = TileFeature.getLocalizedNamefor (client.getGame().getCurrentTile().getCornCircle()); - footer = new JLabel(_("on/from a {0}.", feature.toLowerCase())); - parent.add(footer); - } - - @Override - public void layoutSwingComponents(JComponent parent) { - int panelX = client.getGridPanel().getWidth()-ControlPanel.PANEL_WIDTH-getWidth()-60, - left = panelX + 20; - - header.setBounds(left, 34, ControlPanel.PANEL_WIDTH-10, 30); - deploymentOption.setBounds(left, 64, ControlPanel.PANEL_WIDTH-10, 30); - removalOption.setBounds(left, 104, ControlPanel.PANEL_WIDTH-10, 30); - footer.setBounds(left, 134, ControlPanel.PANEL_WIDTH-10, 30); - } - - @Override - public void destroySwingComponents(JComponent parent) { - parent.remove(deploymentOption); - parent.remove(removalOption); - parent.remove(header); - parent.remove(footer); - } - - @Override - public void paintComponent(Graphics2D g2) { - super.paintComponent(g2); - - GridPanel gp = client.getGridPanel(); - int h = gp.getHeight(); - - g2.setColor(ControlPanel.PANEL_BG_COLOR); - g2.fillRect(0 , 0, getWidth(), h); - - g2.setColor(ControlPanel.HEADER_FONT_COLOR); - g2.setFont(FONT_HEADER); - g2.drawString(_("Corn circle"), 20, 24); - } - -} +package com.jcloisterzone.ui.grid; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; + +import com.jcloisterzone.feature.TileFeature; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.controls.ControlPanel; +import com.jcloisterzone.ui.controls.FakeComponent; + +public class CornCirclesPanel extends FakeComponent { + + private static Font FONT_HEADER = new Font(null, Font.BOLD, 18); + + private JLabel header, footer; + private JButton deploymentOption, removalOption; + + public CornCirclesPanel(Client client) { + super(client); + } + + @Override + public void registerSwingComponents(JComponent parent) { + + + header = new JLabel(_("Each player…")); + parent.add(header); + + deploymentOption = new JButton(); + //deploymentOption.setFont(FONT_BUTTON); + deploymentOption.setText(_("may deploy additional follower")); + deploymentOption.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + client.getServer().cornCiclesRemoveOrDeploy(false); + client.getGridPanel().setSecondPanel(null); + } + }); + parent.add(deploymentOption); + + removalOption = new JButton(); + removalOption.setText(_("must remove follower")); + removalOption.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + client.getServer().cornCiclesRemoveOrDeploy(true); + client.getGridPanel().setSecondPanel(null); + } + }); + + + parent.add(removalOption); + + String feature = TileFeature.getLocalizedNamefor (client.getGame().getCurrentTile().getCornCircle()); + footer = new JLabel(_("on/from a {0}.", feature.toLowerCase())); + parent.add(footer); + } + + @Override + public void layoutSwingComponents(JComponent parent) { + int panelX = client.getGridPanel().getWidth()-ControlPanel.PANEL_WIDTH-getWidth()-60, + left = panelX + 20; + + header.setBounds(left, 34, ControlPanel.PANEL_WIDTH-10, 30); + deploymentOption.setBounds(left, 64, ControlPanel.PANEL_WIDTH-10, 30); + removalOption.setBounds(left, 104, ControlPanel.PANEL_WIDTH-10, 30); + footer.setBounds(left, 134, ControlPanel.PANEL_WIDTH-10, 30); + } + + @Override + public void destroySwingComponents(JComponent parent) { + parent.remove(deploymentOption); + parent.remove(removalOption); + parent.remove(header); + parent.remove(footer); + } + + @Override + public void paintComponent(Graphics2D g2) { + super.paintComponent(g2); + + GridPanel gp = client.getGridPanel(); + int h = gp.getHeight(); + + g2.setColor(ControlPanel.PANEL_BG_COLOR); + g2.fillRect(0 , 0, getWidth(), h); + + g2.setColor(ControlPanel.HEADER_FONT_COLOR); + g2.setFont(FONT_HEADER); + g2.drawString(_("Corn circle"), 20, 24); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/DragInsensitiveMouseClickListener.java b/src/main/java/com/jcloisterzone/ui/grid/DragInsensitiveMouseClickListener.java index 6b6d60f65..ff1147e75 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/DragInsensitiveMouseClickListener.java +++ b/src/main/java/com/jcloisterzone/ui/grid/DragInsensitiveMouseClickListener.java @@ -1,77 +1,77 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.Component; -import java.awt.event.MouseEvent; - -import javax.swing.event.MouseInputListener; - -public class DragInsensitiveMouseClickListener implements MouseInputListener { - - protected static final int MAX_CLICK_DISTANCE = 15; - - private final MouseInputListener target; - - public MouseEvent pressed; - - public DragInsensitiveMouseClickListener(MouseInputListener target) { - this.target = target; - } - - @Override - public final void mousePressed(MouseEvent e) { - pressed = e; - target.mousePressed(e); - } - - private int getDragDistance(MouseEvent e) { - int distance = 0; - distance += Math.abs(pressed.getXOnScreen() - e.getXOnScreen()); - distance += Math.abs(pressed.getYOnScreen() - e.getYOnScreen()); - return distance; - } - - @Override - public final void mouseReleased(MouseEvent e) { - target.mouseReleased(e); - - if (pressed != null) { - if (getDragDistance(e) < MAX_CLICK_DISTANCE) { - MouseEvent clickEvent = new MouseEvent((Component) pressed.getSource(), - MouseEvent.MOUSE_CLICKED, e.getWhen(), pressed.getModifiers(), - pressed.getX(), pressed.getY(), pressed.getXOnScreen(), pressed.getYOnScreen(), - pressed.getClickCount(), pressed.isPopupTrigger(), pressed.getButton()); - target.mouseClicked(clickEvent); - } - pressed = null; - } - } - - @Override - public void mouseClicked(MouseEvent e) { - //do nothing, handled by pressed/released handlers - } - - @Override - public void mouseEntered(MouseEvent e) { - target.mouseEntered(e); - } - - @Override - public void mouseExited(MouseEvent e) { - target.mouseExited(e); - } - - @Override - public void mouseDragged(MouseEvent e) { - if (pressed != null) { - if (getDragDistance(e) < MAX_CLICK_DISTANCE) return; //do not trigger drag yet (distance is in "click" perimeter - pressed = null; - } - target.mouseDragged(e); - } - - @Override - public void mouseMoved(MouseEvent e) { - target.mouseMoved(e); - } -} +package com.jcloisterzone.ui.grid; + +import java.awt.Component; +import java.awt.event.MouseEvent; + +import javax.swing.event.MouseInputListener; + +public class DragInsensitiveMouseClickListener implements MouseInputListener { + + protected static final int MAX_CLICK_DISTANCE = 15; + + private final MouseInputListener target; + + public MouseEvent pressed; + + public DragInsensitiveMouseClickListener(MouseInputListener target) { + this.target = target; + } + + @Override + public final void mousePressed(MouseEvent e) { + pressed = e; + target.mousePressed(e); + } + + private int getDragDistance(MouseEvent e) { + int distance = 0; + distance += Math.abs(pressed.getXOnScreen() - e.getXOnScreen()); + distance += Math.abs(pressed.getYOnScreen() - e.getYOnScreen()); + return distance; + } + + @Override + public final void mouseReleased(MouseEvent e) { + target.mouseReleased(e); + + if (pressed != null) { + if (getDragDistance(e) < MAX_CLICK_DISTANCE) { + MouseEvent clickEvent = new MouseEvent((Component) pressed.getSource(), + MouseEvent.MOUSE_CLICKED, e.getWhen(), pressed.getModifiers(), + pressed.getX(), pressed.getY(), pressed.getXOnScreen(), pressed.getYOnScreen(), + pressed.getClickCount(), pressed.isPopupTrigger(), pressed.getButton()); + target.mouseClicked(clickEvent); + } + pressed = null; + } + } + + @Override + public void mouseClicked(MouseEvent e) { + //do nothing, handled by pressed/released handlers + } + + @Override + public void mouseEntered(MouseEvent e) { + target.mouseEntered(e); + } + + @Override + public void mouseExited(MouseEvent e) { + target.mouseExited(e); + } + + @Override + public void mouseDragged(MouseEvent e) { + if (pressed != null) { + if (getDragDistance(e) < MAX_CLICK_DISTANCE) return; //do not trigger drag yet (distance is in "click" perimeter + pressed = null; + } + target.mouseDragged(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + target.mouseMoved(e); + } +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/FlierPanel.java b/src/main/java/com/jcloisterzone/ui/grid/FlierPanel.java index 9d9a5e68a..556ab3c74 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/FlierPanel.java +++ b/src/main/java/com/jcloisterzone/ui/grid/FlierPanel.java @@ -1,90 +1,90 @@ -package com.jcloisterzone.ui.grid; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JLabel; - -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.controls.ControlPanel; -import com.jcloisterzone.ui.controls.FakeComponent; - -public class FlierPanel extends FakeComponent { - - private static Font FONT_HEADER = new Font(null, Font.BOLD, 18); - - private JLabel header; - private JButton rollButton; - private JLabel rollResult; - - public FlierPanel(Client client) { - super(client); - } - - @Override - public void registerSwingComponents(JComponent parent) { - header = new JLabel(_("Place follower as a flier")); - - parent.add(header); - - rollButton = new JButton(); - rollButton.setText(_("Roll a dice")); - rollButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - client.getServer().rollFlierDice(); - } - }); - - parent.add(rollButton); - - rollResult = new JLabel(); - rollResult.setVisible(false); - parent.add(rollResult); - } - - @Override - public void layoutSwingComponents(JComponent parent) { - int panelX = client.getGridPanel().getWidth()-ControlPanel.PANEL_WIDTH-getWidth()-60, - left = panelX + 20; - - header.setBounds(left, 34, ControlPanel.PANEL_WIDTH-10, 30); - rollButton.setBounds(left, 64, ControlPanel.PANEL_WIDTH-10, 30); - rollResult.setBounds(left, 64, ControlPanel.PANEL_WIDTH-10, 30); - } - - public void setFlierDistance(int distance) { - rollButton.setVisible(false); - rollResult.setText(_("distance")+" "+distance); - rollResult.setVisible(true); - } - - @Override - public void destroySwingComponents(JComponent parent) { - parent.remove(header); - parent.remove(rollButton); - parent.remove(rollResult); - } - - @Override - public void paintComponent(Graphics2D g2) { - super.paintComponent(g2); - - GridPanel gp = client.getGridPanel(); - int h = gp.getHeight(); - - g2.setColor(ControlPanel.PANEL_BG_COLOR); - g2.fillRect(0 , 0, getWidth(), h); - - g2.setColor(ControlPanel.HEADER_FONT_COLOR); - g2.setFont(FONT_HEADER); - g2.drawString(_("The Flier"), 20, 24); - } - -} +package com.jcloisterzone.ui.grid; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; + +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.controls.ControlPanel; +import com.jcloisterzone.ui.controls.FakeComponent; + +public class FlierPanel extends FakeComponent { + + private static Font FONT_HEADER = new Font(null, Font.BOLD, 18); + + private JLabel header; + private JButton rollButton; + private JLabel rollResult; + + public FlierPanel(Client client) { + super(client); + } + + @Override + public void registerSwingComponents(JComponent parent) { + header = new JLabel(_("Place follower as a flier")); + + parent.add(header); + + rollButton = new JButton(); + rollButton.setText(_("Roll a dice")); + rollButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + client.getServer().rollFlierDice(); + } + }); + + parent.add(rollButton); + + rollResult = new JLabel(); + rollResult.setVisible(false); + parent.add(rollResult); + } + + @Override + public void layoutSwingComponents(JComponent parent) { + int panelX = client.getGridPanel().getWidth()-ControlPanel.PANEL_WIDTH-getWidth()-60, + left = panelX + 20; + + header.setBounds(left, 34, ControlPanel.PANEL_WIDTH-10, 30); + rollButton.setBounds(left, 64, ControlPanel.PANEL_WIDTH-10, 30); + rollResult.setBounds(left, 64, ControlPanel.PANEL_WIDTH-10, 30); + } + + public void setFlierDistance(int distance) { + rollButton.setVisible(false); + rollResult.setText(_("distance")+" "+distance); + rollResult.setVisible(true); + } + + @Override + public void destroySwingComponents(JComponent parent) { + parent.remove(header); + parent.remove(rollButton); + parent.remove(rollResult); + } + + @Override + public void paintComponent(Graphics2D g2) { + super.paintComponent(g2); + + GridPanel gp = client.getGridPanel(); + int h = gp.getHeight(); + + g2.setColor(ControlPanel.PANEL_BG_COLOR); + g2.fillRect(0 , 0, getWidth(), h); + + g2.setColor(ControlPanel.HEADER_FONT_COLOR); + g2.setFont(FONT_HEADER); + g2.drawString(_("The Flier"), 20, 24); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/ForwardBackwardListener.java b/src/main/java/com/jcloisterzone/ui/grid/ForwardBackwardListener.java index 27a7b62a9..65aa9efd5 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/ForwardBackwardListener.java +++ b/src/main/java/com/jcloisterzone/ui/grid/ForwardBackwardListener.java @@ -1,8 +1,8 @@ -package com.jcloisterzone.ui.grid; - -public interface ForwardBackwardListener { - - void forward(); - void backward(); - -} +package com.jcloisterzone.ui.grid; + +public interface ForwardBackwardListener { + + void forward(); + void backward(); + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/GridLayer.java b/src/main/java/com/jcloisterzone/ui/grid/GridLayer.java index 59f56b4e4..e450308c1 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/GridLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/GridLayer.java @@ -1,31 +1,31 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.Graphics2D; -import java.util.Comparator; - -public interface GridLayer { - - void paint(Graphics2D g2); - - int getZIndex(); - - void zoomChanged(int squareSize); - - // void gridChanged(int left, int right, int top, int bottom); - - void layerAdded(); - - void layerRemoved(); - - public static final Comparator Z_INDEX_COMPARATOR = new Comparator() { - @Override - public int compare(GridLayer o1, GridLayer o2) { - if (o1.getZIndex() < o2.getZIndex()) - return -1; - if (o1.getZIndex() > o2.getZIndex()) - return 1; - return 0; - } - }; - -} +package com.jcloisterzone.ui.grid; + +import java.awt.Graphics2D; +import java.util.Comparator; + +public interface GridLayer { + + void paint(Graphics2D g2); + + int getZIndex(); + + void zoomChanged(int squareSize); + + // void gridChanged(int left, int right, int top, int bottom); + + void layerAdded(); + + void layerRemoved(); + + public static final Comparator Z_INDEX_COMPARATOR = new Comparator() { + @Override + public int compare(GridLayer o1, GridLayer o2) { + if (o1.getZIndex() < o2.getZIndex()) + return -1; + if (o1.getZIndex() > o2.getZIndex()) + return 1; + return 0; + } + }; + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/GridMouseAdapter.java b/src/main/java/com/jcloisterzone/ui/grid/GridMouseAdapter.java index 7e287166c..32ec55d4b 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/GridMouseAdapter.java +++ b/src/main/java/com/jcloisterzone/ui/grid/GridMouseAdapter.java @@ -1,71 +1,71 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -import javax.swing.event.MouseInputListener; - -import com.jcloisterzone.board.Position; - -public class GridMouseAdapter extends MouseAdapter implements MouseInputListener { - - final GridPanel gridPanel; - final GridMouseListener listener; - - private Position currentPosition; - - public GridMouseAdapter(GridPanel gridPanel, GridMouseListener listener) { - this.gridPanel = gridPanel; - this.listener = listener; - } - - private Position getGridPosition(MouseEvent e) { - int sqSize = gridPanel.getSquareSize(); - int clickX = e.getX() - gridPanel.getOffsetX(); - int clickY = e.getY() - gridPanel.getOffsetY(); - int x = clickX / sqSize + ((clickX < 0) ? -1 : 0); - int y = clickY / sqSize + ((clickY < 0) ? -1 : 0); - return new Position(x, y); - } - - @Override - public void mouseMoved(MouseEvent e) { - Position p = getGridPosition(e); - if (currentPosition != null && ! currentPosition.equals(p)) { - listener.squareExited(e, currentPosition); - currentPosition = null; - } - if (p != null && ! p.equals(currentPosition)) { - currentPosition = p; - listener.squareEntered(e, currentPosition); - } - } - - @Override - public void mouseClicked(MouseEvent e) { - Position p = getGridPosition(e); - if (p != null) { - listener.mouseClicked(e, p); - } - } - - @Override - public void mouseDragged(MouseEvent e) { - } - - - @Override - public void mouseEntered(MouseEvent e) { - mouseMoved(e); - } - - @Override - public void mouseExited(MouseEvent e) { - if (currentPosition != null) { - listener.squareExited(e, currentPosition); - currentPosition = null; - } - - } - -} +package com.jcloisterzone.ui.grid; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.event.MouseInputListener; + +import com.jcloisterzone.board.Position; + +public class GridMouseAdapter extends MouseAdapter implements MouseInputListener { + + final GridPanel gridPanel; + final GridMouseListener listener; + + private Position currentPosition; + + public GridMouseAdapter(GridPanel gridPanel, GridMouseListener listener) { + this.gridPanel = gridPanel; + this.listener = listener; + } + + private Position getGridPosition(MouseEvent e) { + int sqSize = gridPanel.getSquareSize(); + int clickX = e.getX() - gridPanel.getOffsetX(); + int clickY = e.getY() - gridPanel.getOffsetY(); + int x = clickX / sqSize + ((clickX < 0) ? -1 : 0); + int y = clickY / sqSize + ((clickY < 0) ? -1 : 0); + return new Position(x, y); + } + + @Override + public void mouseMoved(MouseEvent e) { + Position p = getGridPosition(e); + if (currentPosition != null && ! currentPosition.equals(p)) { + listener.squareExited(e, currentPosition); + currentPosition = null; + } + if (p != null && ! p.equals(currentPosition)) { + currentPosition = p; + listener.squareEntered(e, currentPosition); + } + } + + @Override + public void mouseClicked(MouseEvent e) { + Position p = getGridPosition(e); + if (p != null) { + listener.mouseClicked(e, p); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + } + + + @Override + public void mouseEntered(MouseEvent e) { + mouseMoved(e); + } + + @Override + public void mouseExited(MouseEvent e) { + if (currentPosition != null) { + listener.squareExited(e, currentPosition); + currentPosition = null; + } + + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/GridMouseListener.java b/src/main/java/com/jcloisterzone/ui/grid/GridMouseListener.java index 1d9a6e730..98f6ffee8 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/GridMouseListener.java +++ b/src/main/java/com/jcloisterzone/ui/grid/GridMouseListener.java @@ -1,13 +1,13 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.event.MouseEvent; - -import com.jcloisterzone.board.Position; - -public interface GridMouseListener { - - void squareEntered(MouseEvent e, Position p); - void squareExited(MouseEvent e, Position p); - - void mouseClicked(MouseEvent e, Position p); -} +package com.jcloisterzone.ui.grid; + +import java.awt.event.MouseEvent; + +import com.jcloisterzone.board.Position; + +public interface GridMouseListener { + + void squareEntered(MouseEvent e, Position p); + void squareExited(MouseEvent e, Position p); + + void mouseClicked(MouseEvent e, Position p); +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/GridPanel.java b/src/main/java/com/jcloisterzone/ui/grid/GridPanel.java index 85ed4a5dd..847f1de1d 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/GridPanel.java +++ b/src/main/java/com/jcloisterzone/ui/grid/GridPanel.java @@ -1,592 +1,592 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.awt.geom.AffineTransform; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; - -import javax.swing.JPanel; -import javax.swing.event.MouseInputListener; - -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.animation.AnimationService; -import com.jcloisterzone.ui.animation.RecentPlacement; -import com.jcloisterzone.ui.controls.ControlPanel; -import com.jcloisterzone.ui.controls.FakeComponent; -import com.jcloisterzone.ui.grid.layer.AbbeyPlacementLayer; -import com.jcloisterzone.ui.grid.layer.AbstractAreaLayer; -import com.jcloisterzone.ui.grid.layer.AbstractTilePlacementLayer; -import com.jcloisterzone.ui.grid.layer.PlacementHistory; -import com.jcloisterzone.ui.grid.layer.TileActionLayer; -import com.jcloisterzone.ui.grid.layer.TileLayer; - -public class GridPanel extends JPanel implements ForwardBackwardListener { - - private static final long serialVersionUID = -7013723613801929324L; - - public static int INITIAL_SQUARE_SIZE = 120; - private static final int STARTING_GRID_SIZE = 3; - - private static final Color MESSAGE_ERROR = new Color(186, 61, 61, 245); - private static final Color MESSAGE_HINT = new Color(147, 146, 155, 245); - - - final Client client; - final ControlPanel controlPanel; - - private FakeComponent secondPanel; - - /** current board size */ - private int left, right, top, bottom; - private int squareSize; - - //focus - private int offsetX, offsetY; - private double cx = 0.0, cy = 0.0; - private MoveCenterAnimation moveAnimation; - - private List layers = Collections.synchronizedList(new LinkedList()); - private String errorMessage, hintMessage; - - public GridPanel(Client client, Snapshot snapshot) { - setDoubleBuffered(true); - setOpaque(false); - setLayout(null); - - this.client = client; - this.controlPanel = client.getControlPanel(); - - squareSize = INITIAL_SQUARE_SIZE; - left = 0 - STARTING_GRID_SIZE / 2; - right = 0 + STARTING_GRID_SIZE / 2; - top = 0 - STARTING_GRID_SIZE / 2; - bottom = 0 + STARTING_GRID_SIZE / 2; - - if (snapshot != null) { - NodeList nl = snapshot.getTileElements(); - for (int i = 0; i < nl.getLength(); i++) { - Element el = (Element) nl.item(i); - Position pos = XmlUtils.extractPosition(el); - if (pos.x <= left) left = pos.x - 1; - if (pos.x >= right) right = pos.x + 1; - if (pos.y <= top) top = pos.y - 1; - if (pos.y >= bottom) bottom = pos.y + 1; - } - } - registerMouseListeners(); - controlPanel.registerSwingComponents(this); - } - - - @Override - public void forward() { - if (client.isClientActive()) { - if (secondPanel instanceof ForwardBackwardListener) { - ((ForwardBackwardListener) secondPanel).forward(); - } - client.getControlPanel().getActionPanel().forward(); - } - } - - @Override - public void backward() { - if (client.isClientActive()) { - if (secondPanel instanceof ForwardBackwardListener) { - ((ForwardBackwardListener) secondPanel).backward(); - } - client.getControlPanel().getActionPanel().backward(); - } - } - - class GridPanelMouseListener extends MouseAdapter implements MouseInputListener { - - private MouseEvent dragSource; - double sourceCx, sourceCy; - - @Override - public void mouseClicked(MouseEvent e) { - switch (e.getButton()) { - case MouseEvent.BUTTON2: - int clickX = e.getX()-offsetX; - int clickY = e.getY()-offsetY; - moveCenterToAnimated(clickX/(double)squareSize, clickY/(double)squareSize); - break; - case MouseEvent.BUTTON3: - case 5: - forward(); - break; - case 4: - backward(); - break; - } - } - - @Override - public void mousePressed(MouseEvent e) { - dragSource = e; - sourceCx = cx; - sourceCy = cy; - } - - @Override - public void mouseReleased(MouseEvent e) { - dragSource = null; - } - - @Override - public void mouseDragged(MouseEvent e) { - //px values - int dx = e.getX() - dragSource.getX(); - int dy = e.getY() - dragSource.getY(); - //relative values - double rdx = dx/(double)squareSize; - double rdy = dy/(double)squareSize; - - moveCenterTo(sourceCx-rdx, sourceCy-rdy); - - //System.err.println(cx + " " + cy + " / " + offsetX + " " + offsetY); - //offsetX = calculateCenterX() - (int)(cx * squareSize); - //offsetY = calculateCenterY() - (int)(cy * squareSize); -// int clickX = e.getX()-offsetX; -// int clickY = e.getY()-offsetY; -// moveCenterToAnimated(clickX/(double)squareSize, clickY/(double)squareSize); - //moveCenterTo(cx-dx*(double)squareSize,cy-dy(double)squareSize); - //System.err.println(x + "/" + y); - } - } - - private void registerMouseListeners() { - DragInsensitiveMouseClickListener listener = new DragInsensitiveMouseClickListener(new GridPanelMouseListener()); - addMouseListener(listener); - addMouseMotionListener(listener); - addMouseWheelListener(new MouseWheelListener() { - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - zoom(-e.getWheelRotation()); - } - }); - - MouseAdapter childDelegation = new MouseAdapter() { - private void dispatch(MouseEvent e) { - if (secondPanel != null) { - secondPanel.dispatchMouseEvent(e); - if (e.isConsumed()) return; - } - controlPanel.dispatchMouseEvent(e); - } - public void mouseClicked(MouseEvent e) { - dispatch(e); - } - public void mouseMoved(MouseEvent e) { - dispatch(e); - } - }; - addMouseListener(childDelegation); - addMouseMotionListener(childDelegation); - - addComponentListener(new ComponentListener() { - @Override - public void componentResized(ComponentEvent e) { - controlPanel.componentResized(e); - if (secondPanel != null) secondPanel.componentResized(e); - } - @Override - public void componentMoved(ComponentEvent e) { - controlPanel.componentMoved(e); - if (secondPanel != null) secondPanel.componentMoved(e); - } - @Override - public void componentShown(ComponentEvent e) { - controlPanel.componentShown(e); - if (secondPanel != null) secondPanel.componentShown(e); - } - @Override - public void componentHidden(ComponentEvent e) { - controlPanel.componentHidden(e); - if (secondPanel != null) secondPanel.componentHidden(e); - } - }); - } - - public Tile getTile(Position p) { - return client.getGame().getBoard().get(p); - } - - public Client getClient() { - return client; - } - - public FakeComponent getSecondPanel() { - return secondPanel; - } - - public void setSecondPanel(FakeComponent secondPanel) { - if (this.secondPanel != null && this.secondPanel != secondPanel) { - //destroy previoud panel - this.secondPanel.destroySwingComponents(this); - } - this.secondPanel = secondPanel; - } - - public AnimationService getAnimationService() { - return client.getMainPanel().getAnimationService(); - } - - public int getSquareSize() { - return squareSize; - } - - public int getLeft() { - return left; - } - - public int getRight() { - return right; - } - - public int getTop() { - return top; - } - - public int getBottom() { - return bottom; - } - - public int getOffsetX() { - return offsetX; - } - - public int getOffsetY() { - return offsetY; - } - - - public String getErrorMessage() { - return errorMessage; - } - - - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - - - public String getHintMessage() { - return hintMessage; - } - - - public void setHintMessage(String hintMessage) { - this.hintMessage = hintMessage; - } - - - public void moveCenter(int xSteps, int ySteps) { - //step should be 30px - double dx = xSteps * 30.0f / getSquareSize(); - double dy = ySteps * 30.0f / getSquareSize(); - moveCenterTo(cx + dx, cy + dy); - } - - public void moveCenterToAnimated(double cx, double cy) { - if (moveAnimation != null) { - moveAnimation.setCancel(true); - } - moveAnimation = new MoveCenterAnimation(cx, cy); - moveAnimation.start(); - } - - private void moveCenterTo(double cx, double cy) { - if (cx < left-0.5f) cx = left-0.5f; - if (cx > right+0.5f) cx = right+0.5f; - if (cy < top-0.5f) cy = top-0.5f; - if (cy > bottom+0.5f) cy = bottom+0.5f; - - this.cx = cx; - this.cy = cy; - repaint(); - } - - public void zoom(double steps) { - int size = (int) (squareSize * Math.pow(1.3, steps)); - if (size < 25) size = 25; - if (size > 300) size = 300; - setZoomSize(size); - } - - private void setZoomSize(int size) { - if (size == squareSize) return; - squareSize = size; - - synchronized (layers) { - for (GridLayer layer : layers) { - layer.zoomChanged(squareSize); - } - } - moveCenterTo(cx, cy); //re-check center constraints - } - - public void showRecentHistory() { - Collection tiles = client.getGame().getBoard().getAllTiles(); - addLayer(new PlacementHistory(this, tiles)); - } - - public void addLayer(GridLayer layer) { - synchronized (layers) { - ListIterator iter = layers.listIterator(); - while(iter.hasNext()) { - GridLayer sl = iter.next(); - if (GridLayer.Z_INDEX_COMPARATOR.compare(layer, sl) <= 0) { - iter.previous(); - break; - } - } - iter.add(layer); - } - layer.layerAdded(); - repaint(); - } - - public void removeLayer(GridLayer layer) { - layers.remove(layer); - layer.layerRemoved(); - repaint(); - } - - public void removeLayer(Class type) { - Iterator iter = layers.iterator(); - while(iter.hasNext()) { - GridLayer layer = iter.next(); - if (type.isInstance(layer)) { - iter.remove(); - layer.layerRemoved(); - } - } - repaint(); - } - - //TODO ok - @SuppressWarnings("unchecked") - synchronized - public T findDecoration(Class type) { - synchronized (layers) { - for (GridLayer layer : layers) { - if (type.isInstance(layer)) { - return (T) layer; - } - } - } - return null; - } - - public boolean containsDecoration(Class type) { - for (GridLayer layer : layers) { - if (type.isInstance(layer)) { - return true; - } - } - return false; - } - - public void clearActionDecorations() { - removeLayer(AbstractAreaLayer.class); - removeLayer(TileActionLayer.class); - removeLayer(AbbeyPlacementLayer.class); - } - - // delegated UI methods - - public void tilePlaced(Tile tile, TileLayer tileLayer) { - Position p = tile.getPosition(); - - removeLayer(AbstractTilePlacementLayer.class); - removeLayer(PlacementHistory.class); - - if (p.x == left) --left; - if (p.x == right) ++right; - if (p.y == top) --top; - if (p.y == bottom) ++bottom; - - tileLayer.tilePlaced(tile); - - if (client.getSettings().isShowHistory()) { - showRecentHistory(); - } - boolean initialPlacement = client.getActivePlayer() == null;//if active player is null we are placing initial tiles - if ((!initialPlacement && !client.isClientActive()) || - (initialPlacement && tile.equals(client.getGame().getCurrentTile()))) { - getAnimationService().registerAnimation(tile.getPosition(), new RecentPlacement(tile.getPosition())); - } - repaint(); - } - - private int calculateCenterX() { - return (getWidth() - ControlPanel.PANEL_WIDTH - squareSize)/2; - } - - private int calculateCenterY() { - return (getHeight() - squareSize)/2; - } - -// //TODO remove profile code -// long ts, last; -// public void profile(String msg) { -// long now = System.currentTimeMillis(); -// System.out.println((now-ts) + " (" + (now-last) +") : " + msg); -// last = now; -// } - -// private void paintGrid(Graphics2D g2) { -// g2.setColor(UIManager.getColor("Panel.background")); -// g2.fillRect(left*squareSize, top*squareSize, (right+2)*squareSize-1, (bottom+2)*squareSize-1); -// g2.setColor(Color.LIGHT_GRAY); -// for (int i = left; i <= right; i++) { -// g2.drawLine(i*squareSize, top*squareSize, i*squareSize, (bottom+1)*squareSize); -// g2.drawLine((i+1)*squareSize-1, top*squareSize, (i+1)*squareSize-1, (bottom+1)*squareSize); -// } -// for (int i = top; i <= bottom; i++) { -// g2.drawLine(left*squareSize, i*squareSize, (right+1)*squareSize, i*squareSize); -// g2.drawLine(left*squareSize, (i+1)*squareSize-1, (right+1)*squareSize, (i+1)*squareSize-1); -// } - -// profile("grid"); -// } - - @Override - protected void paintChildren(Graphics g) { - Graphics2D g2 = (Graphics2D) g; - - //System.err.println("GP " + g2.getTransform()); - -// System.out.println("------------------------"); -// ts = last = System.currentTimeMillis(); - - int w = getWidth(), h = getHeight(); -// int w = getWidth(), h = getHeight(); -// if (blurBuffer == null || blurBuffer.getWidth() != w || blurBuffer.getHeight() != h) { -// blurBuffer = UiUtils.newTransparentImage(w, h); -// } -// Graphics2D g2 = blurBuffer.createGraphics(); -// g2.setBackground(TRANSPARENT_COLOR); -// g2.clearRect(0, 0, w, h); - - AffineTransform origTransform = g2.getTransform(); - offsetX = calculateCenterX() - (int)(cx * squareSize); - offsetY = calculateCenterY() - (int)(cy * squareSize); - g2.translate(offsetX, offsetY); - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - //paintGrid(g2); - - //paint layers - synchronized (layers) { - for (GridLayer layer : layers) { - layer.paint(g2); -// profile(layer.getClass().getSimpleName()); - } - } - - g2.setTransform(origTransform); - g2.translate(w - ControlPanel.PANEL_WIDTH, 0); - - controlPanel.paintComponent(g2); - - int innerWidth; - if (secondPanel != null) { - g2.translate(-secondPanel.getWidth()-60, 0); - secondPanel.paintComponent(g2); - innerWidth = (int) g2.getTransform().getTranslateX(); - } else { - innerWidth = (int) g2.getTransform().getTranslateX() - ControlPanel.LEFT_PADDING - ControlPanel.PANEL_SHADOW_WIDTH; - } - g2.setTransform(origTransform); - paintMessages(g2, innerWidth); - super.paintChildren(g); - } - - private void paintMessages(Graphics2D g2, int innerWidth) { - int y = 0; - if (hintMessage != null) { - g2.setColor(MESSAGE_HINT); - g2.fillRect(0, y, innerWidth, 36); - g2.setFont(new Font(null, Font.PLAIN, 16)); - g2.setColor(Color.WHITE); - g2.drawString(hintMessage, 30, y+23); - y += 42; - } - if (errorMessage != null) { - g2.setColor(MESSAGE_ERROR); - g2.fillRect(0, y, innerWidth, 36); - g2.setFont(new Font(null, Font.PLAIN, 16)); - g2.setColor(Color.WHITE); - g2.drawString(errorMessage, 30, y+23); - y += 42; - } - - } - - class MoveCenterAnimation extends Thread { - //TODO easing ? - - private double toCx, toCy, fromCx, fromCy; - long start, end; - private boolean cancel; - - public MoveCenterAnimation(double toCx, double toCy) { - moveTo(toCx, toCy); - } - - private void moveTo(double toCx, double toCy) { - this.toCx = toCx; - this.toCy = toCy; - fromCx = cx; - fromCy = cy; - start = System.currentTimeMillis(); - end = start + 100; - } - - public void setCancel(boolean cancel) { - this.cancel = cancel; - } - - @Override - public void run() { - long t; - while (!cancel && (t = System.currentTimeMillis()) < end) { - double dx = (double)(t - start)/(end-start)*(toCx-fromCx); - double dy = (double)(t - start)/(end-start)*(toCy-fromCy); - moveCenterTo(fromCx+dx, fromCy+dy); - try { - Thread.sleep(15); - } catch (InterruptedException e) { - } - } - if (!cancel) { - moveCenterTo(toCx, toCy); - } - } - - } - -} +package com.jcloisterzone.ui.grid; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.geom.AffineTransform; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +import javax.swing.JPanel; +import javax.swing.event.MouseInputListener; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.animation.AnimationService; +import com.jcloisterzone.ui.animation.RecentPlacement; +import com.jcloisterzone.ui.controls.ControlPanel; +import com.jcloisterzone.ui.controls.FakeComponent; +import com.jcloisterzone.ui.grid.layer.AbbeyPlacementLayer; +import com.jcloisterzone.ui.grid.layer.AbstractAreaLayer; +import com.jcloisterzone.ui.grid.layer.AbstractTilePlacementLayer; +import com.jcloisterzone.ui.grid.layer.PlacementHistory; +import com.jcloisterzone.ui.grid.layer.TileActionLayer; +import com.jcloisterzone.ui.grid.layer.TileLayer; + +public class GridPanel extends JPanel implements ForwardBackwardListener { + + private static final long serialVersionUID = -7013723613801929324L; + + public static int INITIAL_SQUARE_SIZE = 120; + private static final int STARTING_GRID_SIZE = 3; + + private static final Color MESSAGE_ERROR = new Color(186, 61, 61, 245); + private static final Color MESSAGE_HINT = new Color(147, 146, 155, 245); + + + final Client client; + final ControlPanel controlPanel; + + private FakeComponent secondPanel; + + /** current board size */ + private int left, right, top, bottom; + private int squareSize; + + //focus + private int offsetX, offsetY; + private double cx = 0.0, cy = 0.0; + private MoveCenterAnimation moveAnimation; + + private List layers = Collections.synchronizedList(new LinkedList()); + private String errorMessage, hintMessage; + + public GridPanel(Client client, Snapshot snapshot) { + setDoubleBuffered(true); + setOpaque(false); + setLayout(null); + + this.client = client; + this.controlPanel = client.getControlPanel(); + + squareSize = INITIAL_SQUARE_SIZE; + left = 0 - STARTING_GRID_SIZE / 2; + right = 0 + STARTING_GRID_SIZE / 2; + top = 0 - STARTING_GRID_SIZE / 2; + bottom = 0 + STARTING_GRID_SIZE / 2; + + if (snapshot != null) { + NodeList nl = snapshot.getTileElements(); + for (int i = 0; i < nl.getLength(); i++) { + Element el = (Element) nl.item(i); + Position pos = XmlUtils.extractPosition(el); + if (pos.x <= left) left = pos.x - 1; + if (pos.x >= right) right = pos.x + 1; + if (pos.y <= top) top = pos.y - 1; + if (pos.y >= bottom) bottom = pos.y + 1; + } + } + registerMouseListeners(); + controlPanel.registerSwingComponents(this); + } + + + @Override + public void forward() { + if (client.isClientActive()) { + if (secondPanel instanceof ForwardBackwardListener) { + ((ForwardBackwardListener) secondPanel).forward(); + } + client.getControlPanel().getActionPanel().forward(); + } + } + + @Override + public void backward() { + if (client.isClientActive()) { + if (secondPanel instanceof ForwardBackwardListener) { + ((ForwardBackwardListener) secondPanel).backward(); + } + client.getControlPanel().getActionPanel().backward(); + } + } + + class GridPanelMouseListener extends MouseAdapter implements MouseInputListener { + + private MouseEvent dragSource; + double sourceCx, sourceCy; + + @Override + public void mouseClicked(MouseEvent e) { + switch (e.getButton()) { + case MouseEvent.BUTTON2: + int clickX = e.getX()-offsetX; + int clickY = e.getY()-offsetY; + moveCenterToAnimated(clickX/(double)squareSize, clickY/(double)squareSize); + break; + case MouseEvent.BUTTON3: + case 5: + forward(); + break; + case 4: + backward(); + break; + } + } + + @Override + public void mousePressed(MouseEvent e) { + dragSource = e; + sourceCx = cx; + sourceCy = cy; + } + + @Override + public void mouseReleased(MouseEvent e) { + dragSource = null; + } + + @Override + public void mouseDragged(MouseEvent e) { + //px values + int dx = e.getX() - dragSource.getX(); + int dy = e.getY() - dragSource.getY(); + //relative values + double rdx = dx/(double)squareSize; + double rdy = dy/(double)squareSize; + + moveCenterTo(sourceCx-rdx, sourceCy-rdy); + + //System.err.println(cx + " " + cy + " / " + offsetX + " " + offsetY); + //offsetX = calculateCenterX() - (int)(cx * squareSize); + //offsetY = calculateCenterY() - (int)(cy * squareSize); +// int clickX = e.getX()-offsetX; +// int clickY = e.getY()-offsetY; +// moveCenterToAnimated(clickX/(double)squareSize, clickY/(double)squareSize); + //moveCenterTo(cx-dx*(double)squareSize,cy-dy(double)squareSize); + //System.err.println(x + "/" + y); + } + } + + private void registerMouseListeners() { + DragInsensitiveMouseClickListener listener = new DragInsensitiveMouseClickListener(new GridPanelMouseListener()); + addMouseListener(listener); + addMouseMotionListener(listener); + addMouseWheelListener(new MouseWheelListener() { + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + zoom(-e.getWheelRotation()); + } + }); + + MouseAdapter childDelegation = new MouseAdapter() { + private void dispatch(MouseEvent e) { + if (secondPanel != null) { + secondPanel.dispatchMouseEvent(e); + if (e.isConsumed()) return; + } + controlPanel.dispatchMouseEvent(e); + } + public void mouseClicked(MouseEvent e) { + dispatch(e); + } + public void mouseMoved(MouseEvent e) { + dispatch(e); + } + }; + addMouseListener(childDelegation); + addMouseMotionListener(childDelegation); + + addComponentListener(new ComponentListener() { + @Override + public void componentResized(ComponentEvent e) { + controlPanel.componentResized(e); + if (secondPanel != null) secondPanel.componentResized(e); + } + @Override + public void componentMoved(ComponentEvent e) { + controlPanel.componentMoved(e); + if (secondPanel != null) secondPanel.componentMoved(e); + } + @Override + public void componentShown(ComponentEvent e) { + controlPanel.componentShown(e); + if (secondPanel != null) secondPanel.componentShown(e); + } + @Override + public void componentHidden(ComponentEvent e) { + controlPanel.componentHidden(e); + if (secondPanel != null) secondPanel.componentHidden(e); + } + }); + } + + public Tile getTile(Position p) { + return client.getGame().getBoard().get(p); + } + + public Client getClient() { + return client; + } + + public FakeComponent getSecondPanel() { + return secondPanel; + } + + public void setSecondPanel(FakeComponent secondPanel) { + if (this.secondPanel != null && this.secondPanel != secondPanel) { + //destroy previoud panel + this.secondPanel.destroySwingComponents(this); + } + this.secondPanel = secondPanel; + } + + public AnimationService getAnimationService() { + return client.getMainPanel().getAnimationService(); + } + + public int getSquareSize() { + return squareSize; + } + + public int getLeft() { + return left; + } + + public int getRight() { + return right; + } + + public int getTop() { + return top; + } + + public int getBottom() { + return bottom; + } + + public int getOffsetX() { + return offsetX; + } + + public int getOffsetY() { + return offsetY; + } + + + public String getErrorMessage() { + return errorMessage; + } + + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + + public String getHintMessage() { + return hintMessage; + } + + + public void setHintMessage(String hintMessage) { + this.hintMessage = hintMessage; + } + + + public void moveCenter(int xSteps, int ySteps) { + //step should be 30px + double dx = xSteps * 30.0f / getSquareSize(); + double dy = ySteps * 30.0f / getSquareSize(); + moveCenterTo(cx + dx, cy + dy); + } + + public void moveCenterToAnimated(double cx, double cy) { + if (moveAnimation != null) { + moveAnimation.setCancel(true); + } + moveAnimation = new MoveCenterAnimation(cx, cy); + moveAnimation.start(); + } + + private void moveCenterTo(double cx, double cy) { + if (cx < left-0.5f) cx = left-0.5f; + if (cx > right+0.5f) cx = right+0.5f; + if (cy < top-0.5f) cy = top-0.5f; + if (cy > bottom+0.5f) cy = bottom+0.5f; + + this.cx = cx; + this.cy = cy; + repaint(); + } + + public void zoom(double steps) { + int size = (int) (squareSize * Math.pow(1.3, steps)); + if (size < 25) size = 25; + if (size > 300) size = 300; + setZoomSize(size); + } + + private void setZoomSize(int size) { + if (size == squareSize) return; + squareSize = size; + + synchronized (layers) { + for (GridLayer layer : layers) { + layer.zoomChanged(squareSize); + } + } + moveCenterTo(cx, cy); //re-check center constraints + } + + public void showRecentHistory() { + Collection tiles = client.getGame().getBoard().getAllTiles(); + addLayer(new PlacementHistory(this, tiles)); + } + + public void addLayer(GridLayer layer) { + synchronized (layers) { + ListIterator iter = layers.listIterator(); + while(iter.hasNext()) { + GridLayer sl = iter.next(); + if (GridLayer.Z_INDEX_COMPARATOR.compare(layer, sl) <= 0) { + iter.previous(); + break; + } + } + iter.add(layer); + } + layer.layerAdded(); + repaint(); + } + + public void removeLayer(GridLayer layer) { + layers.remove(layer); + layer.layerRemoved(); + repaint(); + } + + public void removeLayer(Class type) { + Iterator iter = layers.iterator(); + while(iter.hasNext()) { + GridLayer layer = iter.next(); + if (type.isInstance(layer)) { + iter.remove(); + layer.layerRemoved(); + } + } + repaint(); + } + + //TODO ok + @SuppressWarnings("unchecked") + synchronized + public T findDecoration(Class type) { + synchronized (layers) { + for (GridLayer layer : layers) { + if (type.isInstance(layer)) { + return (T) layer; + } + } + } + return null; + } + + public boolean containsDecoration(Class type) { + for (GridLayer layer : layers) { + if (type.isInstance(layer)) { + return true; + } + } + return false; + } + + public void clearActionDecorations() { + removeLayer(AbstractAreaLayer.class); + removeLayer(TileActionLayer.class); + removeLayer(AbbeyPlacementLayer.class); + } + + // delegated UI methods + + public void tilePlaced(Tile tile, TileLayer tileLayer) { + Position p = tile.getPosition(); + + removeLayer(AbstractTilePlacementLayer.class); + removeLayer(PlacementHistory.class); + + if (p.x == left) --left; + if (p.x == right) ++right; + if (p.y == top) --top; + if (p.y == bottom) ++bottom; + + tileLayer.tilePlaced(tile); + + if (client.getSettings().isShowHistory()) { + showRecentHistory(); + } + boolean initialPlacement = client.getActivePlayer() == null;//if active player is null we are placing initial tiles + if ((!initialPlacement && !client.isClientActive()) || + (initialPlacement && tile.equals(client.getGame().getCurrentTile()))) { + getAnimationService().registerAnimation(tile.getPosition(), new RecentPlacement(tile.getPosition())); + } + repaint(); + } + + private int calculateCenterX() { + return (getWidth() - ControlPanel.PANEL_WIDTH - squareSize)/2; + } + + private int calculateCenterY() { + return (getHeight() - squareSize)/2; + } + +// //TODO remove profile code +// long ts, last; +// public void profile(String msg) { +// long now = System.currentTimeMillis(); +// System.out.println((now-ts) + " (" + (now-last) +") : " + msg); +// last = now; +// } + +// private void paintGrid(Graphics2D g2) { +// g2.setColor(UIManager.getColor("Panel.background")); +// g2.fillRect(left*squareSize, top*squareSize, (right+2)*squareSize-1, (bottom+2)*squareSize-1); +// g2.setColor(Color.LIGHT_GRAY); +// for (int i = left; i <= right; i++) { +// g2.drawLine(i*squareSize, top*squareSize, i*squareSize, (bottom+1)*squareSize); +// g2.drawLine((i+1)*squareSize-1, top*squareSize, (i+1)*squareSize-1, (bottom+1)*squareSize); +// } +// for (int i = top; i <= bottom; i++) { +// g2.drawLine(left*squareSize, i*squareSize, (right+1)*squareSize, i*squareSize); +// g2.drawLine(left*squareSize, (i+1)*squareSize-1, (right+1)*squareSize, (i+1)*squareSize-1); +// } + +// profile("grid"); +// } + + @Override + protected void paintChildren(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + + //System.err.println("GP " + g2.getTransform()); + +// System.out.println("------------------------"); +// ts = last = System.currentTimeMillis(); + + int w = getWidth(), h = getHeight(); +// int w = getWidth(), h = getHeight(); +// if (blurBuffer == null || blurBuffer.getWidth() != w || blurBuffer.getHeight() != h) { +// blurBuffer = UiUtils.newTransparentImage(w, h); +// } +// Graphics2D g2 = blurBuffer.createGraphics(); +// g2.setBackground(TRANSPARENT_COLOR); +// g2.clearRect(0, 0, w, h); + + AffineTransform origTransform = g2.getTransform(); + offsetX = calculateCenterX() - (int)(cx * squareSize); + offsetY = calculateCenterY() - (int)(cy * squareSize); + g2.translate(offsetX, offsetY); + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + //paintGrid(g2); + + //paint layers + synchronized (layers) { + for (GridLayer layer : layers) { + layer.paint(g2); +// profile(layer.getClass().getSimpleName()); + } + } + + g2.setTransform(origTransform); + g2.translate(w - ControlPanel.PANEL_WIDTH, 0); + + controlPanel.paintComponent(g2); + + int innerWidth; + if (secondPanel != null) { + g2.translate(-secondPanel.getWidth()-60, 0); + secondPanel.paintComponent(g2); + innerWidth = (int) g2.getTransform().getTranslateX(); + } else { + innerWidth = (int) g2.getTransform().getTranslateX() - ControlPanel.LEFT_PADDING - ControlPanel.PANEL_SHADOW_WIDTH; + } + g2.setTransform(origTransform); + paintMessages(g2, innerWidth); + super.paintChildren(g); + } + + private void paintMessages(Graphics2D g2, int innerWidth) { + int y = 0; + if (hintMessage != null) { + g2.setColor(MESSAGE_HINT); + g2.fillRect(0, y, innerWidth, 36); + g2.setFont(new Font(null, Font.PLAIN, 16)); + g2.setColor(Color.WHITE); + g2.drawString(hintMessage, 30, y+23); + y += 42; + } + if (errorMessage != null) { + g2.setColor(MESSAGE_ERROR); + g2.fillRect(0, y, innerWidth, 36); + g2.setFont(new Font(null, Font.PLAIN, 16)); + g2.setColor(Color.WHITE); + g2.drawString(errorMessage, 30, y+23); + y += 42; + } + + } + + class MoveCenterAnimation extends Thread { + //TODO easing ? + + private double toCx, toCy, fromCx, fromCy; + long start, end; + private boolean cancel; + + public MoveCenterAnimation(double toCx, double toCy) { + moveTo(toCx, toCy); + } + + private void moveTo(double toCx, double toCy) { + this.toCx = toCx; + this.toCy = toCy; + fromCx = cx; + fromCy = cy; + start = System.currentTimeMillis(); + end = start + 100; + } + + public void setCancel(boolean cancel) { + this.cancel = cancel; + } + + @Override + public void run() { + long t; + while (!cancel && (t = System.currentTimeMillis()) < end) { + double dx = (double)(t - start)/(end-start)*(toCx-fromCx); + double dy = (double)(t - start)/(end-start)*(toCy-fromCy); + moveCenterTo(fromCx+dx, fromCy+dy); + try { + Thread.sleep(15); + } catch (InterruptedException e) { + } + } + if (!cancel) { + moveCenterTo(toCx, toCy); + } + } + + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/KeyController.java b/src/main/java/com/jcloisterzone/ui/grid/KeyController.java index f82986e51..84f3afdc8 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/KeyController.java +++ b/src/main/java/com/jcloisterzone/ui/grid/KeyController.java @@ -1,120 +1,120 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.KeyEventDispatcher; -import java.awt.event.KeyEvent; -import java.util.Timer; -import java.util.TimerTask; - -import com.jcloisterzone.ui.Client; - -public class KeyController implements KeyEventDispatcher { - - private final Client client; - - boolean repeatLeft, repeatRight, repeatUp, repeatDown; - boolean repeatZoomIn, repeatZoomOut; - - public KeyController(Client client) { - this.client = client; - (new Timer(true)).scheduleAtFixedRate(new KeyRepeater(), 0, 40); - } - - @Override - public boolean dispatchKeyEvent(KeyEvent e) { - //System.out.println(e); - if (!client.isActive()) return false; - if (e.getID() == KeyEvent.KEY_PRESSED) { - switch (e.getKeyCode()) { - case KeyEvent.VK_SPACE: - case KeyEvent.VK_ENTER: - if (client.isClientActive()) { - client.getControlPanel().pass(); - return true; - } - break; - case KeyEvent.VK_TAB: - if (e.getModifiers() == 0) { - client.getGridPanel().forward(); - } else if (e.getModifiers() == KeyEvent.SHIFT_MASK) { - client.getGridPanel().backward(); - } - break; - default: - return dispatchReptable(e, true); - } - } else if (e.getID() == KeyEvent.KEY_RELEASED) { - return dispatchReptable(e, false); - } else if (e.getID() == KeyEvent.KEY_TYPED) { - return dispatchKeyTyped(e); - } - return false; - } - - private boolean dispatchReptable(KeyEvent e, boolean pressed) { - switch (e.getKeyCode()) { - case KeyEvent.VK_LEFT: - case KeyEvent.VK_A: - repeatLeft = pressed; - return true; - case KeyEvent.VK_RIGHT: - case KeyEvent.VK_D: - repeatRight = pressed; - return true; - case KeyEvent.VK_DOWN: - case KeyEvent.VK_S: - repeatDown = pressed; - return true; - case KeyEvent.VK_UP: - case KeyEvent.VK_W: - repeatUp = pressed; - return true; - } - if (e.getKeyChar() == '+') { - repeatZoomIn = pressed; - e.consume(); - return true; - } - if (e.getKeyChar() == '-') { - repeatZoomOut = pressed; - e.consume(); - return true; - } - return false; - } - - private boolean dispatchKeyTyped(KeyEvent e) { - if (e.getKeyChar() == '+' || e.getKeyChar() == '-') { - e.consume(); - return true; - } - return false; - } - - class KeyRepeater extends TimerTask { - - @Override - public void run() { - GridPanel gridPanel = client.getGridPanel(); - if (gridPanel == null) return; - if (repeatLeft) { - gridPanel.moveCenter(-1, 0); - } - if (repeatRight) { - gridPanel.moveCenter(1, 0); - } - if (repeatUp) { - gridPanel.moveCenter(0, -1); - } - if (repeatDown) { - gridPanel.moveCenter(0, 1); - } - if (repeatZoomIn) { - gridPanel.zoom(0.8); - } - if (repeatZoomOut) { - gridPanel.zoom(-0.8); - } - } - } - -} +package com.jcloisterzone.ui.grid; + +import java.awt.KeyEventDispatcher; +import java.awt.event.KeyEvent; +import java.util.Timer; +import java.util.TimerTask; + +import com.jcloisterzone.ui.Client; + +public class KeyController implements KeyEventDispatcher { + + private final Client client; + + boolean repeatLeft, repeatRight, repeatUp, repeatDown; + boolean repeatZoomIn, repeatZoomOut; + + public KeyController(Client client) { + this.client = client; + (new Timer(true)).scheduleAtFixedRate(new KeyRepeater(), 0, 40); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent e) { + //System.out.println(e); + if (!client.isActive()) return false; + if (e.getID() == KeyEvent.KEY_PRESSED) { + switch (e.getKeyCode()) { + case KeyEvent.VK_SPACE: + case KeyEvent.VK_ENTER: + if (client.isClientActive()) { + client.getControlPanel().pass(); + return true; + } + break; + case KeyEvent.VK_TAB: + if (e.getModifiers() == 0) { + client.getGridPanel().forward(); + } else if (e.getModifiers() == KeyEvent.SHIFT_MASK) { + client.getGridPanel().backward(); + } + break; + default: + return dispatchReptable(e, true); + } + } else if (e.getID() == KeyEvent.KEY_RELEASED) { + return dispatchReptable(e, false); + } else if (e.getID() == KeyEvent.KEY_TYPED) { + return dispatchKeyTyped(e); + } + return false; + } + + private boolean dispatchReptable(KeyEvent e, boolean pressed) { + switch (e.getKeyCode()) { + case KeyEvent.VK_LEFT: + case KeyEvent.VK_A: + repeatLeft = pressed; + return true; + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_D: + repeatRight = pressed; + return true; + case KeyEvent.VK_DOWN: + case KeyEvent.VK_S: + repeatDown = pressed; + return true; + case KeyEvent.VK_UP: + case KeyEvent.VK_W: + repeatUp = pressed; + return true; + } + if (e.getKeyChar() == '+') { + repeatZoomIn = pressed; + e.consume(); + return true; + } + if (e.getKeyChar() == '-') { + repeatZoomOut = pressed; + e.consume(); + return true; + } + return false; + } + + private boolean dispatchKeyTyped(KeyEvent e) { + if (e.getKeyChar() == '+' || e.getKeyChar() == '-') { + e.consume(); + return true; + } + return false; + } + + class KeyRepeater extends TimerTask { + + @Override + public void run() { + GridPanel gridPanel = client.getGridPanel(); + if (gridPanel == null) return; + if (repeatLeft) { + gridPanel.moveCenter(-1, 0); + } + if (repeatRight) { + gridPanel.moveCenter(1, 0); + } + if (repeatUp) { + gridPanel.moveCenter(0, -1); + } + if (repeatDown) { + gridPanel.moveCenter(0, 1); + } + if (repeatZoomIn) { + gridPanel.zoom(0.8); + } + if (repeatZoomOut) { + gridPanel.zoom(-0.8); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/MainPanel.java b/src/main/java/com/jcloisterzone/ui/grid/MainPanel.java index d3385e7aa..ad9c96034 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/MainPanel.java +++ b/src/main/java/com/jcloisterzone/ui/grid/MainPanel.java @@ -1,214 +1,214 @@ -package com.jcloisterzone.ui.grid; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Image; - -import com.jcloisterzone.Player; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.game.Capability; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.game.Snapshot; -import com.jcloisterzone.game.capability.BridgeCapability; -import com.jcloisterzone.game.capability.CastleCapability; -import com.jcloisterzone.game.capability.DragonCapability; -import com.jcloisterzone.game.capability.FairyCapability; -import com.jcloisterzone.game.capability.PlagueCapability; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.animation.AnimationService; -import com.jcloisterzone.ui.animation.ScoreAnimation; -import com.jcloisterzone.ui.grid.layer.AbstractTilePlacementLayer; -import com.jcloisterzone.ui.grid.layer.AnimationLayer; -import com.jcloisterzone.ui.grid.layer.BridgeLayer; -import com.jcloisterzone.ui.grid.layer.CastleLayer; -import com.jcloisterzone.ui.grid.layer.DragonAvailableMove; -import com.jcloisterzone.ui.grid.layer.DragonLayer; -import com.jcloisterzone.ui.grid.layer.FairyLayer; -import com.jcloisterzone.ui.grid.layer.MeepleLayer; -import com.jcloisterzone.ui.grid.layer.PlagueLayer; -import com.jcloisterzone.ui.grid.layer.TileLayer; -import com.jcloisterzone.ui.grid.layer.TowerLayer; -import com.jcloisterzone.ui.panel.BackgroundPanel; - - -@SuppressWarnings("serial") -public class MainPanel extends BackgroundPanel { - - private final Client client; - private AnimationService animationService; - - private GridPanel gridPanel; - private TileLayer tileLayer; - private MeepleLayer meepleLayer; - private TowerLayer towerLayer; - private DragonLayer dragonLayer; - private FairyLayer fairyLayer; - private BridgeLayer bridgeLayer; - private CastleLayer castleLayer; - private PlagueLayer plagueLayer; - - public MainPanel(Client client) { - this.client = client; - animationService = new AnimationService(); - animationService.start(); - - setLayout(new BorderLayout()); - } - - public GridPanel getGridPanel() { - return gridPanel; - } - - public AnimationService getAnimationService() { - return animationService; - } - - private Game getGame() { - return client.getGame(); - } - - public void started(Snapshot snapshot) { - animationService.clearAll(); - animationService.setGridPanel(null); - removeAll(); - setVisible(false); - - gridPanel = new GridPanel(client, snapshot); - meepleLayer = new MeepleLayer(gridPanel); - tileLayer = new TileLayer(gridPanel); - gridPanel.addLayer(tileLayer); - gridPanel.addLayer(meepleLayer); - gridPanel.addLayer(new AnimationLayer(gridPanel, animationService)); - - animationService.setGridPanel(gridPanel); - - for (Class capClass : getGame().getCapabilityClasses()) { - if (capClass.equals(TowerCapability.class)) { - towerLayer = new TowerLayer(gridPanel); - gridPanel.addLayer(towerLayer); - } - if (capClass.equals(DragonCapability.class)) { - dragonLayer = new DragonLayer(gridPanel, null); - gridPanel.addLayer(dragonLayer); - } - if (capClass.equals(FairyCapability.class)) { - fairyLayer = new FairyLayer(gridPanel, null); - gridPanel.addLayer(fairyLayer); - } - if (capClass.equals(BridgeCapability.class)) { - bridgeLayer = new BridgeLayer(gridPanel); - gridPanel.addLayer(bridgeLayer); - } - if (capClass.equals(CastleCapability.class)) { - castleLayer = new CastleLayer(gridPanel); - gridPanel.addLayer(castleLayer); - } - if (capClass.equals(PlagueCapability.class)) { - plagueLayer = new PlagueLayer(gridPanel); - gridPanel.addLayer(plagueLayer); - } - } - add(gridPanel); - setVisible(true); - } - - public void closeGame() { - gridPanel.clearActionDecorations(); - gridPanel.removeLayer(AbstractTilePlacementLayer.class); - gridPanel.setSecondPanel(null); - } - - public void tilePlaced(Tile tile) { - gridPanel.tilePlaced(tile, tileLayer); - } - - public void deployed(Meeple m) { - gridPanel.clearActionDecorations(); - meepleLayer.meepleDeployed(m); - } - - public void undeployed(Meeple m) { - gridPanel.clearActionDecorations(); - meepleLayer.meepleUndeployed(m); - } - - public void bridgeDeployed(Position pos, Location loc) { - gridPanel.clearActionDecorations(); - bridgeLayer.bridgeDeployed(pos, loc); - } - - public void castleDeployed(Castle castle1, Castle castle2) { - gridPanel.clearActionDecorations(); - castleLayer.castleDeployed(castle1, castle2); - } - - private Integer getScoreAnimationDuration() { - return client.getConfig().get("ui", "score_display_duration", Integer.class); - } - - public void scored(Feature scoreable, String points, Meeple m, boolean finalScoring) { - Position pos = m.getPosition(); - Tile tile = getGame().getBoard().get(pos); - ImmutablePoint offset = client.getResourceManager().getMeeplePlacement(tile, m.getClass(), m.getLocation()); - animationService.registerAnimation(pos, - new ScoreAnimation( - pos, - points, - offset, - client.getPlayerColor(m.getPlayer()), - finalScoring ? null : getScoreAnimationDuration() - ) - ); - } - - public void scored(Position pos, Player player, String points, boolean finalScoring) { - animationService.registerAnimation(pos, - new ScoreAnimation( - pos, - points, - new ImmutablePoint(50, 50), - client.getPlayerColor(player), - finalScoring ? null : getScoreAnimationDuration() - ) - ); - - } - - public void towerIncreased(Position p, Integer height) { - towerLayer.setTowerHeight(p, height); - gridPanel.repaint(); - } - - public void tunnelPiecePlaced(Player player, Position p, Location loc, boolean isSecondPiece) { - Color c; - if (isSecondPiece) { - c = client.getPlayerSecondTunelColor(player); - } else { - c = client.getPlayerColor(player); - } - Image tunnelPiece = client.getFigureTheme().getTunnelImage(c); - Tile tile = gridPanel.getTile(p); - ImmutablePoint offset = client.getResourceManager().getMeeplePlacement(tile, SmallFollower.class, loc); - meepleLayer.addPermanentImage(p, offset, tunnelPiece); - } - - public void dragonMoved(Position p) { - dragonLayer.setPosition(p); - dragonLayer.setMoves(0); - gridPanel.removeLayer(DragonAvailableMove.class); - gridPanel.repaint(); - } - - public void fairyMoved(Position p) { - fairyLayer.setPosition(p); - } - -} +package com.jcloisterzone.ui.grid; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Image; + +import com.jcloisterzone.Player; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.game.Capability; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.game.Snapshot; +import com.jcloisterzone.game.capability.BridgeCapability; +import com.jcloisterzone.game.capability.CastleCapability; +import com.jcloisterzone.game.capability.DragonCapability; +import com.jcloisterzone.game.capability.FairyCapability; +import com.jcloisterzone.game.capability.PlagueCapability; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.animation.AnimationService; +import com.jcloisterzone.ui.animation.ScoreAnimation; +import com.jcloisterzone.ui.grid.layer.AbstractTilePlacementLayer; +import com.jcloisterzone.ui.grid.layer.AnimationLayer; +import com.jcloisterzone.ui.grid.layer.BridgeLayer; +import com.jcloisterzone.ui.grid.layer.CastleLayer; +import com.jcloisterzone.ui.grid.layer.DragonAvailableMove; +import com.jcloisterzone.ui.grid.layer.DragonLayer; +import com.jcloisterzone.ui.grid.layer.FairyLayer; +import com.jcloisterzone.ui.grid.layer.MeepleLayer; +import com.jcloisterzone.ui.grid.layer.PlagueLayer; +import com.jcloisterzone.ui.grid.layer.TileLayer; +import com.jcloisterzone.ui.grid.layer.TowerLayer; +import com.jcloisterzone.ui.panel.BackgroundPanel; + + +@SuppressWarnings("serial") +public class MainPanel extends BackgroundPanel { + + private final Client client; + private AnimationService animationService; + + private GridPanel gridPanel; + private TileLayer tileLayer; + private MeepleLayer meepleLayer; + private TowerLayer towerLayer; + private DragonLayer dragonLayer; + private FairyLayer fairyLayer; + private BridgeLayer bridgeLayer; + private CastleLayer castleLayer; + private PlagueLayer plagueLayer; + + public MainPanel(Client client) { + this.client = client; + animationService = new AnimationService(); + animationService.start(); + + setLayout(new BorderLayout()); + } + + public GridPanel getGridPanel() { + return gridPanel; + } + + public AnimationService getAnimationService() { + return animationService; + } + + private Game getGame() { + return client.getGame(); + } + + public void started(Snapshot snapshot) { + animationService.clearAll(); + animationService.setGridPanel(null); + removeAll(); + setVisible(false); + + gridPanel = new GridPanel(client, snapshot); + meepleLayer = new MeepleLayer(gridPanel); + tileLayer = new TileLayer(gridPanel); + gridPanel.addLayer(tileLayer); + gridPanel.addLayer(meepleLayer); + gridPanel.addLayer(new AnimationLayer(gridPanel, animationService)); + + animationService.setGridPanel(gridPanel); + + for (Class capClass : getGame().getCapabilityClasses()) { + if (capClass.equals(TowerCapability.class)) { + towerLayer = new TowerLayer(gridPanel); + gridPanel.addLayer(towerLayer); + } + if (capClass.equals(DragonCapability.class)) { + dragonLayer = new DragonLayer(gridPanel, null); + gridPanel.addLayer(dragonLayer); + } + if (capClass.equals(FairyCapability.class)) { + fairyLayer = new FairyLayer(gridPanel, null); + gridPanel.addLayer(fairyLayer); + } + if (capClass.equals(BridgeCapability.class)) { + bridgeLayer = new BridgeLayer(gridPanel); + gridPanel.addLayer(bridgeLayer); + } + if (capClass.equals(CastleCapability.class)) { + castleLayer = new CastleLayer(gridPanel); + gridPanel.addLayer(castleLayer); + } + if (capClass.equals(PlagueCapability.class)) { + plagueLayer = new PlagueLayer(gridPanel); + gridPanel.addLayer(plagueLayer); + } + } + add(gridPanel); + setVisible(true); + } + + public void closeGame() { + gridPanel.clearActionDecorations(); + gridPanel.removeLayer(AbstractTilePlacementLayer.class); + gridPanel.setSecondPanel(null); + } + + public void tilePlaced(Tile tile) { + gridPanel.tilePlaced(tile, tileLayer); + } + + public void deployed(Meeple m) { + gridPanel.clearActionDecorations(); + meepleLayer.meepleDeployed(m); + } + + public void undeployed(Meeple m) { + gridPanel.clearActionDecorations(); + meepleLayer.meepleUndeployed(m); + } + + public void bridgeDeployed(Position pos, Location loc) { + gridPanel.clearActionDecorations(); + bridgeLayer.bridgeDeployed(pos, loc); + } + + public void castleDeployed(Castle castle1, Castle castle2) { + gridPanel.clearActionDecorations(); + castleLayer.castleDeployed(castle1, castle2); + } + + private Integer getScoreAnimationDuration() { + return client.getConfig().get("ui", "score_display_duration", Integer.class); + } + + public void scored(Feature scoreable, String points, Meeple m, boolean finalScoring) { + Position pos = m.getPosition(); + Tile tile = getGame().getBoard().get(pos); + ImmutablePoint offset = client.getResourceManager().getMeeplePlacement(tile, m.getClass(), m.getLocation()); + animationService.registerAnimation(pos, + new ScoreAnimation( + pos, + points, + offset, + client.getPlayerColor(m.getPlayer()), + finalScoring ? null : getScoreAnimationDuration() + ) + ); + } + + public void scored(Position pos, Player player, String points, boolean finalScoring) { + animationService.registerAnimation(pos, + new ScoreAnimation( + pos, + points, + new ImmutablePoint(50, 50), + client.getPlayerColor(player), + finalScoring ? null : getScoreAnimationDuration() + ) + ); + + } + + public void towerIncreased(Position p, Integer height) { + towerLayer.setTowerHeight(p, height); + gridPanel.repaint(); + } + + public void tunnelPiecePlaced(Player player, Position p, Location loc, boolean isSecondPiece) { + Color c; + if (isSecondPiece) { + c = client.getPlayerSecondTunelColor(player); + } else { + c = client.getPlayerColor(player); + } + Image tunnelPiece = client.getFigureTheme().getTunnelImage(c); + Tile tile = gridPanel.getTile(p); + ImmutablePoint offset = client.getResourceManager().getMeeplePlacement(tile, SmallFollower.class, loc); + meepleLayer.addPermanentImage(p, offset, tunnelPiece); + } + + public void dragonMoved(Position p) { + dragonLayer.setPosition(p); + dragonLayer.setMoves(0); + gridPanel.removeLayer(DragonAvailableMove.class); + gridPanel.repaint(); + } + + public void fairyMoved(Position p) { + fairyLayer.setPosition(p); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/AbbeyPlacementLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/AbbeyPlacementLayer.java index 66b2caa6c..9e9c7127a 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/AbbeyPlacementLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/AbbeyPlacementLayer.java @@ -1,44 +1,44 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.MouseEvent; - -import com.jcloisterzone.action.AbbeyPlacementAction; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.GridPanel; - -public class AbbeyPlacementLayer extends AbstractTilePlacementLayer { - - private AbbeyPlacementAction action; - - public AbbeyPlacementLayer(GridPanel gridPanel, AbbeyPlacementAction action) { - super(gridPanel, action.getSites()); - this.action = action; - } - - @Override - protected Image createPreviewIcon() { - return getClient().getResourceManager().getAbbeyImage(); - } - - @Override - protected void drawPreviewIcon(Graphics2D g2, Image previewIcon, Position previewPosition) { - Composite compositeBackup = g2.getComposite(); - g2.setComposite(ALLOWED_PREVIEW); - g2.drawImage(previewIcon, getAffineTransform(previewIcon.getWidth(null), previewPosition), null); - g2.setComposite(compositeBackup); - } - - @Override - public void mouseClicked(MouseEvent e, Position p) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (getPreviewPosition() != null && getClient().isClientActive()) { - e.consume(); - action.perform(getClient().getServer(), p); - } - } - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.event.MouseEvent; + +import com.jcloisterzone.action.AbbeyPlacementAction; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.GridPanel; + +public class AbbeyPlacementLayer extends AbstractTilePlacementLayer { + + private AbbeyPlacementAction action; + + public AbbeyPlacementLayer(GridPanel gridPanel, AbbeyPlacementAction action) { + super(gridPanel, action.getSites()); + this.action = action; + } + + @Override + protected Image createPreviewIcon() { + return getClient().getResourceManager().getAbbeyImage(); + } + + @Override + protected void drawPreviewIcon(Graphics2D g2, Image previewIcon, Position previewPosition) { + Composite compositeBackup = g2.getComposite(); + g2.setComposite(ALLOWED_PREVIEW); + g2.drawImage(previewIcon, getAffineTransform(previewIcon.getWidth(null), previewPosition), null); + g2.setComposite(compositeBackup); + } + + @Override + public void mouseClicked(MouseEvent e, Position p) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (getPreviewPosition() != null && getClient().isClientActive()) { + e.consume(); + action.perform(getClient().getServer(), p); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractAreaLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractAreaLayer.java index 1dfea4d59..79147ef67 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractAreaLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractAreaLayer.java @@ -1,174 +1,174 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.MouseEvent; -import java.awt.geom.Area; -import java.util.Map; -import java.util.Map.Entry; - -import javax.swing.ImageIcon; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridMouseAdapter; -import com.jcloisterzone.ui.grid.GridMouseListener; -import com.jcloisterzone.ui.grid.GridPanel; - - -public abstract class AbstractAreaLayer extends AbstractGridLayer implements GridMouseListener { - - private static final AlphaComposite AREA_ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .6f); - private static final AlphaComposite FIGURE_HIGHLIGHT_AREA_ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .75f); - - private Map areas; - private Location selectedLocation; - private Position selectedPosition; - - /*if true, area is displayed as placed meeple - this method is intended for tile placement debugging and is not optimized for performace - */ - private boolean figureHighlight = false; - - public AbstractAreaLayer(GridPanel gridPanel) { - super(gridPanel); - if ("figure".equals(getClient().getConfig().get("debug", "area_highlight"))) { - figureHighlight = true; - } - } - - private class MoveTrackingGridMouseAdapter extends GridMouseAdapter { - - public MoveTrackingGridMouseAdapter(GridPanel gridPanel, GridMouseListener listener) { - super(gridPanel, listener); - } - - @Override - public void mouseMoved(MouseEvent e) { - super.mouseMoved(e); - if (areas == null) return; - int size = getSquareSize(); - int x = e.getX() - gridPanel.getOffsetX(); - int y = e.getY() - gridPanel.getOffsetY(); - if (x < 0) x += 1000 * size; //prevent mod from negative number - if (y < 0) y += 1000 * size; //prevent mod from negative number - x = x % size; - y = y % size; - Location swap = null; - for (Entry enrty : areas.entrySet()) { - if (enrty.getValue().contains(x, y)) { - if (swap != null) { // 2 areas at point - select no one - swap = null; - break; - } - swap = enrty.getKey(); - } - } - if (swap != selectedLocation) { - selectedLocation = swap; - gridPanel.repaint(); - //RepaintManager.currentManager(gridPanel).addDirtyRegion(gridPanel, x * size, y * size, size, size); - //gridPanel.repaint(0, x * size, y * size, size, size); - } - } - - } - - @Override - protected GridMouseAdapter createGridMouserAdapter(GridMouseListener listener) { - return new MoveTrackingGridMouseAdapter(gridPanel, listener); - } - - private void cleanAreas() { - areas = null; - selectedPosition = null; - selectedLocation = null; - } - - @Override - public void zoomChanged(int squareSize) { - Position prevSelectedPosition = selectedPosition; - super.zoomChanged(squareSize); - if (selectedPosition != null && selectedPosition.equals(prevSelectedPosition)) { - //no square enter/leave trigger in this case - refresh areas - areas = prepareAreas(gridPanel.getTile(selectedPosition), selectedPosition); - } - } - - @Override - public void squareEntered(MouseEvent e, Position p) { - Tile tile = gridPanel.getTile(p); - if (tile != null) { - selectedPosition = p; - areas = prepareAreas(tile, p); - } - } - - protected abstract Map prepareAreas(Tile tile, Position p); - - - @Override - public void squareExited(MouseEvent e, Position p) { - if (selectedPosition != null) { - cleanAreas(); - gridPanel.repaint(); - } - } - - protected abstract void performAction(Position pos, Location selected); - - @Override - public void mouseClicked(MouseEvent e, Position pos) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (selectedLocation != null) { - performAction(pos, selectedLocation); - e.consume(); - } - } - } - - @Override - public void paint(Graphics2D g2) { - if (selectedLocation != null && areas != null) { - Composite old = g2.getComposite(); - if (figureHighlight) { - paintFigureHighlight(g2); - } else { - paintAreaHighlight(g2); - } - g2.setComposite(old); - } - } - - /** debug purposes highlight - it always shows basic follower (doesn't important for dbg */ - private void paintFigureHighlight(Graphics2D g2) { - //ugly copy pasted code from Meeple but uncached here - g2.setComposite(FIGURE_HIGHLIGHT_AREA_ALPHA_COMPOSITE); - Tile tile = getGame().getBoard().get(selectedPosition); - ImmutablePoint point = getClient().getResourceManager().getMeeplePlacement(tile, SmallFollower.class, selectedLocation); - Image unscaled = getClient().getFigureTheme().getFigureImage(SmallFollower.class, getClient().getPlayerColor(), null); - int size = (int) (getSquareSize() * MeepleLayer.FIGURE_SIZE_RATIO); - Image scaled = unscaled.getScaledInstance(size, size, Image.SCALE_SMOOTH); - scaled = new ImageIcon(scaled).getImage(); - ImmutablePoint scaledOffset = point.scale(getSquareSize(), (int)(getSquareSize() * MeepleLayer.FIGURE_SIZE_RATIO)); - g2.drawImage(scaled, getOffsetX(selectedPosition) + scaledOffset.getX(), getOffsetY(selectedPosition) + scaledOffset.getY(), gridPanel); - } - - /** standard highlight **/ - private void paintAreaHighlight(Graphics2D g2) { - g2.setColor(getClient().getPlayerColor()); - g2.setComposite(AREA_ALPHA_COMPOSITE); - g2.fill(transformArea(areas.get(selectedLocation), selectedPosition)); - } - - @Override - public int getZIndex() { - return 100; - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.awt.geom.Area; +import java.util.Map; +import java.util.Map.Entry; + +import javax.swing.ImageIcon; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridMouseAdapter; +import com.jcloisterzone.ui.grid.GridMouseListener; +import com.jcloisterzone.ui.grid.GridPanel; + + +public abstract class AbstractAreaLayer extends AbstractGridLayer implements GridMouseListener { + + private static final AlphaComposite AREA_ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .6f); + private static final AlphaComposite FIGURE_HIGHLIGHT_AREA_ALPHA_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .75f); + + private Map areas; + private Location selectedLocation; + private Position selectedPosition; + + /*if true, area is displayed as placed meeple + this method is intended for tile placement debugging and is not optimized for performace + */ + private boolean figureHighlight = false; + + public AbstractAreaLayer(GridPanel gridPanel) { + super(gridPanel); + if ("figure".equals(getClient().getConfig().get("debug", "area_highlight"))) { + figureHighlight = true; + } + } + + private class MoveTrackingGridMouseAdapter extends GridMouseAdapter { + + public MoveTrackingGridMouseAdapter(GridPanel gridPanel, GridMouseListener listener) { + super(gridPanel, listener); + } + + @Override + public void mouseMoved(MouseEvent e) { + super.mouseMoved(e); + if (areas == null) return; + int size = getSquareSize(); + int x = e.getX() - gridPanel.getOffsetX(); + int y = e.getY() - gridPanel.getOffsetY(); + if (x < 0) x += 1000 * size; //prevent mod from negative number + if (y < 0) y += 1000 * size; //prevent mod from negative number + x = x % size; + y = y % size; + Location swap = null; + for (Entry enrty : areas.entrySet()) { + if (enrty.getValue().contains(x, y)) { + if (swap != null) { // 2 areas at point - select no one + swap = null; + break; + } + swap = enrty.getKey(); + } + } + if (swap != selectedLocation) { + selectedLocation = swap; + gridPanel.repaint(); + //RepaintManager.currentManager(gridPanel).addDirtyRegion(gridPanel, x * size, y * size, size, size); + //gridPanel.repaint(0, x * size, y * size, size, size); + } + } + + } + + @Override + protected GridMouseAdapter createGridMouserAdapter(GridMouseListener listener) { + return new MoveTrackingGridMouseAdapter(gridPanel, listener); + } + + private void cleanAreas() { + areas = null; + selectedPosition = null; + selectedLocation = null; + } + + @Override + public void zoomChanged(int squareSize) { + Position prevSelectedPosition = selectedPosition; + super.zoomChanged(squareSize); + if (selectedPosition != null && selectedPosition.equals(prevSelectedPosition)) { + //no square enter/leave trigger in this case - refresh areas + areas = prepareAreas(gridPanel.getTile(selectedPosition), selectedPosition); + } + } + + @Override + public void squareEntered(MouseEvent e, Position p) { + Tile tile = gridPanel.getTile(p); + if (tile != null) { + selectedPosition = p; + areas = prepareAreas(tile, p); + } + } + + protected abstract Map prepareAreas(Tile tile, Position p); + + + @Override + public void squareExited(MouseEvent e, Position p) { + if (selectedPosition != null) { + cleanAreas(); + gridPanel.repaint(); + } + } + + protected abstract void performAction(Position pos, Location selected); + + @Override + public void mouseClicked(MouseEvent e, Position pos) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (selectedLocation != null) { + performAction(pos, selectedLocation); + e.consume(); + } + } + } + + @Override + public void paint(Graphics2D g2) { + if (selectedLocation != null && areas != null) { + Composite old = g2.getComposite(); + if (figureHighlight) { + paintFigureHighlight(g2); + } else { + paintAreaHighlight(g2); + } + g2.setComposite(old); + } + } + + /** debug purposes highlight - it always shows basic follower (doesn't important for dbg */ + private void paintFigureHighlight(Graphics2D g2) { + //ugly copy pasted code from Meeple but uncached here + g2.setComposite(FIGURE_HIGHLIGHT_AREA_ALPHA_COMPOSITE); + Tile tile = getGame().getBoard().get(selectedPosition); + ImmutablePoint point = getClient().getResourceManager().getMeeplePlacement(tile, SmallFollower.class, selectedLocation); + Image unscaled = getClient().getFigureTheme().getFigureImage(SmallFollower.class, getClient().getPlayerColor(), null); + int size = (int) (getSquareSize() * MeepleLayer.FIGURE_SIZE_RATIO); + Image scaled = unscaled.getScaledInstance(size, size, Image.SCALE_SMOOTH); + scaled = new ImageIcon(scaled).getImage(); + ImmutablePoint scaledOffset = point.scale(getSquareSize(), (int)(getSquareSize() * MeepleLayer.FIGURE_SIZE_RATIO)); + g2.drawImage(scaled, getOffsetX(selectedPosition) + scaledOffset.getX(), getOffsetY(selectedPosition) + scaledOffset.getY(), gridPanel); + } + + /** standard highlight **/ + private void paintAreaHighlight(Graphics2D g2) { + g2.setColor(getClient().getPlayerColor()); + g2.setComposite(AREA_ALPHA_COMPOSITE); + g2.fill(transformArea(areas.get(selectedLocation), selectedPosition)); + } + + @Override + public int getZIndex() { + return 100; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractGridLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractGridLayer.java index e17d7c077..e09b8e89c 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractGridLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractGridLayer.java @@ -1,174 +1,174 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.event.MouseEvent; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Rectangle2D; - -import javax.swing.event.MouseInputListener; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.game.Game; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.DragInsensitiveMouseClickListener; -import com.jcloisterzone.ui.grid.GridLayer; -import com.jcloisterzone.ui.grid.GridMouseAdapter; -import com.jcloisterzone.ui.grid.GridMouseListener; -import com.jcloisterzone.ui.grid.GridPanel; - -public abstract class AbstractGridLayer implements GridLayer { - - protected final GridPanel gridPanel; - private MouseInputListener mouseListener; - - public AbstractGridLayer(GridPanel gridPanel) { - this.gridPanel = gridPanel; - } - - private void triggerFakeMouseEvent() { - Point pt = gridPanel.getMousePosition(); - if (pt != null) { - mouseListener.mouseMoved( - new MouseEvent(gridPanel, 0, System.currentTimeMillis(), 0, pt.x, pt.y, -1, -1, 0, false, 0) - ); - } - } - - @Override - public void zoomChanged(int squareSize) { - if (mouseListener != null) { - triggerFakeMouseEvent(); - } - } - -// @Override -// public void gridChanged(int left, int right, int top, int bottom) { -// } - - protected GridMouseAdapter createGridMouserAdapter(GridMouseListener listener) { - return new GridMouseAdapter(gridPanel, listener); - } - - @Override - public void layerAdded() { - if (this instanceof GridMouseListener && getClient().isClientActive()) { - mouseListener = new DragInsensitiveMouseClickListener(createGridMouserAdapter((GridMouseListener) this)); - gridPanel.addMouseListener(mouseListener); - gridPanel.addMouseMotionListener(mouseListener); - triggerFakeMouseEvent(); - } - } - - @Override - public void layerRemoved() { - if (mouseListener != null) { - gridPanel.removeMouseMotionListener(mouseListener); - gridPanel.removeMouseListener(mouseListener); - mouseListener = null; - } - } - public AffineTransform getAffineTransform(int scaleFrom, Position pos) { - return getAffineTransform(scaleFrom, pos, Rotation.R0); - } - - public AffineTransform getAffineTransform(Position pos) { - return getAffineTransform(pos, Rotation.R0); - } - - public AffineTransform getAffineTransform(Position pos, Rotation rotation) { - AffineTransform r = rotation.getAffineTransform(getSquareSize()); - AffineTransform t = AffineTransform.getTranslateInstance(getOffsetX(pos), getOffsetY(pos)); - t.concatenate(r); - return t; - } - - public AffineTransform getAffineTransform(int scaleFrom, Position pos, Rotation rotation) { - double ratio = getSquareSize() / (double) scaleFrom; - return getAffineTransform(scaleFrom, pos, rotation, ratio); - } - - public AffineTransform getAffineTransform(int scaleFrom, Position pos, Rotation rotation, double ratio) { - AffineTransform t = getAffineTransform(pos, rotation); - AffineTransform scale = AffineTransform.getScaleInstance(ratio, ratio); - t.concatenate(scale); - return t; - } - - public int getOffsetX(Position pos) { - return getSquareSize() * pos.x; - } - - public int getOffsetY(Position pos) { - return getSquareSize() * pos.y; - } - - public int getSquareSize() { - return gridPanel.getSquareSize(); - } - - protected Client getClient() { - return gridPanel.getClient(); - } - - protected Game getGame() { - return getClient().getGame(); - } - - protected Area transformArea(Area area, Position pos) { - Area copy = new Area(area); - copy.transform(getAffineTransform(pos)); - return copy; - } - - // LEGACY CODE - TODO REFACTOR - - private int scale(int x) { - return (int) (getSquareSize() * (x / 100.0)); - } - - @Deprecated - private Font getFont(int relativeSize) { - int realSize = scale(relativeSize); - return new Font(null, Font.BOLD, realSize); -// Font font = Square.cachedFont; -// if (font == null || font.getSize() != realSize) { -// font = new Font(null, Font.BOLD, realSize); -// Square.cachedFont = font; -// } -// return font; - } - - public void drawAntialiasedTextCentered(Graphics2D g2, String text, int fontSize, Position pos, ImmutablePoint centerNoScaled, Color fgColor, Color bgColor) { - ImmutablePoint center = centerNoScaled.scale(getSquareSize()); - drawAntialiasedTextCenteredNoScale(g2, text, fontSize, pos, center, fgColor, bgColor); - } - - - //TODO misleading name - is centered around point and scaled font but not scale center point (probably :) - public void drawAntialiasedTextCenteredNoScale(Graphics2D g2, String text, int fontSize, Position pos, ImmutablePoint center, Color fgColor, Color bgColor) { - Color original = g2.getColor(); - FontRenderContext frc = g2.getFontRenderContext(); - TextLayout tl = new TextLayout(text, getFont(fontSize),frc); - Rectangle2D bounds = tl.getBounds(); - - center = center.translate( (int) (bounds.getWidth() / -2), (int) (bounds.getHeight() / -2)); - - if (bgColor != null) { - g2.setColor(bgColor); - g2.fillRect(getOffsetX(pos) + center.getX() - 6, getOffsetY(pos) + center.getY() - 5, 12 + (int)bounds.getWidth(),10 +(int) bounds.getHeight()); - } - - g2.setColor(fgColor); - tl.draw(g2, getOffsetX(pos) + center.getX(), getOffsetY(pos) + center.getY() + (int) bounds.getHeight()); - g2.setColor(original); - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; + +import javax.swing.event.MouseInputListener; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.game.Game; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.DragInsensitiveMouseClickListener; +import com.jcloisterzone.ui.grid.GridLayer; +import com.jcloisterzone.ui.grid.GridMouseAdapter; +import com.jcloisterzone.ui.grid.GridMouseListener; +import com.jcloisterzone.ui.grid.GridPanel; + +public abstract class AbstractGridLayer implements GridLayer { + + protected final GridPanel gridPanel; + private MouseInputListener mouseListener; + + public AbstractGridLayer(GridPanel gridPanel) { + this.gridPanel = gridPanel; + } + + private void triggerFakeMouseEvent() { + Point pt = gridPanel.getMousePosition(); + if (pt != null) { + mouseListener.mouseMoved( + new MouseEvent(gridPanel, 0, System.currentTimeMillis(), 0, pt.x, pt.y, -1, -1, 0, false, 0) + ); + } + } + + @Override + public void zoomChanged(int squareSize) { + if (mouseListener != null) { + triggerFakeMouseEvent(); + } + } + +// @Override +// public void gridChanged(int left, int right, int top, int bottom) { +// } + + protected GridMouseAdapter createGridMouserAdapter(GridMouseListener listener) { + return new GridMouseAdapter(gridPanel, listener); + } + + @Override + public void layerAdded() { + if (this instanceof GridMouseListener && getClient().isClientActive()) { + mouseListener = new DragInsensitiveMouseClickListener(createGridMouserAdapter((GridMouseListener) this)); + gridPanel.addMouseListener(mouseListener); + gridPanel.addMouseMotionListener(mouseListener); + triggerFakeMouseEvent(); + } + } + + @Override + public void layerRemoved() { + if (mouseListener != null) { + gridPanel.removeMouseMotionListener(mouseListener); + gridPanel.removeMouseListener(mouseListener); + mouseListener = null; + } + } + public AffineTransform getAffineTransform(int scaleFrom, Position pos) { + return getAffineTransform(scaleFrom, pos, Rotation.R0); + } + + public AffineTransform getAffineTransform(Position pos) { + return getAffineTransform(pos, Rotation.R0); + } + + public AffineTransform getAffineTransform(Position pos, Rotation rotation) { + AffineTransform r = rotation.getAffineTransform(getSquareSize()); + AffineTransform t = AffineTransform.getTranslateInstance(getOffsetX(pos), getOffsetY(pos)); + t.concatenate(r); + return t; + } + + public AffineTransform getAffineTransform(int scaleFrom, Position pos, Rotation rotation) { + double ratio = getSquareSize() / (double) scaleFrom; + return getAffineTransform(scaleFrom, pos, rotation, ratio); + } + + public AffineTransform getAffineTransform(int scaleFrom, Position pos, Rotation rotation, double ratio) { + AffineTransform t = getAffineTransform(pos, rotation); + AffineTransform scale = AffineTransform.getScaleInstance(ratio, ratio); + t.concatenate(scale); + return t; + } + + public int getOffsetX(Position pos) { + return getSquareSize() * pos.x; + } + + public int getOffsetY(Position pos) { + return getSquareSize() * pos.y; + } + + public int getSquareSize() { + return gridPanel.getSquareSize(); + } + + protected Client getClient() { + return gridPanel.getClient(); + } + + protected Game getGame() { + return getClient().getGame(); + } + + protected Area transformArea(Area area, Position pos) { + Area copy = new Area(area); + copy.transform(getAffineTransform(pos)); + return copy; + } + + // LEGACY CODE - TODO REFACTOR + + private int scale(int x) { + return (int) (getSquareSize() * (x / 100.0)); + } + + @Deprecated + private Font getFont(int relativeSize) { + int realSize = scale(relativeSize); + return new Font(null, Font.BOLD, realSize); +// Font font = Square.cachedFont; +// if (font == null || font.getSize() != realSize) { +// font = new Font(null, Font.BOLD, realSize); +// Square.cachedFont = font; +// } +// return font; + } + + public void drawAntialiasedTextCentered(Graphics2D g2, String text, int fontSize, Position pos, ImmutablePoint centerNoScaled, Color fgColor, Color bgColor) { + ImmutablePoint center = centerNoScaled.scale(getSquareSize()); + drawAntialiasedTextCenteredNoScale(g2, text, fontSize, pos, center, fgColor, bgColor); + } + + + //TODO misleading name - is centered around point and scaled font but not scale center point (probably :) + public void drawAntialiasedTextCenteredNoScale(Graphics2D g2, String text, int fontSize, Position pos, ImmutablePoint center, Color fgColor, Color bgColor) { + Color original = g2.getColor(); + FontRenderContext frc = g2.getFontRenderContext(); + TextLayout tl = new TextLayout(text, getFont(fontSize),frc); + Rectangle2D bounds = tl.getBounds(); + + center = center.translate( (int) (bounds.getWidth() / -2), (int) (bounds.getHeight() / -2)); + + if (bgColor != null) { + g2.setColor(bgColor); + g2.fillRect(getOffsetX(pos) + center.getX() - 6, getOffsetY(pos) + center.getY() - 5, 12 + (int)bounds.getWidth(),10 +(int) bounds.getHeight()); + } + + g2.setColor(fgColor); + tl.draw(g2, getOffsetX(pos) + center.getX(), getOffsetY(pos) + center.getY() + (int) bounds.getHeight()); + g2.setColor(original); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTileLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTileLayer.java index bc0d7f7bf..e19f4f126 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTileLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTileLayer.java @@ -1,76 +1,76 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridPanel; - -//PROBABLY TO DELETE -public abstract class AbstractTileLayer extends AbstractGridLayer { - - private Position position; - private Rotation rotation; - - public AbstractTileLayer(GridPanel gridPanel, Position position) { - this(gridPanel, position, Rotation.R0); - } - - public AbstractTileLayer(GridPanel gridPanel, Position position, Rotation rotation) { - super(gridPanel); - this.position = position; - this.rotation = rotation; - } - - //convinient methods - - public Position getPosition() { - return position; - } - - public void setPosition(Position position) { - this.position = position; - } - - public Rotation getRotation() { - return rotation; - } - - public void setRotation(Rotation rotation) { - this.rotation = rotation; - } - - protected int getOffsetX() { - return getOffsetX(position); - } - - protected int getOffsetY() { - return getOffsetY(position); - } - - public AffineTransform getAffineTransform() { - return getAffineTransform(position, rotation); - } - - public AffineTransform getAffineTransform(Rotation rotation) { - return getAffineTransform(position, rotation); - } - - - - //TODO revise - - - - public void drawAntialiasedTextCentered(Graphics2D g2, String text, int fontSize, ImmutablePoint centerNoScaled, Color fgColor, Color bgColor) { - drawAntialiasedTextCentered(g2, text, fontSize, position, centerNoScaled, fgColor, bgColor); - } - - - public void drawAntialiasedTextCenteredNoScale(Graphics2D g2, String text, int fontSize, ImmutablePoint center, Color fgColor, Color bgColor) { - drawAntialiasedTextCenteredNoScale(g2, text, fontSize, position, center, fgColor, bgColor); - } -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridPanel; + +//PROBABLY TO DELETE +public abstract class AbstractTileLayer extends AbstractGridLayer { + + private Position position; + private Rotation rotation; + + public AbstractTileLayer(GridPanel gridPanel, Position position) { + this(gridPanel, position, Rotation.R0); + } + + public AbstractTileLayer(GridPanel gridPanel, Position position, Rotation rotation) { + super(gridPanel); + this.position = position; + this.rotation = rotation; + } + + //convinient methods + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + + public Rotation getRotation() { + return rotation; + } + + public void setRotation(Rotation rotation) { + this.rotation = rotation; + } + + protected int getOffsetX() { + return getOffsetX(position); + } + + protected int getOffsetY() { + return getOffsetY(position); + } + + public AffineTransform getAffineTransform() { + return getAffineTransform(position, rotation); + } + + public AffineTransform getAffineTransform(Rotation rotation) { + return getAffineTransform(position, rotation); + } + + + + //TODO revise + + + + public void drawAntialiasedTextCentered(Graphics2D g2, String text, int fontSize, ImmutablePoint centerNoScaled, Color fgColor, Color bgColor) { + drawAntialiasedTextCentered(g2, text, fontSize, position, centerNoScaled, fgColor, bgColor); + } + + + public void drawAntialiasedTextCenteredNoScale(Graphics2D g2, String text, int fontSize, ImmutablePoint center, Color fgColor, Color bgColor) { + drawAntialiasedTextCenteredNoScale(g2, text, fontSize, position, center, fgColor, bgColor); + } +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTilePlacementLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTilePlacementLayer.java index c7cd85b0a..93cdda684 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTilePlacementLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/AbstractTilePlacementLayer.java @@ -1,87 +1,87 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.MouseEvent; -import java.util.Set; - -import com.google.common.collect.ImmutableSet; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.GridMouseListener; -import com.jcloisterzone.ui.grid.GridPanel; - -public abstract class AbstractTilePlacementLayer extends AbstractGridLayer implements GridMouseListener { - - protected static final Composite ALLOWED_PREVIEW = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .8f); - protected static final Composite DISALLOWED_PREVIEW = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .4f); - - private ImmutableSet availablePositions; - - private Position previewPosition; - private Image previewIcon; - - - public AbstractTilePlacementLayer(GridPanel gridPanel, Set positions) { - super(gridPanel); - availablePositions = ImmutableSet.copyOf(positions); - } - - @Override - public int getZIndex() { - return 3; - } - - public Position getPreviewPosition() { - return previewPosition; - }; - - abstract protected void drawPreviewIcon(Graphics2D g2, Image previewIcon, Position pos); - abstract protected Image createPreviewIcon(); - - - @Override - public void paint(Graphics2D g2) { - int borderSize = getSquareSize() - 4, - shift = 2, - thickness = borderSize/14; - - g2.setColor(Color.LIGHT_GRAY); - for (Position p : availablePositions) { - if (previewPosition == null || !previewPosition.equals(p)) { - int x = getOffsetX(p)+shift, y = getOffsetY(p)+shift; - g2.fillRect(x, y, borderSize, thickness); - g2.fillRect(x, y+borderSize-thickness, borderSize, thickness); - g2.fillRect(x, y, thickness, borderSize); - g2.fillRect(x+borderSize-thickness, y, thickness, borderSize); - } - } - - if (previewPosition != null) { - if (previewIcon == null) { - previewIcon = createPreviewIcon(); - } - drawPreviewIcon(g2, previewIcon, previewPosition); - } - g2.setColor(getClient().isClientActive() ? Color.BLACK : Color.GRAY); - - } - - @Override - public void squareEntered(MouseEvent e, Position p) { - if (availablePositions.contains(p)) { - previewPosition = p; - gridPanel.repaint(); - } - } - - @Override - public void squareExited(MouseEvent e, Position p) { - if (previewPosition != null) { - previewPosition = null; - gridPanel.repaint(); - } - } +package com.jcloisterzone.ui.grid.layer; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.GridMouseListener; +import com.jcloisterzone.ui.grid.GridPanel; + +public abstract class AbstractTilePlacementLayer extends AbstractGridLayer implements GridMouseListener { + + protected static final Composite ALLOWED_PREVIEW = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .8f); + protected static final Composite DISALLOWED_PREVIEW = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .4f); + + private ImmutableSet availablePositions; + + private Position previewPosition; + private Image previewIcon; + + + public AbstractTilePlacementLayer(GridPanel gridPanel, Set positions) { + super(gridPanel); + availablePositions = ImmutableSet.copyOf(positions); + } + + @Override + public int getZIndex() { + return 3; + } + + public Position getPreviewPosition() { + return previewPosition; + }; + + abstract protected void drawPreviewIcon(Graphics2D g2, Image previewIcon, Position pos); + abstract protected Image createPreviewIcon(); + + + @Override + public void paint(Graphics2D g2) { + int borderSize = getSquareSize() - 4, + shift = 2, + thickness = borderSize/14; + + g2.setColor(Color.LIGHT_GRAY); + for (Position p : availablePositions) { + if (previewPosition == null || !previewPosition.equals(p)) { + int x = getOffsetX(p)+shift, y = getOffsetY(p)+shift; + g2.fillRect(x, y, borderSize, thickness); + g2.fillRect(x, y+borderSize-thickness, borderSize, thickness); + g2.fillRect(x, y, thickness, borderSize); + g2.fillRect(x+borderSize-thickness, y, thickness, borderSize); + } + } + + if (previewPosition != null) { + if (previewIcon == null) { + previewIcon = createPreviewIcon(); + } + drawPreviewIcon(g2, previewIcon, previewPosition); + } + g2.setColor(getClient().isClientActive() ? Color.BLACK : Color.GRAY); + + } + + @Override + public void squareEntered(MouseEvent e, Position p) { + if (availablePositions.contains(p)) { + previewPosition = p; + gridPanel.repaint(); + } + } + + @Override + public void squareExited(MouseEvent e, Position p) { + if (previewPosition != null) { + previewPosition = null; + gridPanel.repaint(); + } + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/AnimationLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/AnimationLayer.java index da9dd74aa..e449d45f6 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/AnimationLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/AnimationLayer.java @@ -1,37 +1,37 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Graphics2D; - -import com.jcloisterzone.ui.animation.Animation; -import com.jcloisterzone.ui.animation.AnimationService; -import com.jcloisterzone.ui.animation.RecentPlacement; -import com.jcloisterzone.ui.animation.ScoreAnimation; -import com.jcloisterzone.ui.grid.GridPanel; - -public class AnimationLayer extends AbstractGridLayer { - - private final AnimationService service; - - public AnimationLayer(GridPanel gridPanel, AnimationService service) { - super(gridPanel); - this.service = service; - } - - @Override - public void paint(Graphics2D g2) { - //HACK to correct animation order - TODO change animation design - for (Animation a : service.getAnimations()) { - if (a instanceof RecentPlacement) a.paint(this, g2); - } - for (Animation a : service.getAnimations()) { - if (a instanceof ScoreAnimation) a.paint(this, g2); - } - } - - @Override - public int getZIndex() { - return 800; - } - - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Graphics2D; + +import com.jcloisterzone.ui.animation.Animation; +import com.jcloisterzone.ui.animation.AnimationService; +import com.jcloisterzone.ui.animation.RecentPlacement; +import com.jcloisterzone.ui.animation.ScoreAnimation; +import com.jcloisterzone.ui.grid.GridPanel; + +public class AnimationLayer extends AbstractGridLayer { + + private final AnimationService service; + + public AnimationLayer(GridPanel gridPanel, AnimationService service) { + super(gridPanel); + this.service = service; + } + + @Override + public void paint(Graphics2D g2) { + //HACK to correct animation order - TODO change animation design + for (Animation a : service.getAnimations()) { + if (a instanceof RecentPlacement) a.paint(this, g2); + } + for (Animation a : service.getAnimations()) { + if (a instanceof ScoreAnimation) a.paint(this, g2); + } + } + + @Override + public int getZIndex() { + return 800; + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/BarnAreaLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/BarnAreaLayer.java index 729a3f09e..1b3991505 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/BarnAreaLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/BarnAreaLayer.java @@ -1,35 +1,35 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.geom.Area; -import java.util.Map; - -import com.jcloisterzone.action.BarnAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.ui.grid.GridPanel; - -public class BarnAreaLayer extends AbstractAreaLayer { - - final BarnAction action; - - public BarnAreaLayer(GridPanel gridPanel, BarnAction action) { - super(gridPanel); - this.action = action; - } - - @Override - protected Map prepareAreas(Tile tile, Position p) { - //quick fix - if (getClient().getGame().getCurrentTile().getPosition().equals(p)) { - return getClient().getResourceManager().getBarnTileAreas(tile, getSquareSize(), action.get(p)); - } - return null; - } - - @Override - protected void performAction(Position pos, Location selected) { - action.perform(getClient().getServer(), pos, selected); - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.geom.Area; +import java.util.Map; + +import com.jcloisterzone.action.BarnAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.ui.grid.GridPanel; + +public class BarnAreaLayer extends AbstractAreaLayer { + + final BarnAction action; + + public BarnAreaLayer(GridPanel gridPanel, BarnAction action) { + super(gridPanel); + this.action = action; + } + + @Override + protected Map prepareAreas(Tile tile, Position p) { + //quick fix + if (getClient().getGame().getCurrentTile().getPosition().equals(p)) { + return getClient().getResourceManager().getBarnTileAreas(tile, getSquareSize(), action.get(p)); + } + return null; + } + + @Override + protected void performAction(Position pos, Location selected) { + action.perform(getClient().getServer(), pos, selected); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/BridgeLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/BridgeLayer.java index 840683085..b277d375e 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/BridgeLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/BridgeLayer.java @@ -1,65 +1,65 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.AlphaComposite; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.ui.grid.GridPanel; - -public class BridgeLayer extends AbstractGridLayer { - - private static final AlphaComposite BRIDGE_FILL_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .6f); - //private static final AlphaComposite BRIDGE_STROKE_COMPOSITE = AlphaComposite.SrcOver; - - public BridgeLayer(GridPanel gridPanel) { - super(gridPanel); - } - - //TODO store direct images as in Meeple layer??? - private Map bridges = new HashMap<>(); - - @Override - public void paint(Graphics2D g2) { - Composite oldComposite = g2.getComposite(); -// Stroke oldStroke = g2.getStroke(); -// g2.setStroke(new BasicStroke(getSquareSize() * 0.015f)); - for (Entry entry : bridges.entrySet()) { - //devel code only - use image instead - Tile tile = entry.getKey(); - Location loc = entry.getValue(); - Position pos = tile.getPosition(); - Area a = getClient().getResourceManager().getBridgeArea(tile, getSquareSize(), loc); - a.transform(AffineTransform.getTranslateInstance(getOffsetX(pos), getOffsetY(pos))); - g2.setColor(Color.BLACK); - g2.setComposite(BRIDGE_FILL_COMPOSITE); - g2.fill(a); -// g2.setColor(Color.BLACK); -// g2.setComposite(BRIDGE_STROKE_COMPOSITE); -// g2.draw(a); - - } -// g2.setStroke(oldStroke); - g2.setComposite(oldComposite); - - } - - @Override - public int getZIndex() { - return 45; - } - - public void bridgeDeployed(Position pos, Location loc) { - Tile tile = getClient().getGame().getBoard().get(pos); - bridges.put(tile, loc); - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.ui.grid.GridPanel; + +public class BridgeLayer extends AbstractGridLayer { + + private static final AlphaComposite BRIDGE_FILL_COMPOSITE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .6f); + //private static final AlphaComposite BRIDGE_STROKE_COMPOSITE = AlphaComposite.SrcOver; + + public BridgeLayer(GridPanel gridPanel) { + super(gridPanel); + } + + //TODO store direct images as in Meeple layer??? + private Map bridges = new HashMap<>(); + + @Override + public void paint(Graphics2D g2) { + Composite oldComposite = g2.getComposite(); +// Stroke oldStroke = g2.getStroke(); +// g2.setStroke(new BasicStroke(getSquareSize() * 0.015f)); + for (Entry entry : bridges.entrySet()) { + //devel code only - use image instead + Tile tile = entry.getKey(); + Location loc = entry.getValue(); + Position pos = tile.getPosition(); + Area a = getClient().getResourceManager().getBridgeArea(tile, getSquareSize(), loc); + a.transform(AffineTransform.getTranslateInstance(getOffsetX(pos), getOffsetY(pos))); + g2.setColor(Color.BLACK); + g2.setComposite(BRIDGE_FILL_COMPOSITE); + g2.fill(a); +// g2.setColor(Color.BLACK); +// g2.setComposite(BRIDGE_STROKE_COMPOSITE); +// g2.draw(a); + + } +// g2.setStroke(oldStroke); + g2.setComposite(oldComposite); + + } + + @Override + public int getZIndex() { + return 45; + } + + public void bridgeDeployed(Position pos, Location loc) { + Tile tile = getClient().getGame().getBoard().get(pos); + bridges.put(tile, loc); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/CastleLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/CastleLayer.java index b49b49dc9..b06d329c5 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/CastleLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/CastleLayer.java @@ -1,72 +1,72 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Graphics2D; -import java.awt.Image; -import java.util.ArrayList; -import java.util.List; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.ui.grid.GridPanel; - -public class CastleLayer extends AbstractGridLayer { - - private static class DeployedCastle { - Position position; - Rotation rotation; - - public DeployedCastle(Position position, Rotation rotation) { - this.position = position; - this.rotation = rotation; - } - } - - private List castles = new ArrayList<>(); - private Image castleImage; - - public CastleLayer(GridPanel gridPanel) { - super(gridPanel); - castleImage = getClient().getFigureTheme().getNeutralImage("castle"); - } - - public void castleDeployed(Castle castle1, Castle castle2) { - Position p1 = castle1.getTile().getPosition(); - Position p2 = castle2.getTile().getPosition(); - Position pos; - Rotation rot; - - if (p1.x == p2.x) { - pos = p1.y < p2.y ? p1 : p2; - rot = Rotation.R0; - } else { - pos = p1.x < p2.x ? p1 : p2; - rot = Rotation.R90; - } - castles.add(new DeployedCastle(pos, rot)); - } - - @Override - public void paint(Graphics2D g2) { - int size = getSquareSize(); - for (DeployedCastle dc : castles) { - if (dc.rotation == Rotation.R0) { - g2.drawImage(castleImage, getOffsetX(dc.position), getOffsetY(dc.position) + size/2, size, size, null); - } else { -// AffineTransform at = Rotation.R90.getAffineTransform(size); -// at.concatenate(AffineTransform.getTranslateInstance(getOffsetX(dc.position) + size/2, getOffsetY(dc.position))); -// g2.drawImage(castleImage, at, null); - - //TODO rotated - g2.drawImage(castleImage, getOffsetX(dc.position) + size/2, getOffsetY(dc.position), size, size, null); - } - } - } - - @Override - public int getZIndex() { - return 45; - } - - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.ui.grid.GridPanel; + +public class CastleLayer extends AbstractGridLayer { + + private static class DeployedCastle { + Position position; + Rotation rotation; + + public DeployedCastle(Position position, Rotation rotation) { + this.position = position; + this.rotation = rotation; + } + } + + private List castles = new ArrayList<>(); + private Image castleImage; + + public CastleLayer(GridPanel gridPanel) { + super(gridPanel); + castleImage = getClient().getFigureTheme().getNeutralImage("castle"); + } + + public void castleDeployed(Castle castle1, Castle castle2) { + Position p1 = castle1.getTile().getPosition(); + Position p2 = castle2.getTile().getPosition(); + Position pos; + Rotation rot; + + if (p1.x == p2.x) { + pos = p1.y < p2.y ? p1 : p2; + rot = Rotation.R0; + } else { + pos = p1.x < p2.x ? p1 : p2; + rot = Rotation.R90; + } + castles.add(new DeployedCastle(pos, rot)); + } + + @Override + public void paint(Graphics2D g2) { + int size = getSquareSize(); + for (DeployedCastle dc : castles) { + if (dc.rotation == Rotation.R0) { + g2.drawImage(castleImage, getOffsetX(dc.position), getOffsetY(dc.position) + size/2, size, size, null); + } else { +// AffineTransform at = Rotation.R90.getAffineTransform(size); +// at.concatenate(AffineTransform.getTranslateInstance(getOffsetX(dc.position) + size/2, getOffsetY(dc.position))); +// g2.drawImage(castleImage, at, null); + + //TODO rotated + g2.drawImage(castleImage, getOffsetX(dc.position) + size/2, getOffsetY(dc.position), size, size, null); + } + } + } + + @Override + public int getZIndex() { + return 45; + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/DragonAvailableMove.java b/src/main/java/com/jcloisterzone/ui/grid/layer/DragonAvailableMove.java index a0d6052a6..0b03cb6bd 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/DragonAvailableMove.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/DragonAvailableMove.java @@ -1,57 +1,57 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.MouseEvent; -import java.util.Set; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.GridMouseListener; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class DragonAvailableMove extends AbstractGridLayer implements GridMouseListener { - - private Set positions; - private Position selected; - - public DragonAvailableMove(GridPanel gridPanel, Set positions) { - super(gridPanel); - this.positions = positions; - } - - public void paint(Graphics2D g2) { - Image dragon = getClient().getControlsTheme().getActionDecoration("dragon"); - for (Position pos : positions) { - g2.drawImage(dragon, getOffsetX(pos), getOffsetY(pos), getSquareSize(), getSquareSize(), null); - } - } - - @Override - public int getZIndex() { - return 60; - } - - @Override - public void squareEntered(MouseEvent e, Position p) { - selected = p; - } - - @Override - public void squareExited(MouseEvent e, Position p) { - selected = null; - - } - - @Override - public void mouseClicked(MouseEvent e, Position p) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (positions.contains(selected)) { - e.consume(); - getClient().getServer().moveDragon(selected); - } - } - } - - +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.util.Set; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.GridMouseListener; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class DragonAvailableMove extends AbstractGridLayer implements GridMouseListener { + + private Set positions; + private Position selected; + + public DragonAvailableMove(GridPanel gridPanel, Set positions) { + super(gridPanel); + this.positions = positions; + } + + public void paint(Graphics2D g2) { + Image dragon = getClient().getControlsTheme().getActionDecoration("dragon"); + for (Position pos : positions) { + g2.drawImage(dragon, getOffsetX(pos), getOffsetY(pos), getSquareSize(), getSquareSize(), null); + } + } + + @Override + public int getZIndex() { + return 60; + } + + @Override + public void squareEntered(MouseEvent e, Position p) { + selected = p; + } + + @Override + public void squareExited(MouseEvent e, Position p) { + selected = null; + + } + + @Override + public void mouseClicked(MouseEvent e, Position p) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (positions.contains(selected)) { + e.consume(); + getClient().getServer().moveDragon(selected); + } + } + } + + } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/DragonLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/DragonLayer.java index 0dae4a144..14401fe7c 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/DragonLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/DragonLayer.java @@ -1,54 +1,54 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Image; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class DragonLayer extends AbstractTileLayer { - - protected static final String DRAGON_IMAGE_NAME = "dragon"; - private static final ImmutablePoint POINT = new ImmutablePoint(45,50); - - private int moves; - private Image dragonImage; - - - - public DragonLayer(GridPanel gridPanel, Position position) { - super(gridPanel, position); - dragonImage = getClient().getFigureTheme().getNeutralImage(DRAGON_IMAGE_NAME); - } - - public void paint(Graphics2D g2) { - if (getPosition() != null) { - g2.drawImage(dragonImage, getOffsetX(), getOffsetY(), getSquareSize(), getSquareSize(), null); - if (moves > 0) { - //tohle asi nebude uplne uprostred - drawAntialiasedTextCentered(g2, moves + "", 22, POINT, Color.WHITE, null); - } - } - } - - @Override - public void zoomChanged(int squareSize) { - super.zoomChanged(squareSize); - } - - - @Override - public int getZIndex() { - return 90; - } - - public void setMoves(int moves) { - this.moves = moves; - - } - - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class DragonLayer extends AbstractTileLayer { + + protected static final String DRAGON_IMAGE_NAME = "dragon"; + private static final ImmutablePoint POINT = new ImmutablePoint(45,50); + + private int moves; + private Image dragonImage; + + + + public DragonLayer(GridPanel gridPanel, Position position) { + super(gridPanel, position); + dragonImage = getClient().getFigureTheme().getNeutralImage(DRAGON_IMAGE_NAME); + } + + public void paint(Graphics2D g2) { + if (getPosition() != null) { + g2.drawImage(dragonImage, getOffsetX(), getOffsetY(), getSquareSize(), getSquareSize(), null); + if (moves > 0) { + //tohle asi nebude uplne uprostred + drawAntialiasedTextCentered(g2, moves + "", 22, POINT, Color.WHITE, null); + } + } + } + + @Override + public void zoomChanged(int squareSize) { + super.zoomChanged(squareSize); + } + + + @Override + public int getZIndex() { + return 90; + } + + public void setMoves(int moves) { + this.moves = moves; + + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/FairyLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/FairyLayer.java index 0f605816c..15eb367b9 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/FairyLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/FairyLayer.java @@ -1,36 +1,36 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Graphics2D; -import java.awt.Image; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class FairyLayer extends AbstractTileLayer { - - protected static final String FAIRY_IMAGE_NAME = "fairy"; - - private Image fairyImage; - - public FairyLayer(GridPanel gridPanel, Position position) { - super(gridPanel, position); - fairyImage = getClient().getFigureTheme().getNeutralImage(FAIRY_IMAGE_NAME); - } - - - public void paint(Graphics2D g2) { - if (getPosition() != null) { - g2.drawImage(fairyImage, getOffsetX(), getOffsetY(), getSquareSize(), getSquareSize(), null); - } - } - - @Override - public int getZIndex() { - return 90; - } - - - - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Graphics2D; +import java.awt.Image; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class FairyLayer extends AbstractTileLayer { + + protected static final String FAIRY_IMAGE_NAME = "fairy"; + + private Image fairyImage; + + public FairyLayer(GridPanel gridPanel, Position position) { + super(gridPanel, position); + fairyImage = getClient().getFigureTheme().getNeutralImage(FAIRY_IMAGE_NAME); + } + + + public void paint(Graphics2D g2) { + if (getPosition() != null) { + g2.drawImage(fairyImage, getOffsetX(), getOffsetY(), getSquareSize(), getSquareSize(), null); + } + } + + @Override + public int getZIndex() { + return 90; + } + + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/FeatureAreaLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/FeatureAreaLayer.java index 6bd42c01d..a96f59af1 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/FeatureAreaLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/FeatureAreaLayer.java @@ -1,153 +1,153 @@ -package com.jcloisterzone.ui.grid.layer; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.geom.Area; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.swing.JOptionPane; - -import com.jcloisterzone.Player; -import com.jcloisterzone.PlayerRestriction; -import com.jcloisterzone.action.BridgeAction; -import com.jcloisterzone.action.MeepleAction; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.action.SelectFeatureAction; -import com.jcloisterzone.action.SelectFollowerAction; -import com.jcloisterzone.action.TowerPieceAction; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.game.capability.TowerCapability; -import com.jcloisterzone.ui.dialog.AmbiguousUndeployDialog; -import com.jcloisterzone.ui.dialog.AmbiguousUndeployDialog.AmbiguousUndeployDialogEvent; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class FeatureAreaLayer extends AbstractAreaLayer { - - private final SelectFeatureAction action; - - public FeatureAreaLayer(GridPanel gridPanel, SelectFeatureAction action) { - super(gridPanel); - this.action = action; - } - - protected Map prepareAreas(Tile tile, Position p) { - Set locations = action.getLocationsMap().get(p); - if (locations == null) return null; - if (action instanceof BridgeAction) { - return getClient().getResourceManager().getBridgeAreas(tile, getSquareSize(), locations); - } else { - return getClient().getResourceManager().getFeatureAreas(tile, getSquareSize(), locations); - } - } - - - private boolean confirmFarmPlacement() { - String options[] = {_("Place a follower"), _("Cancel") }; - int result = JOptionPane.showOptionDialog(getClient(), - _("Do you really want to place a follower on farm?"), - _("Confirm follower placement"), - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); - return JOptionPane.YES_OPTION == result; - } - - private boolean confirmTowerPlacement(Position pos) { - int result; - Player activePlayer = getClient().getGame().getActivePlayer(); - if (getClient().getGame().getCapability(TowerCapability.class).getTowerPieces(activePlayer) > 0) { - String options[] = { - _("Confirm follower placement"), - _("Cancel"), - _("Place a tower piece") - }; - result = JOptionPane.showOptionDialog(getClient(), - _("Do you really want to place a follower on the tower?\n(To prevent tower from adding more pieces on the top)"), - _("Confirm follower placement"), - JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); - } else { - String options[] = { - _("Confirm follower placement"), - _("Cancel") - }; - result = JOptionPane.showOptionDialog(getClient(), - _("Do you really want to place a follower on the tower?\n(To prevent tower from adding more pieces on the top)"), - _("Confirm follower placement"), - JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); - } - if (result == JOptionPane.CANCEL_OPTION) { - //place tower piece instead - for (PlayerAction action : getClient().getControlPanel().getActionPanel().getActions()) { - if (action instanceof TowerPieceAction) { - ((TowerPieceAction) action).perform(getClient().getServer(), pos); - gridPanel.removeLayer(this); - return false; - } - } - return false; - } - return result == JOptionPane.YES_OPTION; - } - - private List getDistinctFeatureMeeples(PlayerRestriction allowed, Feature feature) { - //little optimalization, almost all time size is 1 - if (feature.getMeeples().size() == 1) { - return feature.getMeeples(); - } - Set used = new HashSet<>(); - List result = new ArrayList<>(); - for (Meeple m : feature.getMeeples()) { - if (!allowed.isAllowed(m.getPlayer())) continue; - String key = m.getPlayer().getIndex() + m.getClass().getSimpleName(); - if (!used.contains(key)) { - result.add(m); - used.add(key); - } - } - return result; - } - - @Override - protected void performAction(final Position pos, final Location loc) { - if (action instanceof MeepleAction) { - MeepleAction ma = (MeepleAction) action; - Feature piece = gridPanel.getTile(pos).getFeature(loc); - if (piece instanceof Farm) { - if (Follower.class.isAssignableFrom(ma.getMeepleType()) && getClient().getSettings().isConfirmFarmPlacement()) { - if (!confirmFarmPlacement()) return; - } - } else if (piece instanceof Tower) { - if (getClient().getSettings().isConfirmTowerPlacement()) { - if (!confirmTowerPlacement(pos)) return; - } - } - } - if (action instanceof SelectFollowerAction) { - final SelectFollowerAction selectFollowerAction = (SelectFollowerAction) action; - List meeples = getDistinctFeatureMeeples(selectFollowerAction.getPlayers(), getGame().getBoard().get(pos).getFeature(loc)); - if (meeples.size() > 1) { - new AmbiguousUndeployDialog(getClient(), meeples, new AmbiguousUndeployDialogEvent() { - @Override - public void meepleTypeSelected(Meeple meeple) { - selectFollowerAction.perform(getClient().getServer(), pos, loc, meeple.getClass(), meeple.getPlayer()); - } - }); - return; - } - } - action.perform(getClient().getServer(), pos, loc); - return; - } - - -} +package com.jcloisterzone.ui.grid.layer; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.geom.Area; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.JOptionPane; + +import com.jcloisterzone.Player; +import com.jcloisterzone.PlayerRestriction; +import com.jcloisterzone.action.BridgeAction; +import com.jcloisterzone.action.MeepleAction; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.action.SelectFeatureAction; +import com.jcloisterzone.action.SelectFollowerAction; +import com.jcloisterzone.action.TowerPieceAction; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.game.capability.TowerCapability; +import com.jcloisterzone.ui.dialog.AmbiguousUndeployDialog; +import com.jcloisterzone.ui.dialog.AmbiguousUndeployDialog.AmbiguousUndeployDialogEvent; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class FeatureAreaLayer extends AbstractAreaLayer { + + private final SelectFeatureAction action; + + public FeatureAreaLayer(GridPanel gridPanel, SelectFeatureAction action) { + super(gridPanel); + this.action = action; + } + + protected Map prepareAreas(Tile tile, Position p) { + Set locations = action.getLocationsMap().get(p); + if (locations == null) return null; + if (action instanceof BridgeAction) { + return getClient().getResourceManager().getBridgeAreas(tile, getSquareSize(), locations); + } else { + return getClient().getResourceManager().getFeatureAreas(tile, getSquareSize(), locations); + } + } + + + private boolean confirmFarmPlacement() { + String options[] = {_("Place a follower"), _("Cancel") }; + int result = JOptionPane.showOptionDialog(getClient(), + _("Do you really want to place a follower on farm?"), + _("Confirm follower placement"), + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + return JOptionPane.YES_OPTION == result; + } + + private boolean confirmTowerPlacement(Position pos) { + int result; + Player activePlayer = getClient().getGame().getActivePlayer(); + if (getClient().getGame().getCapability(TowerCapability.class).getTowerPieces(activePlayer) > 0) { + String options[] = { + _("Confirm follower placement"), + _("Cancel"), + _("Place a tower piece") + }; + result = JOptionPane.showOptionDialog(getClient(), + _("Do you really want to place a follower on the tower?\n(To prevent tower from adding more pieces on the top)"), + _("Confirm follower placement"), + JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + } else { + String options[] = { + _("Confirm follower placement"), + _("Cancel") + }; + result = JOptionPane.showOptionDialog(getClient(), + _("Do you really want to place a follower on the tower?\n(To prevent tower from adding more pieces on the top)"), + _("Confirm follower placement"), + JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); + } + if (result == JOptionPane.CANCEL_OPTION) { + //place tower piece instead + for (PlayerAction action : getClient().getControlPanel().getActionPanel().getActions()) { + if (action instanceof TowerPieceAction) { + ((TowerPieceAction) action).perform(getClient().getServer(), pos); + gridPanel.removeLayer(this); + return false; + } + } + return false; + } + return result == JOptionPane.YES_OPTION; + } + + private List getDistinctFeatureMeeples(PlayerRestriction allowed, Feature feature) { + //little optimalization, almost all time size is 1 + if (feature.getMeeples().size() == 1) { + return feature.getMeeples(); + } + Set used = new HashSet<>(); + List result = new ArrayList<>(); + for (Meeple m : feature.getMeeples()) { + if (!allowed.isAllowed(m.getPlayer())) continue; + String key = m.getPlayer().getIndex() + m.getClass().getSimpleName(); + if (!used.contains(key)) { + result.add(m); + used.add(key); + } + } + return result; + } + + @Override + protected void performAction(final Position pos, final Location loc) { + if (action instanceof MeepleAction) { + MeepleAction ma = (MeepleAction) action; + Feature piece = gridPanel.getTile(pos).getFeature(loc); + if (piece instanceof Farm) { + if (Follower.class.isAssignableFrom(ma.getMeepleType()) && getClient().getSettings().isConfirmFarmPlacement()) { + if (!confirmFarmPlacement()) return; + } + } else if (piece instanceof Tower) { + if (getClient().getSettings().isConfirmTowerPlacement()) { + if (!confirmTowerPlacement(pos)) return; + } + } + } + if (action instanceof SelectFollowerAction) { + final SelectFollowerAction selectFollowerAction = (SelectFollowerAction) action; + List meeples = getDistinctFeatureMeeples(selectFollowerAction.getPlayers(), getGame().getBoard().get(pos).getFeature(loc)); + if (meeples.size() > 1) { + new AmbiguousUndeployDialog(getClient(), meeples, new AmbiguousUndeployDialogEvent() { + @Override + public void meepleTypeSelected(Meeple meeple) { + selectFollowerAction.perform(getClient().getServer(), pos, loc, meeple.getClass(), meeple.getPlayer()); + } + }); + return; + } + } + action.perform(getClient().getServer(), pos, loc); + return; + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/MeepleLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/MeepleLayer.java index 2d3d981e4..77678f834 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/MeepleLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/MeepleLayer.java @@ -1,162 +1,162 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Image; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; - -import javax.swing.ImageIcon; - -import com.google.common.collect.Maps; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.figure.BigFollower; -import com.jcloisterzone.figure.Follower; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.figure.SmallFollower; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridPanel; - -public class MeepleLayer extends AbstractGridLayer { - - public static final double FIGURE_SIZE_RATIO = 0.35; - - /** - * Corn circles allows multiple meeples on single feature. - * In such case double meeple should be displayed after common ones. - */ - private LinkedHashMap images = Maps.newLinkedHashMap(); - //TODO own layer ??? - private List permanentImages = new ArrayList<>(); - - public MeepleLayer(GridPanel gridPanel) { - super(gridPanel); - } - - @Override - public int getZIndex() { - return 50; - } - - private void paintPositionedImage(Graphics2D g, PositionedImage mi, int boxSize) { - ImmutablePoint scaledOffset = mi.offset.scale(getSquareSize(), boxSize); - //TODO optimize also for scrolling - if (mi.scaledImage == null) { - int size = (int) (getSquareSize() * FIGURE_SIZE_RATIO); - Image img = mi.sourceImage.getScaledInstance(size, size, Image.SCALE_SMOOTH); - mi.scaledImage = new ImageIcon(img).getImage(); - } - g.drawImage(mi.scaledImage, getOffsetX(mi.position) + scaledOffset.getX(), getOffsetY(mi.position) + scaledOffset.getY(), gridPanel); - } - - @Override - public void paint(Graphics2D g) { - int boxSize = (int) (getSquareSize() * FIGURE_SIZE_RATIO); //TODO no resize - direct image resize??? - for (PositionedImage mi : images.values()) { - paintPositionedImage(g, mi, boxSize ); - } - for (PositionedImage mi : permanentImages) { - paintPositionedImage(g, mi, boxSize ); - } - - } - - @Override - public void zoomChanged(int squareSize) { - for (PositionedImage mi : images.values()) { - mi.scaledImage = null; - } - for (PositionedImage mi : permanentImages) { - mi.scaledImage = null; - } - super.zoomChanged(squareSize); - } - - private PositionedImage createMeepleImage(Meeple m, int order) { - Feature feature = m.getFeature(); - ImmutablePoint offset = getClient().getResourceManager().getMeeplePlacement(feature.getTile(), m.getClass(), m.getLocation()); - if (order > 0) { - offset = new ImmutablePoint(offset.getX() + 10*order, offset.getY()); - } - Color c = getClient().getPlayerColor(m.getPlayer()); - Image image = getClient().getFigureTheme().getFigureImage(m.getClass(), c, getExtraDecoration(m)); - return new PositionedImage(m.getPosition(), offset, image); - } - - /** - * recompute offset, keep big follower on top - */ - private void rearrangeMeeples(final Feature feature) { - for (Meeple m : feature.getMeeples()) { - images.remove(m); - } - - int i = 0; - //clone meeples to freeze its state - for (Meeple m : feature.getMeeples()) { - if (m instanceof SmallFollower) { - Meeple c = (Meeple) m.clone(); - if (c.getPosition() == null) continue; //synchronization issue, because reading directly from Feature, not from args passed to ui layer - images.put(c, createMeepleImage(c, i++)); - } - - } - for (Meeple m : feature.getMeeples()) { - if (!(m instanceof SmallFollower)) { - Meeple c = (Meeple) m.clone(); - if (c.getPosition() == null) continue; //synchronization issue, because reading directly from Feature, not from args passed to ui layer - images.put(c, createMeepleImage(c, i++)); - } - } - } - - public void meepleDeployed(Meeple m) { - assert !images.containsKey(m); - rearrangeMeeples(m.getFeature()); - } - - public void meepleUndeployed(Meeple m) { - if (m.getFeature() != null) { - images.remove(m); - rearrangeMeeples(m.getFeature()); - } - } - - public void addPermanentImage(Position position, ImmutablePoint offset, Image image) { - permanentImages.add(new PositionedImage(position, offset, image)); - } - - - //TODO path from Theme - public String getExtraDecoration(Meeple m) { - if (m instanceof Follower && m.getFeature() instanceof Farm) { - return "farm.png"; - } - if (m.getFeature() instanceof Tower) { - if (m instanceof BigFollower) { - return "big_tower.png"; - } else { - return "tower.png"; - } - } - return null; - } - - private static class PositionedImage { - public final Position position; - public final ImmutablePoint offset; - public final Image sourceImage; - public Image scaledImage; - - - public PositionedImage(Position position, ImmutablePoint offset, Image sourceImage) { - this.position = position; - this.offset = offset; - this.sourceImage = sourceImage; - } - } +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +import javax.swing.ImageIcon; + +import com.google.common.collect.Maps; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.figure.BigFollower; +import com.jcloisterzone.figure.Follower; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.figure.SmallFollower; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridPanel; + +public class MeepleLayer extends AbstractGridLayer { + + public static final double FIGURE_SIZE_RATIO = 0.35; + + /** + * Corn circles allows multiple meeples on single feature. + * In such case double meeple should be displayed after common ones. + */ + private LinkedHashMap images = Maps.newLinkedHashMap(); + //TODO own layer ??? + private List permanentImages = new ArrayList<>(); + + public MeepleLayer(GridPanel gridPanel) { + super(gridPanel); + } + + @Override + public int getZIndex() { + return 50; + } + + private void paintPositionedImage(Graphics2D g, PositionedImage mi, int boxSize) { + ImmutablePoint scaledOffset = mi.offset.scale(getSquareSize(), boxSize); + //TODO optimize also for scrolling + if (mi.scaledImage == null) { + int size = (int) (getSquareSize() * FIGURE_SIZE_RATIO); + Image img = mi.sourceImage.getScaledInstance(size, size, Image.SCALE_SMOOTH); + mi.scaledImage = new ImageIcon(img).getImage(); + } + g.drawImage(mi.scaledImage, getOffsetX(mi.position) + scaledOffset.getX(), getOffsetY(mi.position) + scaledOffset.getY(), gridPanel); + } + + @Override + public void paint(Graphics2D g) { + int boxSize = (int) (getSquareSize() * FIGURE_SIZE_RATIO); //TODO no resize - direct image resize??? + for (PositionedImage mi : images.values()) { + paintPositionedImage(g, mi, boxSize ); + } + for (PositionedImage mi : permanentImages) { + paintPositionedImage(g, mi, boxSize ); + } + + } + + @Override + public void zoomChanged(int squareSize) { + for (PositionedImage mi : images.values()) { + mi.scaledImage = null; + } + for (PositionedImage mi : permanentImages) { + mi.scaledImage = null; + } + super.zoomChanged(squareSize); + } + + private PositionedImage createMeepleImage(Meeple m, int order) { + Feature feature = m.getFeature(); + ImmutablePoint offset = getClient().getResourceManager().getMeeplePlacement(feature.getTile(), m.getClass(), m.getLocation()); + if (order > 0) { + offset = new ImmutablePoint(offset.getX() + 10*order, offset.getY()); + } + Color c = getClient().getPlayerColor(m.getPlayer()); + Image image = getClient().getFigureTheme().getFigureImage(m.getClass(), c, getExtraDecoration(m)); + return new PositionedImage(m.getPosition(), offset, image); + } + + /** + * recompute offset, keep big follower on top + */ + private void rearrangeMeeples(final Feature feature) { + for (Meeple m : feature.getMeeples()) { + images.remove(m); + } + + int i = 0; + //clone meeples to freeze its state + for (Meeple m : feature.getMeeples()) { + if (m instanceof SmallFollower) { + Meeple c = (Meeple) m.clone(); + if (c.getPosition() == null) continue; //synchronization issue, because reading directly from Feature, not from args passed to ui layer + images.put(c, createMeepleImage(c, i++)); + } + + } + for (Meeple m : feature.getMeeples()) { + if (!(m instanceof SmallFollower)) { + Meeple c = (Meeple) m.clone(); + if (c.getPosition() == null) continue; //synchronization issue, because reading directly from Feature, not from args passed to ui layer + images.put(c, createMeepleImage(c, i++)); + } + } + } + + public void meepleDeployed(Meeple m) { + assert !images.containsKey(m); + rearrangeMeeples(m.getFeature()); + } + + public void meepleUndeployed(Meeple m) { + if (m.getFeature() != null) { + images.remove(m); + rearrangeMeeples(m.getFeature()); + } + } + + public void addPermanentImage(Position position, ImmutablePoint offset, Image image) { + permanentImages.add(new PositionedImage(position, offset, image)); + } + + + //TODO path from Theme + public String getExtraDecoration(Meeple m) { + if (m instanceof Follower && m.getFeature() instanceof Farm) { + return "farm.png"; + } + if (m.getFeature() instanceof Tower) { + if (m instanceof BigFollower) { + return "big_tower.png"; + } else { + return "tower.png"; + } + } + return null; + } + + private static class PositionedImage { + public final Position position; + public final ImmutablePoint offset; + public final Image sourceImage; + public Image scaledImage; + + + public PositionedImage(Position position, ImmutablePoint offset, Image sourceImage) { + this.position = position; + this.offset = offset; + this.sourceImage = sourceImage; + } + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/PlacementHistory.java b/src/main/java/com/jcloisterzone/ui/grid/layer/PlacementHistory.java index dc02cca5c..b75266dea 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/PlacementHistory.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/PlacementHistory.java @@ -1,48 +1,48 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridPanel; - -public class PlacementHistory extends AbstractGridLayer { - - private static final Color COLOR = new Color(0,0,0,128); - private static final ImmutablePoint POINT = new ImmutablePoint(50,50); - - private Map history = new HashMap<>(); - - public PlacementHistory(GridPanel gridPanel, Collection placedTiles) { - super(gridPanel); - int i = placedTiles.size(); - int limit = getClient().getGame().getAllPlayers().length; - for (Tile t : placedTiles) { - if (i <= limit) { - history.put(t.getPosition(), "" + i); - } - i--; - } - } - - - @Override - public void paint(Graphics2D g) { - for (Entry entry : history.entrySet()) { - drawAntialiasedTextCentered(g, entry.getValue(), 80, entry.getKey(), POINT, COLOR, null); - } - - } - - @Override - public int getZIndex() { - return 1001; - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridPanel; + +public class PlacementHistory extends AbstractGridLayer { + + private static final Color COLOR = new Color(0,0,0,128); + private static final ImmutablePoint POINT = new ImmutablePoint(50,50); + + private Map history = new HashMap<>(); + + public PlacementHistory(GridPanel gridPanel, Collection placedTiles) { + super(gridPanel); + int i = placedTiles.size(); + int limit = getClient().getGame().getAllPlayers().length; + for (Tile t : placedTiles) { + if (i <= limit) { + history.put(t.getPosition(), "" + i); + } + i--; + } + } + + + @Override + public void paint(Graphics2D g) { + for (Entry entry : history.entrySet()) { + drawAntialiasedTextCentered(g, entry.getValue(), 80, entry.getKey(), POINT, COLOR, null); + } + + } + + @Override + public int getZIndex() { + return 1001; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/PlagueLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/PlagueLayer.java index 55f147817..2d790d888 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/PlagueLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/PlagueLayer.java @@ -1,47 +1,47 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; - -import com.jcloisterzone.game.capability.PlagueCapability; -import com.jcloisterzone.game.capability.PlagueCapability.PlagueSource; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridPanel; - -public class PlagueLayer extends AbstractGridLayer { - - private static final Color ACTIVE_PLAGUE = new Color(235, 57, 43); - private static final Color ERADICTED_PLAGUE = new Color(141, 178, 145); - - private final PlagueCapability plague; - - public PlagueLayer(GridPanel gridPanel) { - super(gridPanel); - plague = getGame().getCapability(PlagueCapability.class); - } - - @Override - public void paint(Graphics2D g2) { - int sqSize = getSquareSize(); - int boxSize = (int)(sqSize*0.4); - int i = 0; - for (PlagueSource source: plague.getPlagueSources()) { - i++; - - g2.setColor(source.active ? ACTIVE_PLAGUE : ERADICTED_PLAGUE); - int x = sqSize-boxSize-sqSize/10; - int y = sqSize/10; - g2.fillRect(getOffsetX(source.pos)+x, getOffsetY(source.pos)+y, boxSize, boxSize); - if (source.active) { - ImmutablePoint center = new ImmutablePoint(x+boxSize/2, y+boxSize/2); - drawAntialiasedTextCenteredNoScale(g2, i+"", 26, source.pos, center, Color.WHITE, null); - } - } - } - - @Override - public int getZIndex() { - return 45; - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; + +import com.jcloisterzone.game.capability.PlagueCapability; +import com.jcloisterzone.game.capability.PlagueCapability.PlagueSource; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridPanel; + +public class PlagueLayer extends AbstractGridLayer { + + private static final Color ACTIVE_PLAGUE = new Color(235, 57, 43); + private static final Color ERADICTED_PLAGUE = new Color(141, 178, 145); + + private final PlagueCapability plague; + + public PlagueLayer(GridPanel gridPanel) { + super(gridPanel); + plague = getGame().getCapability(PlagueCapability.class); + } + + @Override + public void paint(Graphics2D g2) { + int sqSize = getSquareSize(); + int boxSize = (int)(sqSize*0.4); + int i = 0; + for (PlagueSource source: plague.getPlagueSources()) { + i++; + + g2.setColor(source.active ? ACTIVE_PLAGUE : ERADICTED_PLAGUE); + int x = sqSize-boxSize-sqSize/10; + int y = sqSize/10; + g2.fillRect(getOffsetX(source.pos)+x, getOffsetY(source.pos)+y, boxSize, boxSize); + if (source.active) { + ImmutablePoint center = new ImmutablePoint(x+boxSize/2, y+boxSize/2); + drawAntialiasedTextCenteredNoScale(g2, i+"", 26, source.pos, center, Color.WHITE, null); + } + } + } + + @Override + public int getZIndex() { + return 45; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/TileActionLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/TileActionLayer.java index f4d2e5be9..04bb6687d 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/TileActionLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/TileActionLayer.java @@ -1,54 +1,54 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.MouseEvent; - -import com.jcloisterzone.action.SelectTileAction; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.grid.GridMouseListener; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class TileActionLayer extends AbstractGridLayer implements GridMouseListener { - - private final SelectTileAction action; - private final Image gridDecoration; - - public TileActionLayer(GridPanel gridPanel, SelectTileAction action, Image gridDecoration) { - super(gridPanel); - this.action = action; - this.gridDecoration = gridDecoration; - } - - @Override - public int getZIndex() { - return 70; - } - - public void paint(Graphics2D g2) { - int imgSize = gridDecoration.getWidth(null); - for (Position pos : action.getSites()) { - g2.drawImage(gridDecoration, getAffineTransform(imgSize, pos), null); - } - } - - @Override - public void mouseClicked(MouseEvent e, Position p) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (action.getSites().contains(p)) { - e.consume(); - action.perform(getClient().getServer(), p); - } - } - } - - - @Override - public void squareEntered(MouseEvent e, Position p) { } - @Override - public void squareExited(MouseEvent e, Position p) { } - - - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.event.MouseEvent; + +import com.jcloisterzone.action.SelectTileAction; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.grid.GridMouseListener; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class TileActionLayer extends AbstractGridLayer implements GridMouseListener { + + private final SelectTileAction action; + private final Image gridDecoration; + + public TileActionLayer(GridPanel gridPanel, SelectTileAction action, Image gridDecoration) { + super(gridPanel); + this.action = action; + this.gridDecoration = gridDecoration; + } + + @Override + public int getZIndex() { + return 70; + } + + public void paint(Graphics2D g2) { + int imgSize = gridDecoration.getWidth(null); + for (Position pos : action.getSites()) { + g2.drawImage(gridDecoration, getAffineTransform(imgSize, pos), null); + } + } + + @Override + public void mouseClicked(MouseEvent e, Position p) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (action.getSites().contains(p)) { + e.consume(); + action.perform(getClient().getServer(), p); + } + } + } + + + @Override + public void squareEntered(MouseEvent e, Position p) { } + @Override + public void squareExited(MouseEvent e, Position p) { } + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/TileLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/TileLayer.java index 34d89cc88..25a57ab39 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/TileLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/TileLayer.java @@ -1,54 +1,54 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Image; -import java.util.ArrayList; -import java.util.List; - -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.ui.grid.GridPanel; - -public class TileLayer extends AbstractGridLayer { - - //keep own copy of tiles in Swing thread to prevent concurent modification ex. of tile list on game - private List placedTiles = new ArrayList<>(); - - - public TileLayer(GridPanel gridPanel) { - super(gridPanel); - } - - @Override - public void paint(Graphics2D g2) { - //TODO nice shadow - if (!getClient().getGridPanel().containsDecoration(AbstractTilePlacementLayer.class)) { - g2.setColor(Color.WHITE); - int squareSize = getSquareSize(), - thickness = squareSize / 11; - for (Tile tile : placedTiles) { - Position p = tile.getPosition(); - int x = getOffsetX(p), y = getOffsetY(p); - g2.fillRect(x-thickness, y-thickness, squareSize+2*thickness, squareSize+2*thickness); - } - } - - for (Tile tile : placedTiles) { - Image img = getClient().getResourceManager().getTileImage(tile); - g2.drawImage(img, getAffineTransform(img.getWidth(null), tile.getPosition(), tile.getRotation()), null); - } - } - - @Override - public int getZIndex() { - return 2; - } - - public void tilePlaced(Tile tile) { - placedTiles.add(tile); - } - - - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; + +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.ui.grid.GridPanel; + +public class TileLayer extends AbstractGridLayer { + + //keep own copy of tiles in Swing thread to prevent concurent modification ex. of tile list on game + private List placedTiles = new ArrayList<>(); + + + public TileLayer(GridPanel gridPanel) { + super(gridPanel); + } + + @Override + public void paint(Graphics2D g2) { + //TODO nice shadow + if (!getClient().getGridPanel().containsDecoration(AbstractTilePlacementLayer.class)) { + g2.setColor(Color.WHITE); + int squareSize = getSquareSize(), + thickness = squareSize / 11; + for (Tile tile : placedTiles) { + Position p = tile.getPosition(); + int x = getOffsetX(p), y = getOffsetY(p); + g2.fillRect(x-thickness, y-thickness, squareSize+2*thickness, squareSize+2*thickness); + } + } + + for (Tile tile : placedTiles) { + Image img = getClient().getResourceManager().getTileImage(tile); + g2.drawImage(img, getAffineTransform(img.getWidth(null), tile.getPosition(), tile.getRotation()), null); + } + } + + @Override + public int getZIndex() { + return 2; + } + + public void tilePlaced(Tile tile) { + placedTiles.add(tile); + } + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/TilePlacementLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/TilePlacementLayer.java index 78a860130..14710c652 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/TilePlacementLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/TilePlacementLayer.java @@ -1,86 +1,86 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Composite; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.event.MouseEvent; -import java.util.Set; - -import com.jcloisterzone.action.TilePlacementAction; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.TileSymmetry; -import com.jcloisterzone.ui.grid.GridPanel; - -public class TilePlacementLayer extends AbstractTilePlacementLayer { - - private TilePlacementAction action; - - private Rotation realRotation; - private Rotation previewRotation; - private boolean allowedRotation; - - public TilePlacementLayer(GridPanel gridPanel, TilePlacementAction action) { - super(gridPanel, action.getAvailablePlacements().keySet()); - this.action = action; - } - - @Override - protected Image createPreviewIcon() { - return getClient().getResourceManager().getTileImage(action.getTile()); - } - - @Override - protected void drawPreviewIcon(Graphics2D g2, Image previewIcon, Position previewPosition) { - if (realRotation != action.getTileRotation()) { - preparePreviewRotation(previewPosition); - } - Composite compositeBackup = g2.getComposite(); - g2.setComposite(allowedRotation ? ALLOWED_PREVIEW : DISALLOWED_PREVIEW); - g2.drawImage(previewIcon, getAffineTransform(previewIcon.getWidth(null), previewPosition, previewRotation), null); - g2.setComposite(compositeBackup); - } - - private void preparePreviewRotation(Position p) { - realRotation = action.getTileRotation(); - previewRotation = realRotation; - - Set allowedRotations = action.getAvailablePlacements().get(p); - if (allowedRotations.contains(previewRotation)) { - allowedRotation = true; - } else { - if (allowedRotations.size() == 1) { - previewRotation = allowedRotations.iterator().next(); - allowedRotation = true; - } else if (action.getTile().getSymmetry() == TileSymmetry.S2) { - previewRotation = realRotation.next(); - allowedRotation = true; - } else { - allowedRotation = false; - } - } - } - - @Override - public void squareEntered(MouseEvent e, Position p) { - realRotation = null; - super.squareEntered(e, p); - } - - @Override - public void squareExited(MouseEvent e, Position p) { - realRotation = null; - super.squareExited(e, p); - } - - @Override - public void mouseClicked(MouseEvent e, Position p) { - if (e.getButton() == MouseEvent.BUTTON1) { - if (getPreviewPosition() != null && getClient().isClientActive() && allowedRotation) { - e.consume(); - action.perform(getClient().getServer(), previewRotation, p); - } - } - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Composite; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.util.Set; + +import com.jcloisterzone.action.TilePlacementAction; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.TileSymmetry; +import com.jcloisterzone.ui.grid.GridPanel; + +public class TilePlacementLayer extends AbstractTilePlacementLayer { + + private TilePlacementAction action; + + private Rotation realRotation; + private Rotation previewRotation; + private boolean allowedRotation; + + public TilePlacementLayer(GridPanel gridPanel, TilePlacementAction action) { + super(gridPanel, action.getAvailablePlacements().keySet()); + this.action = action; + } + + @Override + protected Image createPreviewIcon() { + return getClient().getResourceManager().getTileImage(action.getTile()); + } + + @Override + protected void drawPreviewIcon(Graphics2D g2, Image previewIcon, Position previewPosition) { + if (realRotation != action.getTileRotation()) { + preparePreviewRotation(previewPosition); + } + Composite compositeBackup = g2.getComposite(); + g2.setComposite(allowedRotation ? ALLOWED_PREVIEW : DISALLOWED_PREVIEW); + g2.drawImage(previewIcon, getAffineTransform(previewIcon.getWidth(null), previewPosition, previewRotation), null); + g2.setComposite(compositeBackup); + } + + private void preparePreviewRotation(Position p) { + realRotation = action.getTileRotation(); + previewRotation = realRotation; + + Set allowedRotations = action.getAvailablePlacements().get(p); + if (allowedRotations.contains(previewRotation)) { + allowedRotation = true; + } else { + if (allowedRotations.size() == 1) { + previewRotation = allowedRotations.iterator().next(); + allowedRotation = true; + } else if (action.getTile().getSymmetry() == TileSymmetry.S2) { + previewRotation = realRotation.next(); + allowedRotation = true; + } else { + allowedRotation = false; + } + } + } + + @Override + public void squareEntered(MouseEvent e, Position p) { + realRotation = null; + super.squareEntered(e, p); + } + + @Override + public void squareExited(MouseEvent e, Position p) { + realRotation = null; + super.squareExited(e, p); + } + + @Override + public void mouseClicked(MouseEvent e, Position p) { + if (e.getButton() == MouseEvent.BUTTON1) { + if (getPreviewPosition() != null && getClient().isClientActive() && allowedRotation) { + e.consume(); + action.perform(getClient().getServer(), previewRotation, p); + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/grid/layer/TowerLayer.java b/src/main/java/com/jcloisterzone/ui/grid/layer/TowerLayer.java index 2f894ac45..341461306 100644 --- a/src/main/java/com/jcloisterzone/ui/grid/layer/TowerLayer.java +++ b/src/main/java/com/jcloisterzone/ui/grid/layer/TowerLayer.java @@ -1,46 +1,46 @@ -package com.jcloisterzone.ui.grid.layer; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.Area; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.grid.GridPanel; - - -public class TowerLayer extends AbstractGridLayer { - - private final static Color FILL_COLOR = new Color(40,40,40,150); - - private Map heights = new HashMap<>(); - - public TowerLayer(GridPanel gridPanel) { - super(gridPanel); - } - - @Override - public void paint(Graphics2D g2) { - g2.setColor(FILL_COLOR); - for (Entry entry : heights.entrySet()) { - Area ra = getClient().getResourceManager().getMeepleTileArea(gridPanel.getTile(entry.getKey()), getSquareSize(), Location.TOWER); - g2.fill(transformArea(ra, entry.getKey())); - drawAntialiasedTextCenteredNoScale(g2,"" + entry.getValue(), 22, entry.getKey(), - new ImmutablePoint((int)ra.getBounds2D().getCenterX(),(int)ra.getBounds2D().getCenterY()), Color.WHITE, null); - } - } - - @Override - public int getZIndex() { - return 5; - } - - public void setTowerHeight(Position p, int towerHeight) { - heights.put(p, towerHeight); - } - -} +package com.jcloisterzone.ui.grid.layer; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Area; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.grid.GridPanel; + + +public class TowerLayer extends AbstractGridLayer { + + private final static Color FILL_COLOR = new Color(40,40,40,150); + + private Map heights = new HashMap<>(); + + public TowerLayer(GridPanel gridPanel) { + super(gridPanel); + } + + @Override + public void paint(Graphics2D g2) { + g2.setColor(FILL_COLOR); + for (Entry entry : heights.entrySet()) { + Area ra = getClient().getResourceManager().getMeepleTileArea(gridPanel.getTile(entry.getKey()), getSquareSize(), Location.TOWER); + g2.fill(transformArea(ra, entry.getKey())); + drawAntialiasedTextCenteredNoScale(g2,"" + entry.getValue(), 22, entry.getKey(), + new ImmutablePoint((int)ra.getBounds2D().getCenterX(),(int)ra.getBounds2D().getCenterY()), Color.WHITE, null); + } + } + + @Override + public int getZIndex() { + return 5; + } + + public void setTowerHeight(Position p, int towerHeight) { + heights.put(p, towerHeight); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/legacy/FigureImageFilter.java b/src/main/java/com/jcloisterzone/ui/legacy/FigureImageFilter.java index 18f8b0330..7b74b6535 100644 --- a/src/main/java/com/jcloisterzone/ui/legacy/FigureImageFilter.java +++ b/src/main/java/com/jcloisterzone/ui/legacy/FigureImageFilter.java @@ -1,38 +1,38 @@ -package com.jcloisterzone.ui.legacy; - -import java.awt.Color; -import java.awt.image.RGBImageFilter; - -import com.jcloisterzone.ui.UiUtils; - - -/** - * Filter to change figure color. - * @author Roman Krejcik - */ -public class FigureImageFilter extends RGBImageFilter { - private Color c; - private boolean white2black = false; - - /** - * Initializes a new instance for colorize figure to given color - * @param c demand color of figure - */ - public FigureImageFilter(Color c) { - // The filter's operation does not depend on the - // pixel's location, so IndexColorModels can be - // filtered directly. - canFilterIndexColorModel = true; - this.c = c; - white2black = UiUtils.isBrightColor(c); - } - - public int filterRGB(int x, int y, int rgb) { - if (rgb == Color.MAGENTA.getRGB()) - return c.getRGB(); - if (white2black && rgb == Color.WHITE.getRGB()) - return Color.BLACK.getRGB(); - - return rgb; - } +package com.jcloisterzone.ui.legacy; + +import java.awt.Color; +import java.awt.image.RGBImageFilter; + +import com.jcloisterzone.ui.UiUtils; + + +/** + * Filter to change figure color. + * @author Roman Krejcik + */ +public class FigureImageFilter extends RGBImageFilter { + private Color c; + private boolean white2black = false; + + /** + * Initializes a new instance for colorize figure to given color + * @param c demand color of figure + */ + public FigureImageFilter(Color c) { + // The filter's operation does not depend on the + // pixel's location, so IndexColorModels can be + // filtered directly. + canFilterIndexColorModel = true; + this.c = c; + white2black = UiUtils.isBrightColor(c); + } + + public int filterRGB(int x, int y, int rgb) { + if (rgb == Color.MAGENTA.getRGB()) + return c.getRGB(); + if (white2black && rgb == Color.WHITE.getRGB()) + return Color.BLACK.getRGB(); + + return rgb; + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/panel/BackgroundPanel.java b/src/main/java/com/jcloisterzone/ui/panel/BackgroundPanel.java index d222f65e0..97e7b40a5 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/BackgroundPanel.java +++ b/src/main/java/com/jcloisterzone/ui/panel/BackgroundPanel.java @@ -1,40 +1,40 @@ -package com.jcloisterzone.ui.panel; - -import java.awt.Graphics; -import java.awt.Image; -import java.awt.LayoutManager; - -import javax.swing.ImageIcon; -import javax.swing.JPanel; - -public class BackgroundPanel extends JPanel { - - - static private int W = 396; - static private int H = 396; - static private Image bg = new ImageIcon(BackgroundPanel.class.getClassLoader().getResource("sysimages/panel_bg.png")).getImage(); - - public BackgroundPanel() { - super(); - } - - public BackgroundPanel(LayoutManager layout) { - super(layout); - } - - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - int x = 0; - int y = 0; - while(y < getHeight()) { - x = 0; - while(x < getWidth()) { - g.drawImage(bg, x, y, W, H, this); - x += W; - } - y += H; - } - } - -} +package com.jcloisterzone.ui.panel; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.LayoutManager; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +public class BackgroundPanel extends JPanel { + + + static private int W = 396; + static private int H = 396; + static private Image bg = new ImageIcon(BackgroundPanel.class.getClassLoader().getResource("sysimages/panel_bg.png")).getImage(); + + public BackgroundPanel() { + super(); + } + + public BackgroundPanel(LayoutManager layout) { + super(layout); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + int x = 0; + int y = 0; + while(y < getHeight()) { + x = 0; + while(x < getWidth()) { + g.drawImage(bg, x, y, W, H, this); + x += W; + } + y += H; + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/panel/ConnectGamePanel.java b/src/main/java/com/jcloisterzone/ui/panel/ConnectGamePanel.java index 78d0c5f9f..ca1f94551 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/ConnectGamePanel.java +++ b/src/main/java/com/jcloisterzone/ui/panel/ConnectGamePanel.java @@ -1,101 +1,101 @@ -package com.jcloisterzone.ui.panel; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.UnknownHostException; - -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.border.TitledBorder; - -import net.miginfocom.swing.MigLayout; - -import org.apache.mina.core.RuntimeIoException; - -import com.jcloisterzone.ui.Client; - - -public class ConnectGamePanel extends JPanel { - - private final Client client; - - private JTextField hostField; - private JTextField portField; - private JButton btnConnect; - private JLabel message; - - /** - * Create the panel. - */ - public ConnectGamePanel(Client client) { - setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); - this.client = client; - setLayout(new MigLayout("", "[80.00][grow]", "[][][][][]")); - - JLabel helpLabel = new JLabel("Enter remote host address."); - add(helpLabel, "cell 0 0 2 1"); - - JLabel hostLabel = new JLabel(_("Host")); - add(hostLabel, "cell 0 1,alignx left,aligny top, gaptop 10"); - - hostField = new JTextField(); - add(hostField, "cell 1 1,growx, width 250::"); - hostField.setColumns(10); - - JLabel portLabel = new JLabel(_("Port")); - add(portLabel, "cell 0 2,alignx left, gaptop 5"); - - portField = new JTextField(); - add(portField, "cell 1 2,growx, width 250::"); - portField.setColumns(10); - portField.setText(client.getConfig().get("server", "port", int.class) + ""); - - btnConnect = new JButton(_("Connect")); - btnConnect.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - btnConnect.setEnabled(false); //TODO change to Interrupt button - message.setForeground(Color.BLACK); - message.setText(_("Connecting") + "..."); - (new AsyncConnect()).start(); - } - }); - add(btnConnect, "cell 1 3"); - - message = new JLabel(""); - message.setForeground(Color.BLACK); - add(message, "cell 1 4, height 20"); - } - - class AsyncConnect extends Thread { - @Override - public void run() { - try { - String hostname = hostField.getText().trim(); - InetAddress addr = InetAddress.getByName(hostname); - int port = Integer.parseInt(portField.getText()); - client.connect(addr, port); - return; - } catch (NumberFormatException nfe) { - message.setText( _("Invalid port number.")); - } catch (UnknownHostException e1) { - message.setText( _("Connection failed. Unknown host.")); - } catch (RuntimeIoException ex) { - if (ex.getCause() instanceof ConnectException) { - message.setText( _("Connection refused.")); - } else { - message.setText( _("Connection failed.")); - } - } - message.setForeground(Color.RED); - btnConnect.setEnabled(true); - } - } - -} +package com.jcloisterzone.ui.panel; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.net.ConnectException; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; + +import net.miginfocom.swing.MigLayout; + +import org.apache.mina.core.RuntimeIoException; + +import com.jcloisterzone.ui.Client; + + +public class ConnectGamePanel extends JPanel { + + private final Client client; + + private JTextField hostField; + private JTextField portField; + private JButton btnConnect; + private JLabel message; + + /** + * Create the panel. + */ + public ConnectGamePanel(Client client) { + setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); + this.client = client; + setLayout(new MigLayout("", "[80.00][grow]", "[][][][][]")); + + JLabel helpLabel = new JLabel("Enter remote host address."); + add(helpLabel, "cell 0 0 2 1"); + + JLabel hostLabel = new JLabel(_("Host")); + add(hostLabel, "cell 0 1,alignx left,aligny top, gaptop 10"); + + hostField = new JTextField(); + add(hostField, "cell 1 1,growx, width 250::"); + hostField.setColumns(10); + + JLabel portLabel = new JLabel(_("Port")); + add(portLabel, "cell 0 2,alignx left, gaptop 5"); + + portField = new JTextField(); + add(portField, "cell 1 2,growx, width 250::"); + portField.setColumns(10); + portField.setText(client.getConfig().get("server", "port", int.class) + ""); + + btnConnect = new JButton(_("Connect")); + btnConnect.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + btnConnect.setEnabled(false); //TODO change to Interrupt button + message.setForeground(Color.BLACK); + message.setText(_("Connecting") + "..."); + (new AsyncConnect()).start(); + } + }); + add(btnConnect, "cell 1 3"); + + message = new JLabel(""); + message.setForeground(Color.BLACK); + add(message, "cell 1 4, height 20"); + } + + class AsyncConnect extends Thread { + @Override + public void run() { + try { + String hostname = hostField.getText().trim(); + InetAddress addr = InetAddress.getByName(hostname); + int port = Integer.parseInt(portField.getText()); + client.connect(addr, port); + return; + } catch (NumberFormatException nfe) { + message.setText( _("Invalid port number.")); + } catch (UnknownHostException e1) { + message.setText( _("Connection failed. Unknown host.")); + } catch (RuntimeIoException ex) { + if (ex.getCause() instanceof ConnectException) { + message.setText( _("Connection refused.")); + } else { + message.setText( _("Connection failed.")); + } + } + message.setForeground(Color.RED); + btnConnect.setEnabled(true); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/panel/CreateGamePanel.java b/src/main/java/com/jcloisterzone/ui/panel/CreateGamePanel.java index caf1171f8..a246228fc 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/CreateGamePanel.java +++ b/src/main/java/com/jcloisterzone/ui/panel/CreateGamePanel.java @@ -1,264 +1,264 @@ -package com.jcloisterzone.ui.panel; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.border.TitledBorder; - -import net.miginfocom.swing.MigLayout; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.TilePackFactory; -import com.jcloisterzone.game.CustomRule; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.ui.Client; - -public class CreateGamePanel extends JPanel { - - private static final long serialVersionUID = -8993000662700228625L; - - static Font FONT_RULE_SECTION = new Font(null, Font.ITALIC, 13); - - private final Client client; - private boolean mutableSlots; - - private JPanel playersPanel; - // private JLabel helpText; - private JButton startGameButton; - private JPanel expansionPanel; - private JPanel rulesPanel; - private JPanel panel; - - private Map expansionComponents = new HashMap<>(); - private Map ruleCheckboxes = new HashMap<>(); - - /** - * Create the panel. - */ - public CreateGamePanel(final Client client, boolean mutableSlots, PlayerSlot[] slots) { - this.client = client; - this.mutableSlots = mutableSlots; - NameProvider nameProvider = new NameProvider(client.getConfig()); - - setLayout(new MigLayout("", "[][grow][grow]", "[][grow]")); - - panel = new JPanel(); - add(panel, "cell 0 0 3 1,grow"); - panel.setLayout(new MigLayout("", "[grow][]", "[]")); - - // helpText = new JLabel("[TODO HELP TEXT]"); - // panel.add(helpText, "growx"); - // helpText.setText(_("The game has been created. Remote clients can connect now.")); - - startGameButton = new JButton(_("Start game")); - startGameButton.setIcon(new ImageIcon(CreateGamePanel.class - .getResource("/sysimages/endTurn.png"))); - panel.add(startGameButton, "width 100, h 40, east"); - - startGameButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.getServer().startGame(); - } - }); - - playersPanel = new JPanel(); - playersPanel.setBorder(new TitledBorder(null, _("Players"), - TitledBorder.LEADING, TitledBorder.TOP, null, null)); - playersPanel.setLayout(new MigLayout("", "[grow]", "")); - - for (PlayerSlot slot : slots) { - if (slot != null) { - playersPanel.add(new CreateGamePlayerPanel(client, mutableSlots, slot, nameProvider), "wrap"); - } - } - add(playersPanel, "cell 0 1,grow"); - - expansionPanel = new JPanel(); - expansionPanel.setBorder(new TitledBorder(null, _("Expansions"), - TitledBorder.LEADING, TitledBorder.TOP, null, null)); - - TilePackFactory tilePackFactory = new TilePackFactory(); - tilePackFactory.setConfig(client.getConfig()); - - expansionPanel.setLayout(new MigLayout("", "[][right]", "[]")); - for (Expansion exp : Expansion.values()) { - if (!exp.isEnabled()) - continue; - // if (exp == Expansion.WHEEL_OF_FORTUNE) continue; - JCheckBox chbox = createExpansionCheckbox(exp, mutableSlots); - if (exp == Expansion.KING_AND_SCOUT || exp == Expansion.INNS_AND_CATHEDRALS || exp == Expansion.FLIER) { - expansionPanel.add(chbox, "gaptop 10"); - } else { - expansionPanel.add(chbox, ""); - } - JLabel expansionSize = new JLabel(tilePackFactory.getExpansionSize(exp)+""); - expansionSize.setForeground(Color.GRAY); - expansionPanel.add(expansionSize, "wrap"); - expansionComponents.put(exp, new JComponent[] {chbox, expansionSize}); - } - add(expansionPanel, "cell 1 1,grow"); - - rulesPanel = new JPanel(); - rulesPanel.setBorder(new TitledBorder(null, _("Rules"), - TitledBorder.LEADING, TitledBorder.TOP, null, null)); - rulesPanel.setLayout(new MigLayout("", "[]", "[]")); - add(rulesPanel, "cell 2 1,grow"); - - Expansion prev = Expansion.BASIC; - for (CustomRule rule : CustomRule.values()) { - if (prev != rule.getExpansion()) { - prev = rule.getExpansion(); - JLabel label = new JLabel(prev.toString()); - label.setFont(FONT_RULE_SECTION); - rulesPanel.add(label, "wrap, growx, gaptop 10, gapbottom 7"); - } - JCheckBox chbox = createRuleCheckbox(rule, mutableSlots); - rulesPanel.add(chbox, "wrap"); - ruleCheckboxes.put(rule, chbox); - } - - onSlotStateChange(); - startGameButton.requestFocus(); - } - - public void disposePanel() { - for (Component comp : playersPanel.getComponents()) { - if (comp instanceof CreateGamePlayerPanel) { - ((CreateGamePlayerPanel) comp).disposePanel(); - } - } - } - - private JCheckBox createRuleCheckbox(final CustomRule rule, - boolean mutableSlots) { - JCheckBox chbox = new JCheckBox(rule.getLabel()); - if (mutableSlots) { - chbox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JCheckBox chbox = (JCheckBox) e.getSource(); - client.getServer().updateCustomRule(rule, - chbox.isSelected()); - } - }); - } else { - chbox.setEnabled(false); - } - return chbox; - } - - private JCheckBox createExpansionCheckbox(final Expansion exp, - boolean mutableSlots) { - JCheckBox chbox = new JCheckBox(exp.toString()); - if (!exp.isEnabled() || !mutableSlots) - chbox.setEnabled(false); - if (exp == Expansion.BASIC) { - // chbox.setSelected(true); - chbox.setEnabled(false); - } - if (chbox.isEnabled()) { - chbox.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - JCheckBox chbox = (JCheckBox) e.getSource(); - client.getServer().updateExpansion(exp, chbox.isSelected()); - } - }); - } - return chbox; - } - - public void updateCustomRule(CustomRule rule, Boolean enabled) { - ruleCheckboxes.get(rule).setSelected(enabled); - } - - public void updateExpansion(Expansion expansion, Boolean enabled) { - ((JCheckBox)expansionComponents.get(expansion)[0]).setSelected(enabled); - } - - public void updateSupportedExpansions(EnumSet expansions) { - if (expansions == null) { - expansions = EnumSet.allOf(Expansion.class); - } - for (Expansion exp : Expansion.values()) { - if (exp.isEnabled()) { - boolean isSupported = expansions.contains(exp); - JComponent[] components = expansionComponents.get(exp); - for (JComponent comp : components) { - comp.setVisible(isSupported); - } - } - } - } - - private CreateGamePlayerPanel getPlayerPanel(int number) { - for (Component comp : playersPanel.getComponents()) { - CreateGamePlayerPanel panel = (CreateGamePlayerPanel) comp; - PlayerSlot slot = panel.getSlot(); - if (slot != null && slot.getNumber() == number) - return panel; - } - throw new IllegalArgumentException("Slot " + number + " does not exit."); - } - - public void updateSlot(PlayerSlot slot) { - getPlayerPanel(slot.getNumber()).updateSlot(slot); - onSlotStateChange(); - } - - private void onSlotStateChange() { - boolean anyPlayerAssigned = false; - boolean allPlayersAssigned = true; - ArrayList serials = new ArrayList(); - - for (Component c : playersPanel.getComponents()) { - CreateGamePlayerPanel playerPanel = (CreateGamePlayerPanel) c; - PlayerSlot ps = playerPanel.getSlot(); - if (ps == null || ps.getType() == SlotType.OPEN) { - allPlayersAssigned = false; - } else { - anyPlayerAssigned = true; - } - if (ps != null && ps.getSerial() != null) { - serials.add(ps.getSerial()); - } else { - playerPanel.setSerialText(""); - } - } - if (mutableSlots && !serials.isEmpty()) { - Collections.sort(serials); - for (Component c : playersPanel.getComponents()) { - CreateGamePlayerPanel playerPanel = (CreateGamePlayerPanel) c; - PlayerSlot ps = playerPanel.getSlot(); - if (ps != null && ps.getSerial() != null) { - playerPanel.setSerialText("" - + (1 + serials.indexOf(ps.getSerial()))); - } - } - } - - if (mutableSlots) { - startGameButton.setEnabled(anyPlayerAssigned); - } else { - startGameButton.setEnabled(allPlayersAssigned); - } - } - -} +package com.jcloisterzone.ui.panel; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; + +import net.miginfocom.swing.MigLayout; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.TilePackFactory; +import com.jcloisterzone.game.CustomRule; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.ui.Client; + +public class CreateGamePanel extends JPanel { + + private static final long serialVersionUID = -8993000662700228625L; + + static Font FONT_RULE_SECTION = new Font(null, Font.ITALIC, 13); + + private final Client client; + private boolean mutableSlots; + + private JPanel playersPanel; + // private JLabel helpText; + private JButton startGameButton; + private JPanel expansionPanel; + private JPanel rulesPanel; + private JPanel panel; + + private Map expansionComponents = new HashMap<>(); + private Map ruleCheckboxes = new HashMap<>(); + + /** + * Create the panel. + */ + public CreateGamePanel(final Client client, boolean mutableSlots, PlayerSlot[] slots) { + this.client = client; + this.mutableSlots = mutableSlots; + NameProvider nameProvider = new NameProvider(client.getConfig()); + + setLayout(new MigLayout("", "[][grow][grow]", "[][grow]")); + + panel = new JPanel(); + add(panel, "cell 0 0 3 1,grow"); + panel.setLayout(new MigLayout("", "[grow][]", "[]")); + + // helpText = new JLabel("[TODO HELP TEXT]"); + // panel.add(helpText, "growx"); + // helpText.setText(_("The game has been created. Remote clients can connect now.")); + + startGameButton = new JButton(_("Start game")); + startGameButton.setIcon(new ImageIcon(CreateGamePanel.class + .getResource("/sysimages/endTurn.png"))); + panel.add(startGameButton, "width 100, h 40, east"); + + startGameButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.getServer().startGame(); + } + }); + + playersPanel = new JPanel(); + playersPanel.setBorder(new TitledBorder(null, _("Players"), + TitledBorder.LEADING, TitledBorder.TOP, null, null)); + playersPanel.setLayout(new MigLayout("", "[grow]", "")); + + for (PlayerSlot slot : slots) { + if (slot != null) { + playersPanel.add(new CreateGamePlayerPanel(client, mutableSlots, slot, nameProvider), "wrap"); + } + } + add(playersPanel, "cell 0 1,grow"); + + expansionPanel = new JPanel(); + expansionPanel.setBorder(new TitledBorder(null, _("Expansions"), + TitledBorder.LEADING, TitledBorder.TOP, null, null)); + + TilePackFactory tilePackFactory = new TilePackFactory(); + tilePackFactory.setConfig(client.getConfig()); + + expansionPanel.setLayout(new MigLayout("", "[][right]", "[]")); + for (Expansion exp : Expansion.values()) { + if (!exp.isEnabled()) + continue; + // if (exp == Expansion.WHEEL_OF_FORTUNE) continue; + JCheckBox chbox = createExpansionCheckbox(exp, mutableSlots); + if (exp == Expansion.KING_AND_SCOUT || exp == Expansion.INNS_AND_CATHEDRALS || exp == Expansion.FLIER) { + expansionPanel.add(chbox, "gaptop 10"); + } else { + expansionPanel.add(chbox, ""); + } + JLabel expansionSize = new JLabel(tilePackFactory.getExpansionSize(exp)+""); + expansionSize.setForeground(Color.GRAY); + expansionPanel.add(expansionSize, "wrap"); + expansionComponents.put(exp, new JComponent[] {chbox, expansionSize}); + } + add(expansionPanel, "cell 1 1,grow"); + + rulesPanel = new JPanel(); + rulesPanel.setBorder(new TitledBorder(null, _("Rules"), + TitledBorder.LEADING, TitledBorder.TOP, null, null)); + rulesPanel.setLayout(new MigLayout("", "[]", "[]")); + add(rulesPanel, "cell 2 1,grow"); + + Expansion prev = Expansion.BASIC; + for (CustomRule rule : CustomRule.values()) { + if (prev != rule.getExpansion()) { + prev = rule.getExpansion(); + JLabel label = new JLabel(prev.toString()); + label.setFont(FONT_RULE_SECTION); + rulesPanel.add(label, "wrap, growx, gaptop 10, gapbottom 7"); + } + JCheckBox chbox = createRuleCheckbox(rule, mutableSlots); + rulesPanel.add(chbox, "wrap"); + ruleCheckboxes.put(rule, chbox); + } + + onSlotStateChange(); + startGameButton.requestFocus(); + } + + public void disposePanel() { + for (Component comp : playersPanel.getComponents()) { + if (comp instanceof CreateGamePlayerPanel) { + ((CreateGamePlayerPanel) comp).disposePanel(); + } + } + } + + private JCheckBox createRuleCheckbox(final CustomRule rule, + boolean mutableSlots) { + JCheckBox chbox = new JCheckBox(rule.getLabel()); + if (mutableSlots) { + chbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JCheckBox chbox = (JCheckBox) e.getSource(); + client.getServer().updateCustomRule(rule, + chbox.isSelected()); + } + }); + } else { + chbox.setEnabled(false); + } + return chbox; + } + + private JCheckBox createExpansionCheckbox(final Expansion exp, + boolean mutableSlots) { + JCheckBox chbox = new JCheckBox(exp.toString()); + if (!exp.isEnabled() || !mutableSlots) + chbox.setEnabled(false); + if (exp == Expansion.BASIC) { + // chbox.setSelected(true); + chbox.setEnabled(false); + } + if (chbox.isEnabled()) { + chbox.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + JCheckBox chbox = (JCheckBox) e.getSource(); + client.getServer().updateExpansion(exp, chbox.isSelected()); + } + }); + } + return chbox; + } + + public void updateCustomRule(CustomRule rule, Boolean enabled) { + ruleCheckboxes.get(rule).setSelected(enabled); + } + + public void updateExpansion(Expansion expansion, Boolean enabled) { + ((JCheckBox)expansionComponents.get(expansion)[0]).setSelected(enabled); + } + + public void updateSupportedExpansions(EnumSet expansions) { + if (expansions == null) { + expansions = EnumSet.allOf(Expansion.class); + } + for (Expansion exp : Expansion.values()) { + if (exp.isEnabled()) { + boolean isSupported = expansions.contains(exp); + JComponent[] components = expansionComponents.get(exp); + for (JComponent comp : components) { + comp.setVisible(isSupported); + } + } + } + } + + private CreateGamePlayerPanel getPlayerPanel(int number) { + for (Component comp : playersPanel.getComponents()) { + CreateGamePlayerPanel panel = (CreateGamePlayerPanel) comp; + PlayerSlot slot = panel.getSlot(); + if (slot != null && slot.getNumber() == number) + return panel; + } + throw new IllegalArgumentException("Slot " + number + " does not exit."); + } + + public void updateSlot(PlayerSlot slot) { + getPlayerPanel(slot.getNumber()).updateSlot(slot); + onSlotStateChange(); + } + + private void onSlotStateChange() { + boolean anyPlayerAssigned = false; + boolean allPlayersAssigned = true; + ArrayList serials = new ArrayList(); + + for (Component c : playersPanel.getComponents()) { + CreateGamePlayerPanel playerPanel = (CreateGamePlayerPanel) c; + PlayerSlot ps = playerPanel.getSlot(); + if (ps == null || ps.getType() == SlotType.OPEN) { + allPlayersAssigned = false; + } else { + anyPlayerAssigned = true; + } + if (ps != null && ps.getSerial() != null) { + serials.add(ps.getSerial()); + } else { + playerPanel.setSerialText(""); + } + } + if (mutableSlots && !serials.isEmpty()) { + Collections.sort(serials); + for (Component c : playersPanel.getComponents()) { + CreateGamePlayerPanel playerPanel = (CreateGamePlayerPanel) c; + PlayerSlot ps = playerPanel.getSlot(); + if (ps != null && ps.getSerial() != null) { + playerPanel.setSerialText("" + + (1 + serials.indexOf(ps.getSerial()))); + } + } + } + + if (mutableSlots) { + startGameButton.setEnabled(anyPlayerAssigned); + } else { + startGameButton.setEnabled(allPlayersAssigned); + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/panel/CreateGamePlayerPanel.java b/src/main/java/com/jcloisterzone/ui/panel/CreateGamePlayerPanel.java index e25cffe1e..533bf1d04 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/CreateGamePlayerPanel.java +++ b/src/main/java/com/jcloisterzone/ui/panel/CreateGamePlayerPanel.java @@ -1,310 +1,310 @@ -package com.jcloisterzone.ui.panel; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.util.EnumSet; - -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.SwingConstants; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; - -import net.miginfocom.swing.MigLayout; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.ai.legacyplayer.LegacyAiPlayer; -import com.jcloisterzone.game.PlayerSlot; -import com.jcloisterzone.game.PlayerSlot.SlotType; -import com.jcloisterzone.ui.Client; - -public class CreateGamePlayerPanel extends JPanel { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private static final long serialVersionUID = 1436952221307376517L; - - static Font FONT_PLAYER_TYPE = new Font(null, Font.ITALIC, 11); - static Font FONT_SERIAL = new Font(null, Font.BOLD, 32); - - private PlayerSlot slot; - - private final Client client; - private boolean mutableSlots; - private long clientId; - - private JButton icon; - private JLabel status; - private JTextField nickname; - - private NicknameUpdater nicknameUpdater; - private JLabel serialLabel; - - private NameProvider nameProvider; - - - /** - * Create the panel. - */ - public CreateGamePlayerPanel(final Client client, boolean mutableSlots, PlayerSlot slot, NameProvider nameProvider) { - this.client = client; - this.mutableSlots = mutableSlots; - this.clientId = client.getClientId(); - this.nameProvider = nameProvider; - - setLayout(new MigLayout("", "[][][10px][grow]", "[][]")); - - serialLabel = new JLabel(""); - serialLabel.setHorizontalAlignment(SwingConstants.CENTER); - serialLabel.setForeground(new Color(180,180,180)); - serialLabel.setFont(FONT_SERIAL); - add(serialLabel, "cell 0 0 0 2,width 34!,height 60!"); - - icon = new JButton(); - icon.addActionListener(mutableSlots ? new MutableIconActionListener() : new ImmutableIconActionListener()); - add(icon, "cell 1 0 1 2,width 60!,height 60!"); - - nickname = new JTextField(); - updateNickname(false); - add(nickname, "cell 3 0,growx,width :200:,gapy 10"); - - status = new JLabel(""); - status.setFont(FONT_PLAYER_TYPE); - add(status, "cell 3 1,growx"); - - updateSlot(slot); - - if (mutableSlots) { - nicknameUpdater = new NicknameUpdater(); - nicknameUpdater.setName("NickUpdater"+slot.getNumber()); - nicknameUpdater.start(); - nickname.addCaretListener(nicknameUpdater); - nickname.addFocusListener(nicknameUpdater); - } - } - - public void disposePanel() { - if (nicknameUpdater != null) { - nicknameUpdater.setStopped(true); - nicknameUpdater = null; - } - } - - private boolean isMySlotBefore(PlayerSlot slot) { - if (slot == null || this.slot == null) return false; - if (slot.getOwner() == null || this.slot.getOwner() == null) return false; - if (slot.getOwner() != clientId || this.slot.getOwner() != clientId) return false; - if (slot.getType() != this.slot.getType()) return false; - return true; - } - - public void updateSlot(PlayerSlot slot) { - //logger.debug("Updating slot {}", slot); - if (mutableSlots) { - updateSlotMutable(slot); - } else { - updateSlotImmutable(slot); - } - } - - public PlayerSlot getSlot() { - return slot; - } - - private void updateNickname(boolean editable) { - //nickname.setEditable(false); - nickname.setEnabled(editable); - } - - private void updateIcon(String iconType, Color color, boolean state) { - ImageIcon img = new ImageIcon(client.getFigureTheme().getPlayerSlotImage(iconType, color)); - icon.setIcon(img); - icon.setDisabledIcon(img); - icon.setEnabled(state); - } - - public void updateSlotImmutable(PlayerSlot slot) { - this.slot = slot; - Color color = client.getPlayerColor(slot); - switch (slot.getType()) { - case OPEN: - status.setText(_("Unassigned player")); - updateIcon("open", color, true); - break; - case PLAYER: - if (slot.getOwner() == clientId) { - status.setText(_("Local player")); - updateIcon("local", color, true); - } else { - status.setText(_("Remote player")); - updateIcon("remote", color, false); - } - break; - case AI: - status.setText(_("Computer player")); - updateIcon("ai", color, false); - break; - } - nickname.setText(slot.getNick()); - } - - public void updateSlotMutable(PlayerSlot slot) { - boolean myBefore = isMySlotBefore(slot); - this.slot = slot; - Color color = client.getPlayerColor(slot); - switch (slot.getType()) { - case OPEN: - status.setText(_("Open player slot")); - updateIcon("open", color, true); - updateNickname(false); - break; - case PLAYER: - if (slot.getOwner() != null && slot.getOwner() == clientId) { - status.setText(_("Local player")); - updateIcon("local", color, true); - updateNickname(true); - } else { - status.setText(_("Remote player")); - updateIcon("remote", color, false); - updateNickname(false); - } - break; - case AI: - status.setText(_("Computer player")); - //updateIcon("ai", color, slot.getOwner() == clientId); - updateIcon("ai", color, true); - updateNickname(false); - break; - } - if (!myBefore || ! nickname.isEnabled()) { //probably change by me - nickname.setText(slot.getNick()); - } - /*if (slot.getSerial() == null) { - serialLabel.setText(""); - } else { - serialLabel.setText(slot.getSerial() + ""); - }*/ - } - - public void setSerialText(String text) { - serialLabel.setText(text); - } - - class MutableIconActionListener implements ActionListener { - @Override - public void actionPerformed(ActionEvent e) { - String nick; - EnumSet supported = null; - switch (slot.getType()) { - case OPEN: //-> PLAYER - slot.setType(SlotType.PLAYER); - nick = nameProvider.reserveName(SlotType.PLAYER, slot.getNumber()); - slot.setNick(nick); - nickname.setText(nick); - break; - case PLAYER: //-> AI - nameProvider.releaseName(SlotType.PLAYER, slot.getNumber()); - slot.setType(SlotType.AI); - //TODO pryc s hardcoded AI tridou - slot.setAiClassName(LegacyAiPlayer.class.getName()); - supported = LegacyAiPlayer.supportedExpansions(); - nick = nameProvider.reserveName(SlotType.AI, slot.getNumber()); - slot.setNick(nick); - nickname.setText(nick); - break; - case AI: //-> OPEN - nameProvider.releaseName(SlotType.AI, slot.getNumber()); - slot.setType(SlotType.OPEN); - break; - default: - return; - } - slot.setOwner(clientId); - client.getServer().updateSlot(slot, supported); - } - } - - class ImmutableIconActionListener implements ActionListener { - @Override - public void actionPerformed(ActionEvent e) { - switch (slot.getType()) { - case OPEN: //-> PLAYER - slot.setType(SlotType.PLAYER); - break; - case PLAYER: //-> OPEN - slot.setType(SlotType.OPEN); - break; - default: - return; - } - slot.setOwner(clientId); - client.getServer().updateSlot(slot, null); - } - } - - - class NicknameUpdater extends Thread implements CaretListener, FocusListener { - - private boolean stopped; - private String update; - - @Override - public void caretUpdate(CaretEvent e) { - JTextField field = (JTextField) e.getSource(); - update = field.getText(); - } - - @Override - public void focusGained(FocusEvent e) { - //do nothing - } - - @Override - public void focusLost(FocusEvent e) { - JTextField field = (JTextField) e.getSource(); - update = field.getText(); - } - - - private void requestUpdate() { - if (update != null && ! update.equals(slot.getNick())) { - slot.setNick(update); - client.getServer().updateSlot(slot, null); - update = null; - } - } - - public void setStopped(boolean stopped) { - this.stopped = stopped; - } - - @Override - public void run() { - while (!stopped) { - if (update != null) { - requestUpdate(); - } - try { - Thread.sleep(500); - } catch (InterruptedException e) { - //pass - } - } - } - - - } - -} +package com.jcloisterzone.ui.panel; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.EnumSet; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingConstants; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; + +import net.miginfocom.swing.MigLayout; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.ai.legacyplayer.LegacyAiPlayer; +import com.jcloisterzone.game.PlayerSlot; +import com.jcloisterzone.game.PlayerSlot.SlotType; +import com.jcloisterzone.ui.Client; + +public class CreateGamePlayerPanel extends JPanel { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private static final long serialVersionUID = 1436952221307376517L; + + static Font FONT_PLAYER_TYPE = new Font(null, Font.ITALIC, 11); + static Font FONT_SERIAL = new Font(null, Font.BOLD, 32); + + private PlayerSlot slot; + + private final Client client; + private boolean mutableSlots; + private long clientId; + + private JButton icon; + private JLabel status; + private JTextField nickname; + + private NicknameUpdater nicknameUpdater; + private JLabel serialLabel; + + private NameProvider nameProvider; + + + /** + * Create the panel. + */ + public CreateGamePlayerPanel(final Client client, boolean mutableSlots, PlayerSlot slot, NameProvider nameProvider) { + this.client = client; + this.mutableSlots = mutableSlots; + this.clientId = client.getClientId(); + this.nameProvider = nameProvider; + + setLayout(new MigLayout("", "[][][10px][grow]", "[][]")); + + serialLabel = new JLabel(""); + serialLabel.setHorizontalAlignment(SwingConstants.CENTER); + serialLabel.setForeground(new Color(180,180,180)); + serialLabel.setFont(FONT_SERIAL); + add(serialLabel, "cell 0 0 0 2,width 34!,height 60!"); + + icon = new JButton(); + icon.addActionListener(mutableSlots ? new MutableIconActionListener() : new ImmutableIconActionListener()); + add(icon, "cell 1 0 1 2,width 60!,height 60!"); + + nickname = new JTextField(); + updateNickname(false); + add(nickname, "cell 3 0,growx,width :200:,gapy 10"); + + status = new JLabel(""); + status.setFont(FONT_PLAYER_TYPE); + add(status, "cell 3 1,growx"); + + updateSlot(slot); + + if (mutableSlots) { + nicknameUpdater = new NicknameUpdater(); + nicknameUpdater.setName("NickUpdater"+slot.getNumber()); + nicknameUpdater.start(); + nickname.addCaretListener(nicknameUpdater); + nickname.addFocusListener(nicknameUpdater); + } + } + + public void disposePanel() { + if (nicknameUpdater != null) { + nicknameUpdater.setStopped(true); + nicknameUpdater = null; + } + } + + private boolean isMySlotBefore(PlayerSlot slot) { + if (slot == null || this.slot == null) return false; + if (slot.getOwner() == null || this.slot.getOwner() == null) return false; + if (slot.getOwner() != clientId || this.slot.getOwner() != clientId) return false; + if (slot.getType() != this.slot.getType()) return false; + return true; + } + + public void updateSlot(PlayerSlot slot) { + //logger.debug("Updating slot {}", slot); + if (mutableSlots) { + updateSlotMutable(slot); + } else { + updateSlotImmutable(slot); + } + } + + public PlayerSlot getSlot() { + return slot; + } + + private void updateNickname(boolean editable) { + //nickname.setEditable(false); + nickname.setEnabled(editable); + } + + private void updateIcon(String iconType, Color color, boolean state) { + ImageIcon img = new ImageIcon(client.getFigureTheme().getPlayerSlotImage(iconType, color)); + icon.setIcon(img); + icon.setDisabledIcon(img); + icon.setEnabled(state); + } + + public void updateSlotImmutable(PlayerSlot slot) { + this.slot = slot; + Color color = client.getPlayerColor(slot); + switch (slot.getType()) { + case OPEN: + status.setText(_("Unassigned player")); + updateIcon("open", color, true); + break; + case PLAYER: + if (slot.getOwner() == clientId) { + status.setText(_("Local player")); + updateIcon("local", color, true); + } else { + status.setText(_("Remote player")); + updateIcon("remote", color, false); + } + break; + case AI: + status.setText(_("Computer player")); + updateIcon("ai", color, false); + break; + } + nickname.setText(slot.getNick()); + } + + public void updateSlotMutable(PlayerSlot slot) { + boolean myBefore = isMySlotBefore(slot); + this.slot = slot; + Color color = client.getPlayerColor(slot); + switch (slot.getType()) { + case OPEN: + status.setText(_("Open player slot")); + updateIcon("open", color, true); + updateNickname(false); + break; + case PLAYER: + if (slot.getOwner() != null && slot.getOwner() == clientId) { + status.setText(_("Local player")); + updateIcon("local", color, true); + updateNickname(true); + } else { + status.setText(_("Remote player")); + updateIcon("remote", color, false); + updateNickname(false); + } + break; + case AI: + status.setText(_("Computer player")); + //updateIcon("ai", color, slot.getOwner() == clientId); + updateIcon("ai", color, true); + updateNickname(false); + break; + } + if (!myBefore || ! nickname.isEnabled()) { //probably change by me + nickname.setText(slot.getNick()); + } + /*if (slot.getSerial() == null) { + serialLabel.setText(""); + } else { + serialLabel.setText(slot.getSerial() + ""); + }*/ + } + + public void setSerialText(String text) { + serialLabel.setText(text); + } + + class MutableIconActionListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + String nick; + EnumSet supported = null; + switch (slot.getType()) { + case OPEN: //-> PLAYER + slot.setType(SlotType.PLAYER); + nick = nameProvider.reserveName(SlotType.PLAYER, slot.getNumber()); + slot.setNick(nick); + nickname.setText(nick); + break; + case PLAYER: //-> AI + nameProvider.releaseName(SlotType.PLAYER, slot.getNumber()); + slot.setType(SlotType.AI); + //TODO pryc s hardcoded AI tridou + slot.setAiClassName(LegacyAiPlayer.class.getName()); + supported = LegacyAiPlayer.supportedExpansions(); + nick = nameProvider.reserveName(SlotType.AI, slot.getNumber()); + slot.setNick(nick); + nickname.setText(nick); + break; + case AI: //-> OPEN + nameProvider.releaseName(SlotType.AI, slot.getNumber()); + slot.setType(SlotType.OPEN); + break; + default: + return; + } + slot.setOwner(clientId); + client.getServer().updateSlot(slot, supported); + } + } + + class ImmutableIconActionListener implements ActionListener { + @Override + public void actionPerformed(ActionEvent e) { + switch (slot.getType()) { + case OPEN: //-> PLAYER + slot.setType(SlotType.PLAYER); + break; + case PLAYER: //-> OPEN + slot.setType(SlotType.OPEN); + break; + default: + return; + } + slot.setOwner(clientId); + client.getServer().updateSlot(slot, null); + } + } + + + class NicknameUpdater extends Thread implements CaretListener, FocusListener { + + private boolean stopped; + private String update; + + @Override + public void caretUpdate(CaretEvent e) { + JTextField field = (JTextField) e.getSource(); + update = field.getText(); + } + + @Override + public void focusGained(FocusEvent e) { + //do nothing + } + + @Override + public void focusLost(FocusEvent e) { + JTextField field = (JTextField) e.getSource(); + update = field.getText(); + } + + + private void requestUpdate() { + if (update != null && ! update.equals(slot.getNick())) { + slot.setNick(update); + client.getServer().updateSlot(slot, null); + update = null; + } + } + + public void setStopped(boolean stopped) { + this.stopped = stopped; + } + + @Override + public void run() { + while (!stopped) { + if (update != null) { + requestUpdate(); + } + try { + Thread.sleep(500); + } catch (InterruptedException e) { + //pass + } + } + } + + + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/panel/HelpPanel.java b/src/main/java/com/jcloisterzone/ui/panel/HelpPanel.java index 05311a0ee..d1c00d802 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/HelpPanel.java +++ b/src/main/java/com/jcloisterzone/ui/panel/HelpPanel.java @@ -1,32 +1,32 @@ -package com.jcloisterzone.ui.panel; - -import static com.jcloisterzone.ui.I18nUtils._; - -import javax.swing.JLabel; -import javax.swing.JPanel; - -import net.miginfocom.swing.MigLayout; - -public class HelpPanel extends JPanel { - - public HelpPanel() { - setLayout(new MigLayout("", "[grow]", "[]10[]10[]10[]")); - JLabel paragraph; - - paragraph = new JLabel(_("Use A, S, W, D or cursor keys to scroll the board. " + - "Click with middle mouse button to center the board. " + - "Zoom with + or - keys or use mouse wheel.")); - add(paragraph, "cell 0 0,grow"); - - paragraph = new JLabel(_("Rotate a tile by Tab key or right mouse click. Place it by left click.")); - add(paragraph, "cell 0 1,grow"); - - paragraph = new JLabel(_("When tile is placed use Tab or right click again to "+ - "select appropriate action.")); - add(paragraph, "cell 0 2,grow"); - - paragraph = new JLabel(_("Alternativelly you can pass with Enter or Space to play no action.")); - add(paragraph, "cell 0 3,grow"); - } - -} +package com.jcloisterzone.ui.panel; + +import static com.jcloisterzone.ui.I18nUtils._; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import net.miginfocom.swing.MigLayout; + +public class HelpPanel extends JPanel { + + public HelpPanel() { + setLayout(new MigLayout("", "[grow]", "[]10[]10[]10[]")); + JLabel paragraph; + + paragraph = new JLabel(_("Use A, S, W, D or cursor keys to scroll the board. " + + "Click with middle mouse button to center the board. " + + "Zoom with + or - keys or use mouse wheel.")); + add(paragraph, "cell 0 0,grow"); + + paragraph = new JLabel(_("Rotate a tile by Tab key or right mouse click. Place it by left click.")); + add(paragraph, "cell 0 1,grow"); + + paragraph = new JLabel(_("When tile is placed use Tab or right click again to "+ + "select appropriate action.")); + add(paragraph, "cell 0 2,grow"); + + paragraph = new JLabel(_("Alternativelly you can pass with Enter or Space to play no action.")); + add(paragraph, "cell 0 3,grow"); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/panel/NameProvider.java b/src/main/java/com/jcloisterzone/ui/panel/NameProvider.java index 5cc784e36..49f66d9fd 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/NameProvider.java +++ b/src/main/java/com/jcloisterzone/ui/panel/NameProvider.java @@ -1,63 +1,63 @@ -package com.jcloisterzone.ui.panel; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.ini4j.Ini; - -import com.jcloisterzone.game.PlayerSlot.SlotType; - -public class NameProvider { - - private static class ReservedName { - String name; - Integer slot; - - public ReservedName(String name, Integer slot) { - this.name = name; - this.slot = slot; - } - } - - private Map> namesMap = new HashMap<>(); - - - public NameProvider(Ini config) { - initNames(SlotType.PLAYER, config.get("players").getAll("name")); - initNames(SlotType.AI, config.get("players").getAll("ai_name")); - } - - private void initNames(SlotType type, List names) { - List rn = new ArrayList<>(); - namesMap.put(type, rn); - if (names != null) { - for (String name: names) { - rn.add(new ReservedName(name, null)); - } - } - } - - synchronized - public String reserveName(SlotType type, int slot) { - for (ReservedName rn : namesMap.get(type)) { - if (rn.slot == null) { - rn.slot = slot; - return rn.name; - } - } - return ""; - } - - synchronized - public void releaseName(SlotType type, int slot) { - for (ReservedName rn : namesMap.get(type)) { - if (rn.slot != null && rn.slot == slot) { //autoboxing, must check for null - rn.slot = null; - return; - } - } - } - -} +package com.jcloisterzone.ui.panel; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.ini4j.Ini; + +import com.jcloisterzone.game.PlayerSlot.SlotType; + +public class NameProvider { + + private static class ReservedName { + String name; + Integer slot; + + public ReservedName(String name, Integer slot) { + this.name = name; + this.slot = slot; + } + } + + private Map> namesMap = new HashMap<>(); + + + public NameProvider(Ini config) { + initNames(SlotType.PLAYER, config.get("players").getAll("name")); + initNames(SlotType.AI, config.get("players").getAll("ai_name")); + } + + private void initNames(SlotType type, List names) { + List rn = new ArrayList<>(); + namesMap.put(type, rn); + if (names != null) { + for (String name: names) { + rn.add(new ReservedName(name, null)); + } + } + } + + synchronized + public String reserveName(SlotType type, int slot) { + for (ReservedName rn : namesMap.get(type)) { + if (rn.slot == null) { + rn.slot = slot; + return rn.name; + } + } + return ""; + } + + synchronized + public void releaseName(SlotType type, int slot) { + for (ReservedName rn : namesMap.get(type)) { + if (rn.slot != null && rn.slot == slot) { //autoboxing, must check for null + rn.slot = null; + return; + } + } + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/panel/StartPanel.java b/src/main/java/com/jcloisterzone/ui/panel/StartPanel.java index 6cfbc6f10..16db194b5 100644 --- a/src/main/java/com/jcloisterzone/ui/panel/StartPanel.java +++ b/src/main/java/com/jcloisterzone/ui/panel/StartPanel.java @@ -1,109 +1,109 @@ -package com.jcloisterzone.ui.panel; - -import static com.jcloisterzone.ui.I18nUtils._; - -import java.awt.Color; -import java.awt.Font; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.UIManager; -import javax.swing.border.TitledBorder; - -import net.miginfocom.swing.MigLayout; - -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.MultiLineLabel; - -public class StartPanel extends JPanel { - - static Font FONT_LARGE_BUTTON = new Font(null, Font.PLAIN, 25); - - private Client client; - - private HelpPanel helpPanel; - - /** - * Create the panel. - */ - public StartPanel() { - setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); - setLayout(new MigLayout("", "[center, grow]20[center, grow]20[center, grow]", "[]20[]10[]")); - - JLabel lblNewLabel = new JLabel(); - lblNewLabel.setIcon(new ImageIcon(StartPanel.class.getResource("/sysimages/jcloisterzone.png"))); - add(lblNewLabel, "span 3, wrap, center"); - helpPanel = new HelpPanel(); - add(helpPanel, "span 3, wrap, grow, gap 30 30"); - - JPanel createPanel = new JPanel(); - createPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); - add(createPanel, "grow, width :250:"); - createPanel.setLayout(new MigLayout("", "[grow,center]", "20[40px]20[grow]")); - - JButton create = new JButton(_("New game")); - createPanel.add(create, "wrap, alignx center,aligny top"); - create.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.createGame(); - } - }); - create.setFont(FONT_LARGE_BUTTON); - createPanel.add(new MultiLineLabel( - _("Create a new local or network game. You can play against any number of computer players.")), - "wrap, grow"); - - - JPanel connectPanel = new JPanel(); - connectPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); - add(connectPanel, "grow, width :250:"); - connectPanel.setLayout(new MigLayout("", "[grow,center]", "20[40px]20[grow]")); - - JButton connect = new JButton(_("Connect")); - connectPanel.add(connect, "wrap, alignx center,aligny top"); - connect.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.showConnectGamePanel(); - } - }); - connect.setFont(FONT_LARGE_BUTTON); - connectPanel.add(new MultiLineLabel( - _("Connect to a remote JCloisterZone application with settled new game.")), - "wrap, grow"); - - - JPanel loadPanel = new JPanel(); - loadPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); - add(loadPanel, "grow, width :250:"); - loadPanel.setLayout(new MigLayout("", "[grow,center]", "20[40px]20[grow]")); - - JButton load = new JButton(_("Load game")); - loadPanel.add(load, "wrap, alignx center,aligny top"); - load.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - client.handleLoad(); - } - }); - load.setFont(FONT_LARGE_BUTTON); - loadPanel.add(new MultiLineLabel( - _("Load from a file previously saved game.")), - "wrap, grow"); - } - - public Client getClient() { - return client; - } - - public void setClient(Client client) { - this.client = client; - } - - public HelpPanel getHelpPanel() { - return helpPanel; - } - -} +package com.jcloisterzone.ui.panel; + +import static com.jcloisterzone.ui.I18nUtils._; + +import java.awt.Color; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.UIManager; +import javax.swing.border.TitledBorder; + +import net.miginfocom.swing.MigLayout; + +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.MultiLineLabel; + +public class StartPanel extends JPanel { + + static Font FONT_LARGE_BUTTON = new Font(null, Font.PLAIN, 25); + + private Client client; + + private HelpPanel helpPanel; + + /** + * Create the panel. + */ + public StartPanel() { + setBorder(new TitledBorder(null, "", TitledBorder.LEADING, TitledBorder.TOP, null, null)); + setLayout(new MigLayout("", "[center, grow]20[center, grow]20[center, grow]", "[]20[]10[]")); + + JLabel lblNewLabel = new JLabel(); + lblNewLabel.setIcon(new ImageIcon(StartPanel.class.getResource("/sysimages/jcloisterzone.png"))); + add(lblNewLabel, "span 3, wrap, center"); + helpPanel = new HelpPanel(); + add(helpPanel, "span 3, wrap, grow, gap 30 30"); + + JPanel createPanel = new JPanel(); + createPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); + add(createPanel, "grow, width :250:"); + createPanel.setLayout(new MigLayout("", "[grow,center]", "20[40px]20[grow]")); + + JButton create = new JButton(_("New game")); + createPanel.add(create, "wrap, alignx center,aligny top"); + create.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.createGame(); + } + }); + create.setFont(FONT_LARGE_BUTTON); + createPanel.add(new MultiLineLabel( + _("Create a new local or network game. You can play against any number of computer players.")), + "wrap, grow"); + + + JPanel connectPanel = new JPanel(); + connectPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); + add(connectPanel, "grow, width :250:"); + connectPanel.setLayout(new MigLayout("", "[grow,center]", "20[40px]20[grow]")); + + JButton connect = new JButton(_("Connect")); + connectPanel.add(connect, "wrap, alignx center,aligny top"); + connect.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.showConnectGamePanel(); + } + }); + connect.setFont(FONT_LARGE_BUTTON); + connectPanel.add(new MultiLineLabel( + _("Connect to a remote JCloisterZone application with settled new game.")), + "wrap, grow"); + + + JPanel loadPanel = new JPanel(); + loadPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(0, 0, 0))); + add(loadPanel, "grow, width :250:"); + loadPanel.setLayout(new MigLayout("", "[grow,center]", "20[40px]20[grow]")); + + JButton load = new JButton(_("Load game")); + loadPanel.add(load, "wrap, alignx center,aligny top"); + load.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + client.handleLoad(); + } + }); + load.setFont(FONT_LARGE_BUTTON); + loadPanel.add(new MultiLineLabel( + _("Load from a file previously saved game.")), + "wrap, grow"); + } + + public Client getClient() { + return client; + } + + public void setClient(Client client) { + this.client = client; + } + + public HelpPanel getHelpPanel() { + return helpPanel; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/plugin/Plugin.java b/src/main/java/com/jcloisterzone/ui/plugin/Plugin.java index 3970d058a..04ff04998 100644 --- a/src/main/java/com/jcloisterzone/ui/plugin/Plugin.java +++ b/src/main/java/com/jcloisterzone/ui/plugin/Plugin.java @@ -1,83 +1,83 @@ -package com.jcloisterzone.ui.plugin; - -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.XmlUtils; - -public class Plugin { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private URL url; - private URLClassLoader loader; - - private String id; - private String title; - private String description; - - public Plugin(URL url) throws MalformedURLException { - this.url = fixPluginURL(url); - logger.debug("Creating plugin loader for URL {}", this.url); - loader = new URLClassLoader(new URL[] { this.url }); - } - - private URL fixPluginURL(URL url) throws MalformedURLException { - boolean isFile = url.toString().endsWith(".jar") || url.toString().endsWith(".zip"); - if (isFile) return url; - return new URL(url.toString()+"/"); - } - - protected final void loadMetadata() throws Exception { - Element plugin = XmlUtils.parseDocument(loader.getResource("plugin.xml")).getDocumentElement(); - parseMetadata(plugin); - } - - protected void parseMetadata(Element rootElement) throws Exception { - id = rootElement.getAttribute("id"); - NodeList nl = rootElement.getElementsByTagName("title"); - if (nl.getLength() > 0) { - title = nl.item(0).getTextContent(); - } - nl = rootElement.getElementsByTagName("description"); - if (nl.getLength() > 0) { - description = nl.item(0).getTextContent(); - } - } - - public URL getUrl() { - return url; - } - public String getId() { - return id; - } - public String getTitle() { - return title; - } - public String getDescription() { - return description; - } - - public URLClassLoader getLoader() { - return loader; - } - - @Override - public String toString() { - return title; - } - - public static Plugin loadPlugin(String path) throws Exception { - URL pluginURL = Plugin.class.getClassLoader().getResource(path); - ResourcePlugin plugin = new ResourcePlugin(pluginURL); - plugin.loadMetadata(); - return plugin; - } -} - +package com.jcloisterzone.ui.plugin; + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.XmlUtils; + +public class Plugin { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private URL url; + private URLClassLoader loader; + + private String id; + private String title; + private String description; + + public Plugin(URL url) throws MalformedURLException { + this.url = fixPluginURL(url); + logger.debug("Creating plugin loader for URL {}", this.url); + loader = new URLClassLoader(new URL[] { this.url }); + } + + private URL fixPluginURL(URL url) throws MalformedURLException { + boolean isFile = url.toString().endsWith(".jar") || url.toString().endsWith(".zip"); + if (isFile) return url; + return new URL(url.toString()+"/"); + } + + protected final void loadMetadata() throws Exception { + Element plugin = XmlUtils.parseDocument(loader.getResource("plugin.xml")).getDocumentElement(); + parseMetadata(plugin); + } + + protected void parseMetadata(Element rootElement) throws Exception { + id = rootElement.getAttribute("id"); + NodeList nl = rootElement.getElementsByTagName("title"); + if (nl.getLength() > 0) { + title = nl.item(0).getTextContent(); + } + nl = rootElement.getElementsByTagName("description"); + if (nl.getLength() > 0) { + description = nl.item(0).getTextContent(); + } + } + + public URL getUrl() { + return url; + } + public String getId() { + return id; + } + public String getTitle() { + return title; + } + public String getDescription() { + return description; + } + + public URLClassLoader getLoader() { + return loader; + } + + @Override + public String toString() { + return title; + } + + public static Plugin loadPlugin(String path) throws Exception { + URL pluginURL = Plugin.class.getClassLoader().getResource(path); + ResourcePlugin plugin = new ResourcePlugin(pluginURL); + plugin.loadMetadata(); + return plugin; + } +} + diff --git a/src/main/java/com/jcloisterzone/ui/plugin/ResourcePlugin.java b/src/main/java/com/jcloisterzone/ui/plugin/ResourcePlugin.java index 0dd59e922..79c06b8ed 100644 --- a/src/main/java/com/jcloisterzone/ui/plugin/ResourcePlugin.java +++ b/src/main/java/com/jcloisterzone/ui/plugin/ResourcePlugin.java @@ -1,287 +1,287 @@ -package com.jcloisterzone.ui.plugin; - -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.Toolkit; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.io.IOException; -import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.swing.ImageIcon; -import javax.xml.parsers.ParserConfigurationException; - -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Bridge; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.Tower; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.resources.ResourceManager; -import com.jcloisterzone.ui.theme.FeatureDescriptor; -import com.jcloisterzone.ui.theme.ThemeGeometry; - -public class ResourcePlugin extends Plugin implements ResourceManager { - - public static final int NORMALIZED_SIZE = 1000; - - private static ThemeGeometry defaultGeometry; - private ThemeGeometry pluginGeometry; - - private Set supportedExpansions = new HashSet<>(); //expansion codes - - static { - try { - defaultGeometry = new ThemeGeometry(ResourcePlugin.class.getClassLoader(), "defaults"); - } catch (IOException | SAXException | ParserConfigurationException e) { - LoggerFactory.getLogger(ThemeGeometry.class).error(e.getMessage(), e); - } - } - - public ResourcePlugin(URL url) throws Exception { - super(url); - pluginGeometry = new ThemeGeometry(getLoader(), "tiles"); - } - - @Override - protected void parseMetadata(Element rootElement) throws Exception { - super.parseMetadata(rootElement); - NodeList nl = rootElement.getElementsByTagName("expansions"); - if (nl.getLength() == 0) throw new Exception("Supported expansions missing in plugin.xml for " + getId()); - Element expansion = (Element) nl.item(0); - nl = expansion.getElementsByTagName("expansion"); - if (nl.getLength() == 0) throw new Exception("No expansion is supported by " + getId()); - for (int i = 0; i < nl.getLength(); i++) { - String expName = nl.item(i).getFirstChild().getNodeValue().trim(); - Expansion exp = Expansion.valueOf(expName); - supportedExpansions.add(exp.getCode()); - } - } - - - protected Image getImageResource(String path) { - logger.debug("Trying to load image resource {}:{}", getTitle(), path); - URL url = getLoader().getResource(path); - if (url == null) return null; - return Toolkit.getDefaultToolkit().getImage(url); - } - - protected boolean containsTile(String tileId) { - String expCode = tileId.substring(0, 2); - return supportedExpansions.contains(expCode); - } - - @Override - public Image getTileImage(Tile tile) { - return getTileImage(tile.getId()); - } - - @Override - public Image getAbbeyImage() { - return getTileImage(Tile.ABBEY_TILE_ID); - } - - private Image getTileImage(String tileId) { - //return null; - if (!containsTile(tileId)) return null; - String fileName = "tiles/"+tileId.substring(0, 2) + "/" + tileId.substring(3) + ".jpg"; - Image img = getImageResource(fileName); - if (img == null) return null; - return (new ImageIcon(img)).getImage(); - } - - - @Override - public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { - if (!containsTile(tile.getId())) return null; - if (type.equals(Barn.class)) return null; - Feature piece = tile.getFeature(loc); - ImmutablePoint point = pluginGeometry.getMeeplePlacement(tile, piece.getClass(), piece.getLocation()); - if (point == null) { - point = defaultGeometry.getMeeplePlacement(tile, piece.getClass(), piece.getLocation()); - } - if (point == null) { - logger.warn("No point defined for <" + (new FeatureDescriptor(tile, piece.getClass(), loc)) + ">"); - point = new ImmutablePoint(0, 0); - } - return point; - } - - private Area getArea(Tile tile, Class featureClass, Location loc) { - Area area = pluginGeometry.getArea(tile, featureClass, loc); - if (area == null) { - area = defaultGeometry.getArea(tile, featureClass, loc); - } - if (area == null) { - logger.error("No shape defined for <" + (new FeatureDescriptor(tile, featureClass, loc)) + ">"); - area = new Area(); - } - return area; - } - - private Area getSubstractionArea(Tile tile, boolean farm) { - Area d = defaultGeometry.getSubstractionArea(tile, farm), - p = pluginGeometry.getSubstractionArea(tile, farm), - area = new Area(); - - if (d != null) area.add(d); - if (p != null) area.add(p); - return area; - } - - private boolean isFarmComplement(Tile tile, Location loc) { - if (pluginGeometry.isFarmComplement(tile, loc)) return true; - if (defaultGeometry.isFarmComplement(tile, loc)) return true; - return false; - } - - @Override - public Map getFeatureAreas(Tile tile, int size, Set locations) { - if (!containsTile(tile.getId())) return null; - - Map areas = new HashMap<>(); - Area subsBridge = getBaseRoadAndCitySubstractions(tile); - Area subsRoadCity = new Area(subsBridge); - substractBridge(subsRoadCity, tile); - Area subsFarm = getFarmSubstractions(tile); - - for (Feature piece : tile.getFeatures()) { - Location loc = piece.getLocation(); - if (!locations.contains(loc)) { - continue; - } - - if (piece instanceof Farm) { - areas.put(loc, getFarmArea(loc, tile, subsFarm)); - continue; - } - Area a = getArea(tile, piece.getClass(), loc); - if (piece instanceof City || piece instanceof Road) { - Area subs = subsRoadCity; - if (piece instanceof Bridge) { - subs = subsBridge; - } - if (!subs.isEmpty()) { - a = new Area(a); //copy to preserve original - a.subtract(subs); - } - } - areas.put(loc, a); - } - Map transformed = new HashMap<>(); - - AffineTransform transform1; - if (size == NORMALIZED_SIZE) { - transform1 = new AffineTransform(); - } else { - double ratio = size/(double)NORMALIZED_SIZE; - transform1 = AffineTransform.getScaleInstance(ratio,ratio); - } - //TODO rotation - 3 rotations are done - Location rotation, getArea and this affine - AffineTransform transform2 = tile.getRotation().getAffineTransform(size); - - for (Entry entry : areas.entrySet()) { - Area a = entry.getValue(); - a = a.createTransformedArea(transform1); - a = a.createTransformedArea(transform2); - transformed.put(entry.getKey(), a); - } - return transformed; - } - - @Override - public Map getBarnTileAreas(Tile tile, int size, Set corners) { - return null; - } - - //TODO Move to default provider ??? - public Map getBridgeAreas(Tile tile, int size, Set locations) { - Map result = new HashMap<>(); - for (Location loc : locations) { - result.put(loc, getBridgeArea(size, loc)); - } - return result; - } - - //TODO move to Area Provider ??? - private Area getBridgeArea(int size, Location loc) { - AffineTransform transform1; - if (size == NORMALIZED_SIZE) { - transform1 = new AffineTransform(); - } else { - double ratio = size/(double)NORMALIZED_SIZE; - transform1 = AffineTransform.getScaleInstance(ratio,ratio); - } - return pluginGeometry.getBridgeArea(loc).createTransformedArea(transform1); - } - - private void substractBridge(Area substractions, Tile tile) { - Bridge bridge = tile.getBridge(); - if (bridge != null) { - Area area; - area = getArea(tile, Bridge.class, bridge.getLocation()); - substractions.add(area); - } - } - - private Area getBaseRoadAndCitySubstractions(Tile tile) { - Area sub = new Area(); - if (tile.getTower() != null) { - sub.add(getArea(tile, Tower.class, Location.TOWER)); - } - sub.add(getSubstractionArea(tile, false)); - return sub; - } - - private Area getFarmSubstractions(Tile tile) { - Area sub = new Area(); - for (Feature piece : tile.getFeatures()) { - if (!(piece instanceof Farm)) { - Area area = getArea(tile, piece.getClass(), piece.getLocation()); - sub.add(area); - } - } - sub.add(getSubstractionArea(tile, true)); - return sub; - } - - - private Area getFarmArea(Location farm, Tile tile, Area sub) { - Area base; - if (isFarmComplement(tile, farm)) { //is complement farm - base = new Area(new Rectangle(0,0, NORMALIZED_SIZE, NORMALIZED_SIZE)); - for (Feature piece : tile.getFeatures()) { - if (piece instanceof Farm && piece.getLocation() != farm) { - Area area = getArea(tile, Farm.class, piece.getLocation()); - base.subtract(area); - } - } - } else { - base = getArea(tile, Farm.class, farm); - base = new Area(base); //copy area to not substract from original - } - if (!sub.isEmpty()) { - base.subtract(sub); - } - return base; - } - - - -} +package com.jcloisterzone.ui.plugin; + +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.io.IOException; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.swing.ImageIcon; +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Bridge; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.Tower; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.resources.ResourceManager; +import com.jcloisterzone.ui.theme.FeatureDescriptor; +import com.jcloisterzone.ui.theme.ThemeGeometry; + +public class ResourcePlugin extends Plugin implements ResourceManager { + + public static final int NORMALIZED_SIZE = 1000; + + private static ThemeGeometry defaultGeometry; + private ThemeGeometry pluginGeometry; + + private Set supportedExpansions = new HashSet<>(); //expansion codes + + static { + try { + defaultGeometry = new ThemeGeometry(ResourcePlugin.class.getClassLoader(), "defaults"); + } catch (IOException | SAXException | ParserConfigurationException e) { + LoggerFactory.getLogger(ThemeGeometry.class).error(e.getMessage(), e); + } + } + + public ResourcePlugin(URL url) throws Exception { + super(url); + pluginGeometry = new ThemeGeometry(getLoader(), "tiles"); + } + + @Override + protected void parseMetadata(Element rootElement) throws Exception { + super.parseMetadata(rootElement); + NodeList nl = rootElement.getElementsByTagName("expansions"); + if (nl.getLength() == 0) throw new Exception("Supported expansions missing in plugin.xml for " + getId()); + Element expansion = (Element) nl.item(0); + nl = expansion.getElementsByTagName("expansion"); + if (nl.getLength() == 0) throw new Exception("No expansion is supported by " + getId()); + for (int i = 0; i < nl.getLength(); i++) { + String expName = nl.item(i).getFirstChild().getNodeValue().trim(); + Expansion exp = Expansion.valueOf(expName); + supportedExpansions.add(exp.getCode()); + } + } + + + protected Image getImageResource(String path) { + logger.debug("Trying to load image resource {}:{}", getTitle(), path); + URL url = getLoader().getResource(path); + if (url == null) return null; + return Toolkit.getDefaultToolkit().getImage(url); + } + + protected boolean containsTile(String tileId) { + String expCode = tileId.substring(0, 2); + return supportedExpansions.contains(expCode); + } + + @Override + public Image getTileImage(Tile tile) { + return getTileImage(tile.getId()); + } + + @Override + public Image getAbbeyImage() { + return getTileImage(Tile.ABBEY_TILE_ID); + } + + private Image getTileImage(String tileId) { + //return null; + if (!containsTile(tileId)) return null; + String fileName = "tiles/"+tileId.substring(0, 2) + "/" + tileId.substring(3) + ".jpg"; + Image img = getImageResource(fileName); + if (img == null) return null; + return (new ImageIcon(img)).getImage(); + } + + + @Override + public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { + if (!containsTile(tile.getId())) return null; + if (type.equals(Barn.class)) return null; + Feature piece = tile.getFeature(loc); + ImmutablePoint point = pluginGeometry.getMeeplePlacement(tile, piece.getClass(), piece.getLocation()); + if (point == null) { + point = defaultGeometry.getMeeplePlacement(tile, piece.getClass(), piece.getLocation()); + } + if (point == null) { + logger.warn("No point defined for <" + (new FeatureDescriptor(tile, piece.getClass(), loc)) + ">"); + point = new ImmutablePoint(0, 0); + } + return point; + } + + private Area getArea(Tile tile, Class featureClass, Location loc) { + Area area = pluginGeometry.getArea(tile, featureClass, loc); + if (area == null) { + area = defaultGeometry.getArea(tile, featureClass, loc); + } + if (area == null) { + logger.error("No shape defined for <" + (new FeatureDescriptor(tile, featureClass, loc)) + ">"); + area = new Area(); + } + return area; + } + + private Area getSubstractionArea(Tile tile, boolean farm) { + Area d = defaultGeometry.getSubstractionArea(tile, farm), + p = pluginGeometry.getSubstractionArea(tile, farm), + area = new Area(); + + if (d != null) area.add(d); + if (p != null) area.add(p); + return area; + } + + private boolean isFarmComplement(Tile tile, Location loc) { + if (pluginGeometry.isFarmComplement(tile, loc)) return true; + if (defaultGeometry.isFarmComplement(tile, loc)) return true; + return false; + } + + @Override + public Map getFeatureAreas(Tile tile, int size, Set locations) { + if (!containsTile(tile.getId())) return null; + + Map areas = new HashMap<>(); + Area subsBridge = getBaseRoadAndCitySubstractions(tile); + Area subsRoadCity = new Area(subsBridge); + substractBridge(subsRoadCity, tile); + Area subsFarm = getFarmSubstractions(tile); + + for (Feature piece : tile.getFeatures()) { + Location loc = piece.getLocation(); + if (!locations.contains(loc)) { + continue; + } + + if (piece instanceof Farm) { + areas.put(loc, getFarmArea(loc, tile, subsFarm)); + continue; + } + Area a = getArea(tile, piece.getClass(), loc); + if (piece instanceof City || piece instanceof Road) { + Area subs = subsRoadCity; + if (piece instanceof Bridge) { + subs = subsBridge; + } + if (!subs.isEmpty()) { + a = new Area(a); //copy to preserve original + a.subtract(subs); + } + } + areas.put(loc, a); + } + Map transformed = new HashMap<>(); + + AffineTransform transform1; + if (size == NORMALIZED_SIZE) { + transform1 = new AffineTransform(); + } else { + double ratio = size/(double)NORMALIZED_SIZE; + transform1 = AffineTransform.getScaleInstance(ratio,ratio); + } + //TODO rotation - 3 rotations are done - Location rotation, getArea and this affine + AffineTransform transform2 = tile.getRotation().getAffineTransform(size); + + for (Entry entry : areas.entrySet()) { + Area a = entry.getValue(); + a = a.createTransformedArea(transform1); + a = a.createTransformedArea(transform2); + transformed.put(entry.getKey(), a); + } + return transformed; + } + + @Override + public Map getBarnTileAreas(Tile tile, int size, Set corners) { + return null; + } + + //TODO Move to default provider ??? + public Map getBridgeAreas(Tile tile, int size, Set locations) { + Map result = new HashMap<>(); + for (Location loc : locations) { + result.put(loc, getBridgeArea(size, loc)); + } + return result; + } + + //TODO move to Area Provider ??? + private Area getBridgeArea(int size, Location loc) { + AffineTransform transform1; + if (size == NORMALIZED_SIZE) { + transform1 = new AffineTransform(); + } else { + double ratio = size/(double)NORMALIZED_SIZE; + transform1 = AffineTransform.getScaleInstance(ratio,ratio); + } + return pluginGeometry.getBridgeArea(loc).createTransformedArea(transform1); + } + + private void substractBridge(Area substractions, Tile tile) { + Bridge bridge = tile.getBridge(); + if (bridge != null) { + Area area; + area = getArea(tile, Bridge.class, bridge.getLocation()); + substractions.add(area); + } + } + + private Area getBaseRoadAndCitySubstractions(Tile tile) { + Area sub = new Area(); + if (tile.getTower() != null) { + sub.add(getArea(tile, Tower.class, Location.TOWER)); + } + sub.add(getSubstractionArea(tile, false)); + return sub; + } + + private Area getFarmSubstractions(Tile tile) { + Area sub = new Area(); + for (Feature piece : tile.getFeatures()) { + if (!(piece instanceof Farm)) { + Area area = getArea(tile, piece.getClass(), piece.getLocation()); + sub.add(area); + } + } + sub.add(getSubstractionArea(tile, true)); + return sub; + } + + + private Area getFarmArea(Location farm, Tile tile, Area sub) { + Area base; + if (isFarmComplement(tile, farm)) { //is complement farm + base = new Area(new Rectangle(0,0, NORMALIZED_SIZE, NORMALIZED_SIZE)); + for (Feature piece : tile.getFeatures()) { + if (piece instanceof Farm && piece.getLocation() != farm) { + Area area = getArea(tile, Farm.class, piece.getLocation()); + base.subtract(area); + } + } + } else { + base = getArea(tile, Farm.class, farm); + base = new Area(base); //copy area to not substract from original + } + if (!sub.isEmpty()) { + base.subtract(sub); + } + return base; + } + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/resources/ConvenientResourceManager.java b/src/main/java/com/jcloisterzone/ui/resources/ConvenientResourceManager.java index 0b6a31d14..c97e552d3 100644 --- a/src/main/java/com/jcloisterzone/ui/resources/ConvenientResourceManager.java +++ b/src/main/java/com/jcloisterzone/ui/resources/ConvenientResourceManager.java @@ -1,81 +1,81 @@ -package com.jcloisterzone.ui.resources; - -import java.awt.Image; -import java.awt.geom.Area; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.ImmutablePoint; - -/** extends resource manager with convenient methods - * and add tile image caching - */ -public class ConvenientResourceManager implements ResourceManager { - - private final ResourceManager manager; - private final Map imageCache = new HashMap<>(); - - public ConvenientResourceManager(ResourceManager manager) { - this.manager = manager; - } - - //helper methods - - public Area getBridgeArea(Tile tile, int size, Location loc) { - Map result = manager.getBridgeAreas(tile, size, Collections.singleton(loc)); - return result.isEmpty() ? null : result.values().iterator().next(); - } - - public Area getMeepleTileArea(Tile tile, int size, Location loc) { - Map result = manager.getFeatureAreas(tile, size, Collections.singleton(loc)); - return result.isEmpty() ? null : result.values().iterator().next(); - } - - //delegate methods - - @Override - public Image getTileImage(Tile tile) { - Image img = imageCache.get(tile.getId()); - if (img == null) { - img = manager.getTileImage(tile); - imageCache.put(tile.getId(), img); - } - return img; - } - - @Override - public Image getAbbeyImage() { - Image img = imageCache.get(Tile.ABBEY_TILE_ID); - if (img == null) { - img = manager.getAbbeyImage(); - imageCache.put(Tile.ABBEY_TILE_ID, img); - } - return img; - } - - @Override - public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { - return manager.getMeeplePlacement(tile, type, loc); - } - - @Override - public Map getBarnTileAreas(Tile tile, int size, Set corners) { - return manager.getBarnTileAreas(tile, size, corners); - } - - @Override - public Map getBridgeAreas(Tile tile, int size, Set locations) { - return manager.getBridgeAreas(tile, size, locations); - } - - @Override - public Map getFeatureAreas(Tile tile, int size, Set locations) { - return manager.getFeatureAreas(tile, size, locations); - } - -} +package com.jcloisterzone.ui.resources; + +import java.awt.Image; +import java.awt.geom.Area; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.ImmutablePoint; + +/** extends resource manager with convenient methods + * and add tile image caching + */ +public class ConvenientResourceManager implements ResourceManager { + + private final ResourceManager manager; + private final Map imageCache = new HashMap<>(); + + public ConvenientResourceManager(ResourceManager manager) { + this.manager = manager; + } + + //helper methods + + public Area getBridgeArea(Tile tile, int size, Location loc) { + Map result = manager.getBridgeAreas(tile, size, Collections.singleton(loc)); + return result.isEmpty() ? null : result.values().iterator().next(); + } + + public Area getMeepleTileArea(Tile tile, int size, Location loc) { + Map result = manager.getFeatureAreas(tile, size, Collections.singleton(loc)); + return result.isEmpty() ? null : result.values().iterator().next(); + } + + //delegate methods + + @Override + public Image getTileImage(Tile tile) { + Image img = imageCache.get(tile.getId()); + if (img == null) { + img = manager.getTileImage(tile); + imageCache.put(tile.getId(), img); + } + return img; + } + + @Override + public Image getAbbeyImage() { + Image img = imageCache.get(Tile.ABBEY_TILE_ID); + if (img == null) { + img = manager.getAbbeyImage(); + imageCache.put(Tile.ABBEY_TILE_ID, img); + } + return img; + } + + @Override + public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { + return manager.getMeeplePlacement(tile, type, loc); + } + + @Override + public Map getBarnTileAreas(Tile tile, int size, Set corners) { + return manager.getBarnTileAreas(tile, size, corners); + } + + @Override + public Map getBridgeAreas(Tile tile, int size, Set locations) { + return manager.getBridgeAreas(tile, size, locations); + } + + @Override + public Map getFeatureAreas(Tile tile, int size, Set locations) { + return manager.getFeatureAreas(tile, size, locations); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/resources/DefaultResourceManager.java b/src/main/java/com/jcloisterzone/ui/resources/DefaultResourceManager.java index 41ae36410..34ec368a3 100644 --- a/src/main/java/com/jcloisterzone/ui/resources/DefaultResourceManager.java +++ b/src/main/java/com/jcloisterzone/ui/resources/DefaultResourceManager.java @@ -1,74 +1,74 @@ -package com.jcloisterzone.ui.resources; - -import java.awt.Image; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Barn; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.ImmutablePoint; - -public class DefaultResourceManager implements ResourceManager { - - - @Override - public Image getTileImage(Tile tile) { - return (new TileImageFactory()).getTileImage(tile); - } - - @Override - public Image getAbbeyImage() { - return (new TileImageFactory()).getAbbeyImage(); - } - - - private ImmutablePoint getBarnPlacement(Location loc) { - if (loc.intersect(Location.NL.union(Location.WR)) != null) return new ImmutablePoint(0, 0); - if (loc.intersect(Location.NR.union(Location.EL)) != null) return new ImmutablePoint(100, 0); - if (loc.intersect(Location.SL.union(Location.ER)) != null) return new ImmutablePoint(100, 100); - if (loc.intersect(Location.SR.union(Location.WL)) != null) return new ImmutablePoint(0, 100); - throw new IllegalArgumentException("Corner location expected"); - } - - @Override - public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { - if (type.equals(Barn.class)) { - return getBarnPlacement(loc); - } - return null; - } - - public Map getBarnTileAreas(Tile tile, int size, Set corners) { - Map result = new HashMap<>(); - for (Location corner : corners) { - int r = size/2; - Area a = new Area(new Ellipse2D.Double(-r,-r,2*r,2*r)); - if (corner.isPartOf(Location.NR.union(Location.EL))) a.transform(Rotation.R90.getAffineTransform(size)); - if (corner.isPartOf(Location.SL.union(Location.ER))) a.transform(Rotation.R180.getAffineTransform(size)); - if (corner.isPartOf(Location.SR.union(Location.WL))) a.transform(Rotation.R270.getAffineTransform(size)); - result.put(corner, a); - } - return result; - } - - - @Override - public Map getBridgeAreas(Tile tile, int size, Set locations) { - return null; - } - - @Override - public Map getFeatureAreas(Tile tile, int size, - Set locations) { - return null; - } - - - -} +package com.jcloisterzone.ui.resources; + +import java.awt.Image; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Barn; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.ImmutablePoint; + +public class DefaultResourceManager implements ResourceManager { + + + @Override + public Image getTileImage(Tile tile) { + return (new TileImageFactory()).getTileImage(tile); + } + + @Override + public Image getAbbeyImage() { + return (new TileImageFactory()).getAbbeyImage(); + } + + + private ImmutablePoint getBarnPlacement(Location loc) { + if (loc.intersect(Location.NL.union(Location.WR)) != null) return new ImmutablePoint(0, 0); + if (loc.intersect(Location.NR.union(Location.EL)) != null) return new ImmutablePoint(100, 0); + if (loc.intersect(Location.SL.union(Location.ER)) != null) return new ImmutablePoint(100, 100); + if (loc.intersect(Location.SR.union(Location.WL)) != null) return new ImmutablePoint(0, 100); + throw new IllegalArgumentException("Corner location expected"); + } + + @Override + public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { + if (type.equals(Barn.class)) { + return getBarnPlacement(loc); + } + return null; + } + + public Map getBarnTileAreas(Tile tile, int size, Set corners) { + Map result = new HashMap<>(); + for (Location corner : corners) { + int r = size/2; + Area a = new Area(new Ellipse2D.Double(-r,-r,2*r,2*r)); + if (corner.isPartOf(Location.NR.union(Location.EL))) a.transform(Rotation.R90.getAffineTransform(size)); + if (corner.isPartOf(Location.SL.union(Location.ER))) a.transform(Rotation.R180.getAffineTransform(size)); + if (corner.isPartOf(Location.SR.union(Location.WL))) a.transform(Rotation.R270.getAffineTransform(size)); + result.put(corner, a); + } + return result; + } + + + @Override + public Map getBridgeAreas(Tile tile, int size, Set locations) { + return null; + } + + @Override + public Map getFeatureAreas(Tile tile, int size, + Set locations) { + return null; + } + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/resources/PlugableResourceManager.java b/src/main/java/com/jcloisterzone/ui/resources/PlugableResourceManager.java index 61ebea225..ed5a4b708 100644 --- a/src/main/java/com/jcloisterzone/ui/resources/PlugableResourceManager.java +++ b/src/main/java/com/jcloisterzone/ui/resources/PlugableResourceManager.java @@ -1,100 +1,100 @@ -package com.jcloisterzone.ui.resources; - -import java.awt.Image; -import java.awt.geom.Area; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.plugin.Plugin; - -/** - * Delegates requests to child plugins - */ -public class PlugableResourceManager implements ResourceManager { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final Client client; - private final List managers; - - - public PlugableResourceManager(Client client, List plugins) { - this.client = client; - managers = new ArrayList<>(); - - for (Plugin p: plugins) { - if (p instanceof ResourceManager) { - managers.add((ResourceManager) p); - } - } - - managers.add(new DefaultResourceManager()); - } - - @Override - public Image getTileImage(Tile tile) { - for (ResourceManager manager : managers) { - Image result = manager.getTileImage(tile); - if (result != null) return result; - } - return null; - } - - @Override - public Image getAbbeyImage() { - for (ResourceManager manager : managers) { - Image result = manager.getAbbeyImage(); - if (result != null) return result; - } - return null; - } - - - @Override - public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { - for (ResourceManager manager : managers) { - ImmutablePoint result = manager.getMeeplePlacement(tile, type, loc); - if (result != null) return result; - } - return null; - } - - @Override - public Map getBarnTileAreas(Tile tile, int size, Set corners) { - for (ResourceManager manager : managers) { - Map result = manager.getBarnTileAreas(tile, size, corners); - if (result != null) return result; - } - return null; - } - - @Override - public Map getBridgeAreas(Tile tile, int size, Set locations) { - for (ResourceManager manager : managers) { - Map result = manager.getBridgeAreas(tile, size, locations); - if (result != null) return result; - } - return null; - } - - - @Override - public Map getFeatureAreas(Tile tile, int size, Set locations) { - for (ResourceManager manager : managers) { - Map result = manager.getFeatureAreas(tile, size, locations); - if (result != null) return result; - } - return null; - } - -} +package com.jcloisterzone.ui.resources; + +import java.awt.Image; +import java.awt.geom.Area; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.plugin.Plugin; + +/** + * Delegates requests to child plugins + */ +public class PlugableResourceManager implements ResourceManager { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final Client client; + private final List managers; + + + public PlugableResourceManager(Client client, List plugins) { + this.client = client; + managers = new ArrayList<>(); + + for (Plugin p: plugins) { + if (p instanceof ResourceManager) { + managers.add((ResourceManager) p); + } + } + + managers.add(new DefaultResourceManager()); + } + + @Override + public Image getTileImage(Tile tile) { + for (ResourceManager manager : managers) { + Image result = manager.getTileImage(tile); + if (result != null) return result; + } + return null; + } + + @Override + public Image getAbbeyImage() { + for (ResourceManager manager : managers) { + Image result = manager.getAbbeyImage(); + if (result != null) return result; + } + return null; + } + + + @Override + public ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc) { + for (ResourceManager manager : managers) { + ImmutablePoint result = manager.getMeeplePlacement(tile, type, loc); + if (result != null) return result; + } + return null; + } + + @Override + public Map getBarnTileAreas(Tile tile, int size, Set corners) { + for (ResourceManager manager : managers) { + Map result = manager.getBarnTileAreas(tile, size, corners); + if (result != null) return result; + } + return null; + } + + @Override + public Map getBridgeAreas(Tile tile, int size, Set locations) { + for (ResourceManager manager : managers) { + Map result = manager.getBridgeAreas(tile, size, locations); + if (result != null) return result; + } + return null; + } + + + @Override + public Map getFeatureAreas(Tile tile, int size, Set locations) { + for (ResourceManager manager : managers) { + Map result = manager.getFeatureAreas(tile, size, locations); + if (result != null) return result; + } + return null; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/resources/ResourceManager.java b/src/main/java/com/jcloisterzone/ui/resources/ResourceManager.java index aa24808fa..f683047b1 100644 --- a/src/main/java/com/jcloisterzone/ui/resources/ResourceManager.java +++ b/src/main/java/com/jcloisterzone/ui/resources/ResourceManager.java @@ -1,32 +1,32 @@ -package com.jcloisterzone.ui.resources; - -import java.awt.Image; -import java.awt.geom.Area; -import java.util.Map; -import java.util.Set; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.ImmutablePoint; - -public interface ResourceManager { - - Image getTileImage(Tile tile); - Image getAbbeyImage(); - - Map getFeatureAreas(Tile tile, int size, Set locations); - Map getBarnTileAreas(Tile tile, int size, Set corners); - Map getBridgeAreas(Tile tile, int size, Set locations); - - //TODO change to 1000x1000 - /** returns meeple offset on tile, normalized to 100x100 tile size */ - ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc); - - - - - - - -} +package com.jcloisterzone.ui.resources; + +import java.awt.Image; +import java.awt.geom.Area; +import java.util.Map; +import java.util.Set; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.ImmutablePoint; + +public interface ResourceManager { + + Image getTileImage(Tile tile); + Image getAbbeyImage(); + + Map getFeatureAreas(Tile tile, int size, Set locations); + Map getBarnTileAreas(Tile tile, int size, Set corners); + Map getBridgeAreas(Tile tile, int size, Set locations); + + //TODO change to 1000x1000 + /** returns meeple offset on tile, normalized to 100x100 tile size */ + ImmutablePoint getMeeplePlacement(Tile tile, Class type, Location loc); + + + + + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/resources/TileImageFactory.java b/src/main/java/com/jcloisterzone/ui/resources/TileImageFactory.java index 6e7a72c1b..3aaebb099 100644 --- a/src/main/java/com/jcloisterzone/ui/resources/TileImageFactory.java +++ b/src/main/java/com/jcloisterzone/ui/resources/TileImageFactory.java @@ -1,87 +1,87 @@ -package com.jcloisterzone.ui.resources; - -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.image.BufferedImage; -import java.net.URL; -import java.net.URLClassLoader; - -import javax.swing.ImageIcon; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.ui.plugin.Plugin; - -public class TileImageFactory { - - private URLClassLoader loader; - - private static final int SIZE = 300; - - private Location[] BASE_ROTATIONS = new Location[] { - Location.N, - Location.NW, - Location.WE, - Location._N, - Location.NWSE, - Location.CLOISTER, - Location.TOWER - }; - - public TileImageFactory() { - //debug - TODO make plugin from this - try { - URL url = Plugin.class.getClassLoader().getResource("plugins/fallback"); - url = new URL(url.toString()+"/"); - loader = new URLClassLoader(new URL[] { url }); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public URLClassLoader getLoader() { - return loader; - } - - protected Image getImageResource(String path) { - Image img = Toolkit.getDefaultToolkit().getImage(getLoader().getResource(path)); - return (new ImageIcon(img)).getImage(); - } - - //------------ - - public Image getTileImage(Tile tile) { - BufferedImage img = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2 = img.createGraphics(); - - g2.drawImage(getImageResource("tiles/bg.png"), 0, 0, null); - - for (Feature f : tile.getFeatures()) { - if (f instanceof Farm) continue; - drawFeature(g2, f); - } - return img; - } - - private void drawFeature(Graphics2D g2, Feature feature) { - Location loc = feature.getRawLocation(); - //System.out.println(feature + " / " + loc); - for (Location base : BASE_ROTATIONS) { - Rotation rot = loc.getRotationOf(base); - if (rot != null) { - String path = feature.getClass().getSimpleName().toLowerCase(); - Image img = getImageResource("tiles/"+path+"/"+base.toString()+".png"); - g2.drawImage(img, rot.getAffineTransform(SIZE), null); - break; - } - } - } - - public Image getAbbeyImage() { - return null; - } -} +package com.jcloisterzone.ui.resources; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.net.URL; +import java.net.URLClassLoader; + +import javax.swing.ImageIcon; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.ui.plugin.Plugin; + +public class TileImageFactory { + + private URLClassLoader loader; + + private static final int SIZE = 300; + + private Location[] BASE_ROTATIONS = new Location[] { + Location.N, + Location.NW, + Location.WE, + Location._N, + Location.NWSE, + Location.CLOISTER, + Location.TOWER + }; + + public TileImageFactory() { + //debug - TODO make plugin from this + try { + URL url = Plugin.class.getClassLoader().getResource("plugins/fallback"); + url = new URL(url.toString()+"/"); + loader = new URLClassLoader(new URL[] { url }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public URLClassLoader getLoader() { + return loader; + } + + protected Image getImageResource(String path) { + Image img = Toolkit.getDefaultToolkit().getImage(getLoader().getResource(path)); + return (new ImageIcon(img)).getImage(); + } + + //------------ + + public Image getTileImage(Tile tile) { + BufferedImage img = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = img.createGraphics(); + + g2.drawImage(getImageResource("tiles/bg.png"), 0, 0, null); + + for (Feature f : tile.getFeatures()) { + if (f instanceof Farm) continue; + drawFeature(g2, f); + } + return img; + } + + private void drawFeature(Graphics2D g2, Feature feature) { + Location loc = feature.getRawLocation(); + //System.out.println(feature + " / " + loc); + for (Location base : BASE_ROTATIONS) { + Rotation rot = loc.getRotationOf(base); + if (rot != null) { + String path = feature.getClass().getSimpleName().toLowerCase(); + Image img = getImageResource("tiles/"+path+"/"+base.toString()+".png"); + g2.drawImage(img, rot.getAffineTransform(SIZE), null); + break; + } + } + } + + public Image getAbbeyImage() { + return null; + } +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/ControlsTheme.java b/src/main/java/com/jcloisterzone/ui/theme/ControlsTheme.java index 992a0ec52..bb085695c 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/ControlsTheme.java +++ b/src/main/java/com/jcloisterzone/ui/theme/ControlsTheme.java @@ -1,18 +1,18 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.Image; - -import com.jcloisterzone.ui.Client; - -public class ControlsTheme extends Theme { - - public ControlsTheme(Client client) { - super("theme-controls", client); - } - - public Image getActionDecoration(String name) { - return getImage("action-decorations/" + name + ".png"); - } - - -} +package com.jcloisterzone.ui.theme; + +import java.awt.Image; + +import com.jcloisterzone.ui.Client; + +public class ControlsTheme extends Theme { + + public ControlsTheme(Client client) { + super("theme-controls", client); + } + + public Image getActionDecoration(String name) { + return getImage("action-decorations/" + name + ".png"); + } + + +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/FeatureDescriptor.java b/src/main/java/com/jcloisterzone/ui/theme/FeatureDescriptor.java index c8eae040d..3d05f9482 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/FeatureDescriptor.java +++ b/src/main/java/com/jcloisterzone/ui/theme/FeatureDescriptor.java @@ -1,115 +1,115 @@ -package com.jcloisterzone.ui.theme; - -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Bridge; -import com.jcloisterzone.feature.Castle; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Cloister; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.feature.Road; -import com.jcloisterzone.feature.Tower; - -public class FeatureDescriptor { - - public static final String EVERY = "*"; - - private final String tileId; - private final Class featureType; - private final Location location; - - public FeatureDescriptor(String tileId, Class featureType, Location location) { - this.tileId = tileId; - this.featureType = featureType; - this.location = location; - } - - public FeatureDescriptor(Tile tile, Class featureType, Location location) { - this(tile.getId(), featureType, location); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(tileId).append(' '); - sb.append(featureType.getSimpleName().toUpperCase()).append(' '); - sb.append(location.toString()); - return sb.toString(); - } - - public static FeatureDescriptor valueOf(String descriptor) { - String[] tokens = descriptor.split(" "); - return FeatureDescriptor.valueOf(tokens[0], tokens[1], tokens[2]); - } - - public static FeatureDescriptor valueOf(String tileId, String featureName, String locationName) { - Class featureType; - switch (featureName) { - case "ROAD": featureType = Road.class; break; - case "CITY": featureType = City.class; break; - case "FARM": featureType = Farm.class; break; - case "CLOISTER": featureType = Cloister.class; break; - case "TOWER": featureType = Tower.class; break; - case "CASTLE": featureType = Castle.class; break; - case "BRIDGE": featureType = Bridge.class; break; - default: throw new IllegalArgumentException("Unsupported feature "+featureName); - } - Location location = Location.valueOf(locationName); - assert location.isFarmLocation() ^ !featureType.equals(Farm.class) : "improper location "+locationName; - return new FeatureDescriptor(tileId, featureType, location); - } - - public String getTileId() { - return tileId; - } - - public Class getFeatureType() { - return featureType; - } - - public Location getLocation() { - return location; - } - - @Override - public int hashCode() { - int result = 1; - result = 31 * result + featureType.toString().hashCode(); - result = 31 * result + location.hashCode(); - result = 31 * result + tileId.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (!(obj instanceof FeatureDescriptor)) - return false; - FeatureDescriptor other = (FeatureDescriptor) obj; - if (featureType == null) { - if (other.featureType != null) - return false; - } else if (!featureType.equals(other.featureType)) - return false; - if (location == null) { - if (other.location != null) - return false; - } else if (!location.equals(other.location)) - return false; - if (tileId == null) { - if (other.tileId != null) - return false; - } else if (!tileId.equals(other.tileId)) - return false; - return true; - } - - - - - -} +package com.jcloisterzone.ui.theme; + +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Bridge; +import com.jcloisterzone.feature.Castle; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Cloister; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.feature.Road; +import com.jcloisterzone.feature.Tower; + +public class FeatureDescriptor { + + public static final String EVERY = "*"; + + private final String tileId; + private final Class featureType; + private final Location location; + + public FeatureDescriptor(String tileId, Class featureType, Location location) { + this.tileId = tileId; + this.featureType = featureType; + this.location = location; + } + + public FeatureDescriptor(Tile tile, Class featureType, Location location) { + this(tile.getId(), featureType, location); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(tileId).append(' '); + sb.append(featureType.getSimpleName().toUpperCase()).append(' '); + sb.append(location.toString()); + return sb.toString(); + } + + public static FeatureDescriptor valueOf(String descriptor) { + String[] tokens = descriptor.split(" "); + return FeatureDescriptor.valueOf(tokens[0], tokens[1], tokens[2]); + } + + public static FeatureDescriptor valueOf(String tileId, String featureName, String locationName) { + Class featureType; + switch (featureName) { + case "ROAD": featureType = Road.class; break; + case "CITY": featureType = City.class; break; + case "FARM": featureType = Farm.class; break; + case "CLOISTER": featureType = Cloister.class; break; + case "TOWER": featureType = Tower.class; break; + case "CASTLE": featureType = Castle.class; break; + case "BRIDGE": featureType = Bridge.class; break; + default: throw new IllegalArgumentException("Unsupported feature "+featureName); + } + Location location = Location.valueOf(locationName); + assert location.isFarmLocation() ^ !featureType.equals(Farm.class) : "improper location "+locationName; + return new FeatureDescriptor(tileId, featureType, location); + } + + public String getTileId() { + return tileId; + } + + public Class getFeatureType() { + return featureType; + } + + public Location getLocation() { + return location; + } + + @Override + public int hashCode() { + int result = 1; + result = 31 * result + featureType.toString().hashCode(); + result = 31 * result + location.hashCode(); + result = 31 * result + tileId.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof FeatureDescriptor)) + return false; + FeatureDescriptor other = (FeatureDescriptor) obj; + if (featureType == null) { + if (other.featureType != null) + return false; + } else if (!featureType.equals(other.featureType)) + return false; + if (location == null) { + if (other.location != null) + return false; + } else if (!location.equals(other.location)) + return false; + if (tileId == null) { + if (other.tileId != null) + return false; + } else if (!tileId.equals(other.tileId)) + return false; + return true; + } + + + + + +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/FigureTheme.java b/src/main/java/com/jcloisterzone/ui/theme/FigureTheme.java index e87b7ea93..a97acf3eb 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/FigureTheme.java +++ b/src/main/java/com/jcloisterzone/ui/theme/FigureTheme.java @@ -1,64 +1,64 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.Color; -import java.awt.Image; -import java.net.URL; -import java.util.Collections; - -import com.google.common.collect.Iterables; -import com.jcloisterzone.action.PlayerAction; -import com.jcloisterzone.figure.Meeple; -import com.jcloisterzone.ui.Client; - -public class FigureTheme extends Theme { - - public FigureTheme(Client client) { - super("theme-figures", client); - } - - public Image getActionImage(PlayerAction action, Color color) { - return getLayeredImage("actions/" + action.getName(), color); - } - - public Image getNeutralImage(String name) { - return getLayeredImage("neutral/" + name, null); - } - - public Image getFigureImage(Meeple m, Color c) { - return getFigureImage(m.getClass(), c, null); - } - - public Image getFigureImage(Class type, Color c, String extraDecoration) { - String name = type.getSimpleName().toLowerCase(); - return getFigureImage("player-meeples/" + name, c, extraDecoration, null); - } - - public Image getTunnelImage(Color c) { - return getFigureImage("player-meeples/tunnel" , c, null, null); - } - - public Image getPlayerSlotImage(String name, Color c) { - return getFigureImage("player-slot/" + name, c, null, 60); - } - - private Image getFigureImage(String name, Color c, String extraDecoration, Integer fixedSize) { - String key = name + '#' + c.getRGB() + '#' + extraDecoration; - Image image = getImageCache().get(name); - if (image == null) { - Iterable layers = getResourceLayers(name); - if (extraDecoration != null) { - URL url = getResource("player-meeples/decorations/" + extraDecoration); - layers = Iterables.concat(layers, Collections.singletonList(url)); - } - image = composeImages(layers, c); - if (fixedSize != null) { - image = image.getScaledInstance(fixedSize, fixedSize, Image.SCALE_SMOOTH); - } - - getImageCache().put(key, image); - } - return image; - - } - -} +package com.jcloisterzone.ui.theme; + +import java.awt.Color; +import java.awt.Image; +import java.net.URL; +import java.util.Collections; + +import com.google.common.collect.Iterables; +import com.jcloisterzone.action.PlayerAction; +import com.jcloisterzone.figure.Meeple; +import com.jcloisterzone.ui.Client; + +public class FigureTheme extends Theme { + + public FigureTheme(Client client) { + super("theme-figures", client); + } + + public Image getActionImage(PlayerAction action, Color color) { + return getLayeredImage("actions/" + action.getName(), color); + } + + public Image getNeutralImage(String name) { + return getLayeredImage("neutral/" + name, null); + } + + public Image getFigureImage(Meeple m, Color c) { + return getFigureImage(m.getClass(), c, null); + } + + public Image getFigureImage(Class type, Color c, String extraDecoration) { + String name = type.getSimpleName().toLowerCase(); + return getFigureImage("player-meeples/" + name, c, extraDecoration, null); + } + + public Image getTunnelImage(Color c) { + return getFigureImage("player-meeples/tunnel" , c, null, null); + } + + public Image getPlayerSlotImage(String name, Color c) { + return getFigureImage("player-slot/" + name, c, null, 60); + } + + private Image getFigureImage(String name, Color c, String extraDecoration, Integer fixedSize) { + String key = name + '#' + c.getRGB() + '#' + extraDecoration; + Image image = getImageCache().get(name); + if (image == null) { + Iterable layers = getResourceLayers(name); + if (extraDecoration != null) { + URL url = getResource("player-meeples/decorations/" + extraDecoration); + layers = Iterables.concat(layers, Collections.singletonList(url)); + } + image = composeImages(layers, c); + if (fixedSize != null) { + image = image.getScaledInstance(fixedSize, fixedSize, Image.SCALE_SMOOTH); + } + + getImageCache().put(key, image); + } + return image; + + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/PointsParser.java b/src/main/java/com/jcloisterzone/ui/theme/PointsParser.java index 389990a2d..a4348efbd 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/PointsParser.java +++ b/src/main/java/com/jcloisterzone/ui/theme/PointsParser.java @@ -1,74 +1,74 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.Point; -import java.awt.geom.AffineTransform; -import java.io.IOException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.theme.SvgTransformationCollector.GeometryHandler; - -class PointsParser { - final URL resource; - private Map points; - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - public PointsParser(URL resource) { - this.resource = resource; - } - - private void processPointElement(Element pointNode) { - int cx = Integer.parseInt(pointNode.getAttribute("cx")); - int cy = Integer.parseInt(pointNode.getAttribute("cy")); - final Point destPoint = new Point(), srcPoint = new Point(cx, cy); - - SvgTransformationCollector transformCollector = new SvgTransformationCollector(pointNode); - transformCollector.collect(new GeometryHandler() { - - @Override - public void processApply(Element node, FeatureDescriptor fd, AffineTransform transform) { - assert !points.containsKey(fd) : fd + " already defined"; - transform.transform(srcPoint, destPoint); - //TODO use 1000-pixel standard - points.put(fd, new ImmutablePoint(destPoint.x/10, destPoint.y/10)); - } - - @Override - public void processSubstract(Element node, String tileId, AffineTransform transform, boolean isFarm) { - throw new UnsupportedOperationException(" not allowed for points.xml"); - } - - }); - } - - public Map parse() { - try { - return doParse(); - } catch (IOException | SAXException | ParserConfigurationException e) { - logger.error(e.getMessage(), e); - return new HashMap<>(); - } - } - - private Map doParse() throws IOException, SAXException, ParserConfigurationException { - Element root = XmlUtils.parseDocument(resource).getDocumentElement(); - NodeList nl = root.getElementsByTagName("point"); - points = new HashMap<>(); - for (int i = 0; i < nl.getLength(); i++) { - processPointElement((Element) nl.item(i)); - } - return points; - } +package com.jcloisterzone.ui.theme; + +import java.awt.Point; +import java.awt.geom.AffineTransform; +import java.io.IOException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.theme.SvgTransformationCollector.GeometryHandler; + +class PointsParser { + final URL resource; + private Map points; + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + public PointsParser(URL resource) { + this.resource = resource; + } + + private void processPointElement(Element pointNode) { + int cx = Integer.parseInt(pointNode.getAttribute("cx")); + int cy = Integer.parseInt(pointNode.getAttribute("cy")); + final Point destPoint = new Point(), srcPoint = new Point(cx, cy); + + SvgTransformationCollector transformCollector = new SvgTransformationCollector(pointNode); + transformCollector.collect(new GeometryHandler() { + + @Override + public void processApply(Element node, FeatureDescriptor fd, AffineTransform transform) { + assert !points.containsKey(fd) : fd + " already defined"; + transform.transform(srcPoint, destPoint); + //TODO use 1000-pixel standard + points.put(fd, new ImmutablePoint(destPoint.x/10, destPoint.y/10)); + } + + @Override + public void processSubstract(Element node, String tileId, AffineTransform transform, boolean isFarm) { + throw new UnsupportedOperationException(" not allowed for points.xml"); + } + + }); + } + + public Map parse() { + try { + return doParse(); + } catch (IOException | SAXException | ParserConfigurationException e) { + logger.error(e.getMessage(), e); + return new HashMap<>(); + } + } + + private Map doParse() throws IOException, SAXException, ParserConfigurationException { + Element root = XmlUtils.parseDocument(resource).getDocumentElement(); + NodeList nl = root.getElementsByTagName("point"); + points = new HashMap<>(); + for (int i = 0; i < nl.getLength(); i++) { + processPointElement((Element) nl.item(i)); + } + return points; + } } \ No newline at end of file diff --git a/src/main/java/com/jcloisterzone/ui/theme/SvgToShapeConverter.java b/src/main/java/com/jcloisterzone/ui/theme/SvgToShapeConverter.java index c59af822b..7dd3e9a52 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/SvgToShapeConverter.java +++ b/src/main/java/com/jcloisterzone/ui/theme/SvgToShapeConverter.java @@ -1,61 +1,61 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; - -import org.w3c.dom.Element; - -public class SvgToShapeConverter { - - public Area convert(Element shapeSvgNode) { - Shape s; - switch (shapeSvgNode.getNodeName()) { - case "svg:polygon": - s = createPolygon(shapeSvgNode); - break; - case "svg:rect": - s = createRectangle(shapeSvgNode); - break; - case "svg:circle": - s = createCircle(shapeSvgNode); - break; - default: - throw new IllegalArgumentException("Unable to convert "+shapeSvgNode.getNodeName()); - } - return new Area(s); - } - -// public Area convert(Element shapeSvgNode, AffineTransform transform) { -// Area area = convert(shapeSvgNode); -// return area.createTransformedArea(transform); -// } - - private Rectangle createRectangle(Element shapeSvgNode) { - int x = Integer.valueOf(shapeSvgNode.getAttribute("x")); - int y = Integer.valueOf(shapeSvgNode.getAttribute("y")); - int width = Integer.valueOf(shapeSvgNode.getAttribute("width")); - int heigh = Integer.valueOf(shapeSvgNode.getAttribute("height")); - return new Rectangle(x, y, width, heigh); - } - - private Ellipse2D.Double createCircle(Element shapeSvgNode) { - int x, y, r; - x = Integer.parseInt(shapeSvgNode.getAttribute("cx")); - y = Integer.parseInt(shapeSvgNode.getAttribute("cy")); - r = Integer.parseInt(shapeSvgNode.getAttribute("r")); - return new Ellipse2D.Double(x-r,y-r,2*r,2*r); - } - - private Polygon createPolygon(Element shapeSvgNode) { - Polygon p = new Polygon(); - String[] points = shapeSvgNode.getAttribute("points").split(" "); - for (int i = 0; i < points.length; i++) { - String[] xy = points[i].split(","); - p.addPoint(Integer.valueOf(xy[0]), Integer.valueOf(xy[1])); - } - return p; - } -} +package com.jcloisterzone.ui.theme; + +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; + +import org.w3c.dom.Element; + +public class SvgToShapeConverter { + + public Area convert(Element shapeSvgNode) { + Shape s; + switch (shapeSvgNode.getNodeName()) { + case "svg:polygon": + s = createPolygon(shapeSvgNode); + break; + case "svg:rect": + s = createRectangle(shapeSvgNode); + break; + case "svg:circle": + s = createCircle(shapeSvgNode); + break; + default: + throw new IllegalArgumentException("Unable to convert "+shapeSvgNode.getNodeName()); + } + return new Area(s); + } + +// public Area convert(Element shapeSvgNode, AffineTransform transform) { +// Area area = convert(shapeSvgNode); +// return area.createTransformedArea(transform); +// } + + private Rectangle createRectangle(Element shapeSvgNode) { + int x = Integer.valueOf(shapeSvgNode.getAttribute("x")); + int y = Integer.valueOf(shapeSvgNode.getAttribute("y")); + int width = Integer.valueOf(shapeSvgNode.getAttribute("width")); + int heigh = Integer.valueOf(shapeSvgNode.getAttribute("height")); + return new Rectangle(x, y, width, heigh); + } + + private Ellipse2D.Double createCircle(Element shapeSvgNode) { + int x, y, r; + x = Integer.parseInt(shapeSvgNode.getAttribute("cx")); + y = Integer.parseInt(shapeSvgNode.getAttribute("cy")); + r = Integer.parseInt(shapeSvgNode.getAttribute("r")); + return new Ellipse2D.Double(x-r,y-r,2*r,2*r); + } + + private Polygon createPolygon(Element shapeSvgNode) { + Polygon p = new Polygon(); + String[] points = shapeSvgNode.getAttribute("points").split(" "); + for (int i = 0; i < points.length; i++) { + String[] xy = points[i].split(","); + p.addPoint(Integer.valueOf(xy[0]), Integer.valueOf(xy[1])); + } + return p; + } +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/SvgTransformationCollector.java b/src/main/java/com/jcloisterzone/ui/theme/SvgTransformationCollector.java index 36a848afe..1317fec1e 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/SvgTransformationCollector.java +++ b/src/main/java/com/jcloisterzone/ui/theme/SvgTransformationCollector.java @@ -1,113 +1,113 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.geom.AffineTransform; -import java.util.ArrayDeque; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.ui.plugin.ResourcePlugin; - -public class SvgTransformationCollector { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final Element root; - - private final Location baseLocation; - - private ArrayDeque transforms = new ArrayDeque<>(); - - public SvgTransformationCollector(Element root) { - this.root = root; - if (root.hasAttribute("baseLocation")) { - baseLocation = Location.valueOf(root.getAttribute("baseLocation")); - } else { - baseLocation = null; - } - } - - public void collect(GeometryHandler handler) { - try { - collect(root, handler); - } catch (Exception ex) { - logger.error("Invalid geometry definition:\n" + XmlUtils.nodeToString(root), ex); - } - } - - private void collect(Element parent, GeometryHandler handler) { - NodeList nl = parent.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - if (!(nl.item(i) instanceof Element)) continue; - Element child = (Element) nl.item(i); - boolean hasTransform = child.hasAttribute("svg:transform"); - if (hasTransform) { - transforms.push(createTransformation(child.getAttribute("svg:transform"))); - } - switch (child.getNodeName()) { - case "apply": - String[] tokens = child.getTextContent().split(" "); - FeatureDescriptor fd = FeatureDescriptor.valueOf(tokens[0], root.getAttribute("feature"), tokens[1]); - AffineTransform af = getTransform(); - if (baseLocation != null) { - Rotation rotate = fd.getLocation().getRotationOf(baseLocation); - af.concatenate(rotate.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); - } - handler.processApply(child, fd, af); - if (XmlUtils.attributeBoolValue(child, "allRotations")) { - Rotation rot = Rotation.R90; - for (int ri = 0; ri < 3; ri++) { - Location rotatedLoc = fd.getLocation().rotateCW(rot); - FeatureDescriptor rotatedFd = new FeatureDescriptor(fd.getTileId(), fd.getFeatureType(), rotatedLoc); - af.concatenate(Rotation.R90.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); - handler.processApply(child, rotatedFd, af); - rot = rot.next(); - } - } - break; - case "substract": - assert baseLocation == null : "baseLocation is not allowed together with substraction element"; - String feature = root.getAttribute("feature"); - assert feature.equals("") || feature.equals("FARM") : "Substraction area can be declared only generic or for FARM"; - handler.processSubstract(child, child.getTextContent(), getTransform(), feature.equals("FARM")); - break; - case "g": - assert baseLocation == null; - collect(child, handler); - break; - } - if (hasTransform) { - transforms.pop(); - } - } - } - - private AffineTransform getTransform() { - AffineTransform af = new AffineTransform(); - for (AffineTransform item : transforms) { - af.concatenate(item); - } - return af; - } - - private AffineTransform createTransformation(String svg) { - switch (svg) { - case "rotate(90 500 500)": return AffineTransform.getRotateInstance(Math.PI * 0.5, 500, 500); - case "rotate(180 500 500)": return AffineTransform.getRotateInstance(Math.PI, 500, 500); - case "rotate(270 500 500)": return AffineTransform.getRotateInstance(Math.PI * 1.5, 500, 500); - default: throw new IllegalArgumentException("Unsupported transform: "+svg); - } - } - - - public interface GeometryHandler { - public void processApply(Element node, FeatureDescriptor fd, AffineTransform transform); - public void processSubstract(Element node, String tileId, AffineTransform transform, boolean isFarm); - } - -} +package com.jcloisterzone.ui.theme; + +import java.awt.geom.AffineTransform; +import java.util.ArrayDeque; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.ui.plugin.ResourcePlugin; + +public class SvgTransformationCollector { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final Element root; + + private final Location baseLocation; + + private ArrayDeque transforms = new ArrayDeque<>(); + + public SvgTransformationCollector(Element root) { + this.root = root; + if (root.hasAttribute("baseLocation")) { + baseLocation = Location.valueOf(root.getAttribute("baseLocation")); + } else { + baseLocation = null; + } + } + + public void collect(GeometryHandler handler) { + try { + collect(root, handler); + } catch (Exception ex) { + logger.error("Invalid geometry definition:\n" + XmlUtils.nodeToString(root), ex); + } + } + + private void collect(Element parent, GeometryHandler handler) { + NodeList nl = parent.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + if (!(nl.item(i) instanceof Element)) continue; + Element child = (Element) nl.item(i); + boolean hasTransform = child.hasAttribute("svg:transform"); + if (hasTransform) { + transforms.push(createTransformation(child.getAttribute("svg:transform"))); + } + switch (child.getNodeName()) { + case "apply": + String[] tokens = child.getTextContent().split(" "); + FeatureDescriptor fd = FeatureDescriptor.valueOf(tokens[0], root.getAttribute("feature"), tokens[1]); + AffineTransform af = getTransform(); + if (baseLocation != null) { + Rotation rotate = fd.getLocation().getRotationOf(baseLocation); + af.concatenate(rotate.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); + } + handler.processApply(child, fd, af); + if (XmlUtils.attributeBoolValue(child, "allRotations")) { + Rotation rot = Rotation.R90; + for (int ri = 0; ri < 3; ri++) { + Location rotatedLoc = fd.getLocation().rotateCW(rot); + FeatureDescriptor rotatedFd = new FeatureDescriptor(fd.getTileId(), fd.getFeatureType(), rotatedLoc); + af.concatenate(Rotation.R90.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); + handler.processApply(child, rotatedFd, af); + rot = rot.next(); + } + } + break; + case "substract": + assert baseLocation == null : "baseLocation is not allowed together with substraction element"; + String feature = root.getAttribute("feature"); + assert feature.equals("") || feature.equals("FARM") : "Substraction area can be declared only generic or for FARM"; + handler.processSubstract(child, child.getTextContent(), getTransform(), feature.equals("FARM")); + break; + case "g": + assert baseLocation == null; + collect(child, handler); + break; + } + if (hasTransform) { + transforms.pop(); + } + } + } + + private AffineTransform getTransform() { + AffineTransform af = new AffineTransform(); + for (AffineTransform item : transforms) { + af.concatenate(item); + } + return af; + } + + private AffineTransform createTransformation(String svg) { + switch (svg) { + case "rotate(90 500 500)": return AffineTransform.getRotateInstance(Math.PI * 0.5, 500, 500); + case "rotate(180 500 500)": return AffineTransform.getRotateInstance(Math.PI, 500, 500); + case "rotate(270 500 500)": return AffineTransform.getRotateInstance(Math.PI * 1.5, 500, 500); + default: throw new IllegalArgumentException("Unsupported transform: "+svg); + } + } + + + public interface GeometryHandler { + public void processApply(Element node, FeatureDescriptor fd, AffineTransform transform); + public void processSubstract(Element node, String tileId, AffineTransform transform, boolean isFarm); + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/Theme.java b/src/main/java/com/jcloisterzone/ui/theme/Theme.java index 71d8851df..6f7886abd 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/Theme.java +++ b/src/main/java/com/jcloisterzone/ui/theme/Theme.java @@ -1,134 +1,134 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.image.BufferedImage; -import java.awt.image.FilteredImageSource; -import java.awt.image.ImageFilter; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.WeakHashMap; - -import javax.swing.ImageIcon; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.jcloisterzone.ui.Client; -import com.jcloisterzone.ui.UiUtils; -import com.jcloisterzone.ui.legacy.FigureImageFilter; - -public abstract class Theme { - - protected final transient Logger logger = LoggerFactory - .getLogger(getClass()); - - private final Client client; - private final String baseDir; - - private Map imageCache = new WeakHashMap(64); - - public Theme(String baseDir, Client client) { - this.baseDir = baseDir; - this.client = client; - } - - public Client getClient() { - return client; - } - - protected Map getImageCache() { - return imageCache; - } - - protected List getResourceLayers(String name) { - int i = 0; - List layers = new ArrayList<>(); - for (;;) { - URL url = getResource(name + "_" + i + ".png", i > 0); - if (url == null) - break; - layers.add(url); - i++; - } - return layers; - } - - protected URL getResource(String relativePath) { - return getResource(relativePath, false); - } - - private URL getResource(String relativePath, boolean silent) { - // System.err.println(baseDir + "/" + relativePath); - URL result = Theme.class.getClassLoader().getResource( - baseDir + "/" + relativePath); - if (result == null && !silent) { - logger.error("Unable to load resource \"" + relativePath + "\""); - } - return result; - } - - protected Image getImageResource(String relativePath) { - return Toolkit.getDefaultToolkit().getImage(getResource(relativePath)); - } - - protected Image getLayeredImage(String name, Color color) { - String key; - if (color == null) { - key = name; - } else { - key = name + '#' + color.getRGB(); - } - Image image = imageCache.get(key); - if (image == null) { - List layers = getResourceLayers(name); - image = composeImages(layers, color); - imageCache.put(key, image); - } - return image; - } - - protected Image getImage(String name) { - Image image = imageCache.get(name); - if (image == null) { - image = (new ImageIcon(getImageResource(name))).getImage(); - imageCache.put(name, image); - } - return image; - } - - protected Image composeImages(Iterable layers, Color color) { - BufferedImage result = null; - Graphics2D g = null; - - ImageFilter colorfilter = null; - if (color != null) { - colorfilter = new FigureImageFilter(color); - } - - for (URL layer : layers) { - // Image img = new ImageIcon(getResource(path)).getImage(); - Image img = Toolkit.getDefaultToolkit().createImage(layer); - if (colorfilter != null) { - img = Toolkit.getDefaultToolkit().createImage( - new FilteredImageSource(img.getSource(), colorfilter)); - } - img = (new ImageIcon(img)).getImage(); // wait for load - if (g == null) { - result = UiUtils.newTransparentImage(img.getWidth(null), - img.getHeight(null)); - g = result.createGraphics(); - } - // bez new ImgIcon nefunguje - vyzkoumat proc - g.drawImage(img, 0, 0, null); - } - - g.dispose(); - return result; - } - -} +package com.jcloisterzone.ui.theme; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageFilter; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import javax.swing.ImageIcon; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.jcloisterzone.ui.Client; +import com.jcloisterzone.ui.UiUtils; +import com.jcloisterzone.ui.legacy.FigureImageFilter; + +public abstract class Theme { + + protected final transient Logger logger = LoggerFactory + .getLogger(getClass()); + + private final Client client; + private final String baseDir; + + private Map imageCache = new WeakHashMap(64); + + public Theme(String baseDir, Client client) { + this.baseDir = baseDir; + this.client = client; + } + + public Client getClient() { + return client; + } + + protected Map getImageCache() { + return imageCache; + } + + protected List getResourceLayers(String name) { + int i = 0; + List layers = new ArrayList<>(); + for (;;) { + URL url = getResource(name + "_" + i + ".png", i > 0); + if (url == null) + break; + layers.add(url); + i++; + } + return layers; + } + + protected URL getResource(String relativePath) { + return getResource(relativePath, false); + } + + private URL getResource(String relativePath, boolean silent) { + // System.err.println(baseDir + "/" + relativePath); + URL result = Theme.class.getClassLoader().getResource( + baseDir + "/" + relativePath); + if (result == null && !silent) { + logger.error("Unable to load resource \"" + relativePath + "\""); + } + return result; + } + + protected Image getImageResource(String relativePath) { + return Toolkit.getDefaultToolkit().getImage(getResource(relativePath)); + } + + protected Image getLayeredImage(String name, Color color) { + String key; + if (color == null) { + key = name; + } else { + key = name + '#' + color.getRGB(); + } + Image image = imageCache.get(key); + if (image == null) { + List layers = getResourceLayers(name); + image = composeImages(layers, color); + imageCache.put(key, image); + } + return image; + } + + protected Image getImage(String name) { + Image image = imageCache.get(name); + if (image == null) { + image = (new ImageIcon(getImageResource(name))).getImage(); + imageCache.put(name, image); + } + return image; + } + + protected Image composeImages(Iterable layers, Color color) { + BufferedImage result = null; + Graphics2D g = null; + + ImageFilter colorfilter = null; + if (color != null) { + colorfilter = new FigureImageFilter(color); + } + + for (URL layer : layers) { + // Image img = new ImageIcon(getResource(path)).getImage(); + Image img = Toolkit.getDefaultToolkit().createImage(layer); + if (colorfilter != null) { + img = Toolkit.getDefaultToolkit().createImage( + new FilteredImageSource(img.getSource(), colorfilter)); + } + img = (new ImageIcon(img)).getImage(); // wait for load + if (g == null) { + result = UiUtils.newTransparentImage(img.getWidth(null), + img.getHeight(null)); + g = result.createGraphics(); + } + // bez new ImgIcon nefunguje - vyzkoumat proc + g.drawImage(img, 0, 0, null); + } + + g.dispose(); + return result; + } + +} diff --git a/src/main/java/com/jcloisterzone/ui/theme/ThemeGeometry.java b/src/main/java/com/jcloisterzone/ui/theme/ThemeGeometry.java index a15e7487c..ffbccc44d 100644 --- a/src/main/java/com/jcloisterzone/ui/theme/ThemeGeometry.java +++ b/src/main/java/com/jcloisterzone/ui/theme/ThemeGeometry.java @@ -1,209 +1,209 @@ -package com.jcloisterzone.ui.theme; - -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Ellipse2D; -import java.io.IOException; -import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import javax.xml.parsers.ParserConfigurationException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; - -import com.jcloisterzone.XmlUtils; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.Bridge; -import com.jcloisterzone.feature.Farm; -import com.jcloisterzone.feature.Feature; -import com.jcloisterzone.ui.ImmutablePoint; -import com.jcloisterzone.ui.plugin.ResourcePlugin; -import com.jcloisterzone.ui.theme.SvgTransformationCollector.GeometryHandler; - - -public class ThemeGeometry { - - protected final transient Logger logger = LoggerFactory.getLogger(getClass()); - - private final Map aliases = new HashMap<>(); - private final Map areas = new HashMap<>(); - private final Map substractionAll = new HashMap<>(); //key tile ID - private final Map substractionFarm = new HashMap<>(); //key tile ID - private final Set complementFarms = new HashSet<>(); - private final Map points; - - private static final Area BRIDGE_AREA_NS, BRIDGE_AREA_WE; - - static { - Area a = new Area(new Rectangle(400, 0, 200, 1000)); - a.subtract(new Area(new Ellipse2D.Double(300, 150, 200, 700))); - BRIDGE_AREA_NS = new Area(a); - a.transform(Rotation.R270.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); - BRIDGE_AREA_WE = a; - } - - public ThemeGeometry(ClassLoader loader, String folder) throws IOException, SAXException, ParserConfigurationException { - NodeList nl; - URL aliasesResource = loader.getResource(folder + "/aliases.xml"); - if (aliasesResource != null) { - Element aliasesEl = XmlUtils.parseDocument(aliasesResource).getDocumentElement(); - nl = aliasesEl.getElementsByTagName("alias"); - for (int i = 0; i < nl.getLength(); i++) { - Element alias = (Element) nl.item(i); - aliases.put(alias.getAttribute("treat"), alias.getAttribute("as")); - } - } - - Element shapes = XmlUtils.parseDocument(loader.getResource(folder +"/shapes.xml")).getDocumentElement(); - nl = shapes.getElementsByTagName("shape"); - for (int i = 0; i < nl.getLength(); i++) { - processShapeElement((Element) nl.item(i)); - } - nl = shapes.getElementsByTagName("complement-farm"); - for (int i = 0; i < nl.getLength(); i++) { - processComplementFarm((Element) nl.item(i)); - } - - points = (new PointsParser(loader.getResource(folder + "/points.xml"))).parse(); - } - - private FeatureDescriptor createFeatureDescriptor(String featureName, String tileAndLocation) { - String[] tokens = tileAndLocation.split(" "); - return FeatureDescriptor.valueOf(tokens[0], featureName, tokens[1]); - } - - private Area createArea(Element shapeNode) { - NodeList nl = shapeNode.getChildNodes(); - for (int i = 0; i < nl.getLength(); i++) { - if (nl.item(i) instanceof Element) { - Element el = (Element) nl.item(i); - if (el.getNodeName().startsWith("svg:")) { - return new SvgToShapeConverter().convert(el); - } - } - } - throw new IllegalArgumentException("Node doesn't contains svg shape."); - } - - private void processShapeElement(Element shapeNode) { - final Area area = createArea(shapeNode); - - SvgTransformationCollector transformCollector = new SvgTransformationCollector(shapeNode); - transformCollector.collect(new GeometryHandler() { - - @Override - public void processApply(Element node, FeatureDescriptor fd, AffineTransform transform) { - assert !areas.containsKey(fd) : "Duplicate key " + fd; - areas.put(fd, area.createTransformedArea(transform)); - } - - @Override - public void processSubstract(Element node, String tileId, AffineTransform transform, boolean isFarm) { - Map target = isFarm ? substractionFarm : substractionAll; - //TODO merge if already exists - assert !target.containsKey(tileId); - target.put(tileId, area.createTransformedArea(transform)); - } - - }); - } - - private void processComplementFarm(Element xml) { - NodeList nl = xml.getElementsByTagName("apply"); - for (int i = 0; i < nl.getLength(); i++) { - Element apply = (Element) nl.item(i); - FeatureDescriptor fd = createFeatureDescriptor("FARM", apply.getTextContent()); - complementFarms.add(fd); - } - } - - private FeatureDescriptor[] getLookups(Tile tile, Class featureType, Location location) { - String alias = aliases.get(tile.getId()); - FeatureDescriptor[] fd = new FeatureDescriptor[alias == null ? 2 : 3]; - fd[0] = new FeatureDescriptor(tile.getId(), featureType, location); - if (alias != null) { - fd[1] = new FeatureDescriptor(alias, featureType, location); - } - fd[alias == null ? 1 : 2] = new FeatureDescriptor(FeatureDescriptor.EVERY, featureType, location); - return fd; - } - - public Area getArea(Tile tile, Class featureClass, Location loc) { - Rotation tileRotation = tile.getRotation(); - if (featureClass.equals(Bridge.class)) { - Area a = getBridgeArea(loc.rotateCCW(tileRotation)); - //bridge is independent on tile rotation - if ((loc == Location.WE && (tileRotation == Rotation.R90 || tileRotation == Rotation.R180)) || - (loc == Location.NS && (tileRotation == Rotation.R180 || tileRotation == Rotation.R270))) { - a = new Area(a); - a.transform(Rotation.R180.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); - } - return a; - } - loc = loc.rotateCCW(tileRotation); - FeatureDescriptor lookups[] = getLookups(tile, featureClass, loc); - Area area; - for (FeatureDescriptor fd : lookups) { - area = areas.get(fd); - if (area != null) return area; - } - return null; - } - - public Area getBridgeArea(Location loc) { - //TODO use shapes.xml to define areas ? (but it is too complicated shape) - if (loc == Location.NS) return BRIDGE_AREA_NS; - if (loc == Location.WE) return BRIDGE_AREA_WE; - throw new IllegalArgumentException("Incorrect location"); - } - - public Area getSubstractionArea(Tile tile, boolean isFarm) { - if (isFarm) { - Area area = getSubstractionArea(substractionFarm, tile); - if (area != null) return area; - } - return getSubstractionArea(substractionAll, tile); - } - - private Area getSubstractionArea(Map substractions, Tile tile) { - Area area = substractions.get(tile.getId()); - if (area == null) { - String alias = aliases.get(tile.getId()); - if (alias != null) { - area = substractions.get(alias); - } - } - return area; - } - - public boolean isFarmComplement(Tile tile, Location loc) { - loc = loc.rotateCCW(tile.getRotation()); - FeatureDescriptor lookups[] = getLookups(tile, Farm.class, loc); - for (FeatureDescriptor fd : lookups) { - if (complementFarms.contains(fd)) return true; - } - return false; - } - - public ImmutablePoint getMeeplePlacement(Tile tile, Class feature, Location location) { - Location normalizedLoc = location.rotateCCW(tile.getRotation()); - FeatureDescriptor lookups[] = getLookups(tile, feature, normalizedLoc); - ImmutablePoint point = null; - for (FeatureDescriptor fd : lookups) { - point = points.get(fd); - if (point != null) break; - } - if (point == null) return null; - return point.rotate(tile.getRotation()); - } +package com.jcloisterzone.ui.theme; + +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.io.IOException; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.ParserConfigurationException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import com.jcloisterzone.XmlUtils; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.Bridge; +import com.jcloisterzone.feature.Farm; +import com.jcloisterzone.feature.Feature; +import com.jcloisterzone.ui.ImmutablePoint; +import com.jcloisterzone.ui.plugin.ResourcePlugin; +import com.jcloisterzone.ui.theme.SvgTransformationCollector.GeometryHandler; + + +public class ThemeGeometry { + + protected final transient Logger logger = LoggerFactory.getLogger(getClass()); + + private final Map aliases = new HashMap<>(); + private final Map areas = new HashMap<>(); + private final Map substractionAll = new HashMap<>(); //key tile ID + private final Map substractionFarm = new HashMap<>(); //key tile ID + private final Set complementFarms = new HashSet<>(); + private final Map points; + + private static final Area BRIDGE_AREA_NS, BRIDGE_AREA_WE; + + static { + Area a = new Area(new Rectangle(400, 0, 200, 1000)); + a.subtract(new Area(new Ellipse2D.Double(300, 150, 200, 700))); + BRIDGE_AREA_NS = new Area(a); + a.transform(Rotation.R270.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); + BRIDGE_AREA_WE = a; + } + + public ThemeGeometry(ClassLoader loader, String folder) throws IOException, SAXException, ParserConfigurationException { + NodeList nl; + URL aliasesResource = loader.getResource(folder + "/aliases.xml"); + if (aliasesResource != null) { + Element aliasesEl = XmlUtils.parseDocument(aliasesResource).getDocumentElement(); + nl = aliasesEl.getElementsByTagName("alias"); + for (int i = 0; i < nl.getLength(); i++) { + Element alias = (Element) nl.item(i); + aliases.put(alias.getAttribute("treat"), alias.getAttribute("as")); + } + } + + Element shapes = XmlUtils.parseDocument(loader.getResource(folder +"/shapes.xml")).getDocumentElement(); + nl = shapes.getElementsByTagName("shape"); + for (int i = 0; i < nl.getLength(); i++) { + processShapeElement((Element) nl.item(i)); + } + nl = shapes.getElementsByTagName("complement-farm"); + for (int i = 0; i < nl.getLength(); i++) { + processComplementFarm((Element) nl.item(i)); + } + + points = (new PointsParser(loader.getResource(folder + "/points.xml"))).parse(); + } + + private FeatureDescriptor createFeatureDescriptor(String featureName, String tileAndLocation) { + String[] tokens = tileAndLocation.split(" "); + return FeatureDescriptor.valueOf(tokens[0], featureName, tokens[1]); + } + + private Area createArea(Element shapeNode) { + NodeList nl = shapeNode.getChildNodes(); + for (int i = 0; i < nl.getLength(); i++) { + if (nl.item(i) instanceof Element) { + Element el = (Element) nl.item(i); + if (el.getNodeName().startsWith("svg:")) { + return new SvgToShapeConverter().convert(el); + } + } + } + throw new IllegalArgumentException("Node doesn't contains svg shape."); + } + + private void processShapeElement(Element shapeNode) { + final Area area = createArea(shapeNode); + + SvgTransformationCollector transformCollector = new SvgTransformationCollector(shapeNode); + transformCollector.collect(new GeometryHandler() { + + @Override + public void processApply(Element node, FeatureDescriptor fd, AffineTransform transform) { + assert !areas.containsKey(fd) : "Duplicate key " + fd; + areas.put(fd, area.createTransformedArea(transform)); + } + + @Override + public void processSubstract(Element node, String tileId, AffineTransform transform, boolean isFarm) { + Map target = isFarm ? substractionFarm : substractionAll; + //TODO merge if already exists + assert !target.containsKey(tileId); + target.put(tileId, area.createTransformedArea(transform)); + } + + }); + } + + private void processComplementFarm(Element xml) { + NodeList nl = xml.getElementsByTagName("apply"); + for (int i = 0; i < nl.getLength(); i++) { + Element apply = (Element) nl.item(i); + FeatureDescriptor fd = createFeatureDescriptor("FARM", apply.getTextContent()); + complementFarms.add(fd); + } + } + + private FeatureDescriptor[] getLookups(Tile tile, Class featureType, Location location) { + String alias = aliases.get(tile.getId()); + FeatureDescriptor[] fd = new FeatureDescriptor[alias == null ? 2 : 3]; + fd[0] = new FeatureDescriptor(tile.getId(), featureType, location); + if (alias != null) { + fd[1] = new FeatureDescriptor(alias, featureType, location); + } + fd[alias == null ? 1 : 2] = new FeatureDescriptor(FeatureDescriptor.EVERY, featureType, location); + return fd; + } + + public Area getArea(Tile tile, Class featureClass, Location loc) { + Rotation tileRotation = tile.getRotation(); + if (featureClass.equals(Bridge.class)) { + Area a = getBridgeArea(loc.rotateCCW(tileRotation)); + //bridge is independent on tile rotation + if ((loc == Location.WE && (tileRotation == Rotation.R90 || tileRotation == Rotation.R180)) || + (loc == Location.NS && (tileRotation == Rotation.R180 || tileRotation == Rotation.R270))) { + a = new Area(a); + a.transform(Rotation.R180.getAffineTransform(ResourcePlugin.NORMALIZED_SIZE)); + } + return a; + } + loc = loc.rotateCCW(tileRotation); + FeatureDescriptor lookups[] = getLookups(tile, featureClass, loc); + Area area; + for (FeatureDescriptor fd : lookups) { + area = areas.get(fd); + if (area != null) return area; + } + return null; + } + + public Area getBridgeArea(Location loc) { + //TODO use shapes.xml to define areas ? (but it is too complicated shape) + if (loc == Location.NS) return BRIDGE_AREA_NS; + if (loc == Location.WE) return BRIDGE_AREA_WE; + throw new IllegalArgumentException("Incorrect location"); + } + + public Area getSubstractionArea(Tile tile, boolean isFarm) { + if (isFarm) { + Area area = getSubstractionArea(substractionFarm, tile); + if (area != null) return area; + } + return getSubstractionArea(substractionAll, tile); + } + + private Area getSubstractionArea(Map substractions, Tile tile) { + Area area = substractions.get(tile.getId()); + if (area == null) { + String alias = aliases.get(tile.getId()); + if (alias != null) { + area = substractions.get(alias); + } + } + return area; + } + + public boolean isFarmComplement(Tile tile, Location loc) { + loc = loc.rotateCCW(tile.getRotation()); + FeatureDescriptor lookups[] = getLookups(tile, Farm.class, loc); + for (FeatureDescriptor fd : lookups) { + if (complementFarms.contains(fd)) return true; + } + return false; + } + + public ImmutablePoint getMeeplePlacement(Tile tile, Class feature, Location location) { + Location normalizedLoc = location.rotateCCW(tile.getRotation()); + FeatureDescriptor lookups[] = getLookups(tile, feature, normalizedLoc); + ImmutablePoint point = null; + for (FeatureDescriptor fd : lookups) { + point = points.get(fd); + if (point != null) break; + } + if (point == null) return null; + return point.rotate(tile.getRotation()); + } } \ No newline at end of file diff --git a/src/main/resources/defaults/points.xml b/src/main/resources/defaults/points.xml index 04094f29d..bbdc55a28 100644 --- a/src/main/resources/defaults/points.xml +++ b/src/main/resources/defaults/points.xml @@ -1,108 +1,108 @@ - - - - - - * CLOISTER - - - - - - * N - - - * NW - - - * NWSE - - - * NS - * WE - * _N - - - - * N - - - - * N - - - * NW - - - * _N - - - * NWSE - - - * NS - * WE - - - * NL - - - * NL.SR - * NL.ER - - - * NL.NR - - - * NL.NR.SL.SR - * WL.WR.EL.ER - - - * INNER_FARM - * NL.NR.EL.ER.SL.SR.WL.WR - * NL.NR.SL - * NL.NR.SR - - - * NL.NR.EL - * NL.NR.EL.ER - * NL.NR.EL.ER.SL.WR - * NL.NR.EL.ER.SL - - - * NR - - - * NR.EL.ER.WL - - - * NL.NR.EL.ER.SL.SR - - - * WR.EL.ER.SL - - - * NR.EL.ER.SL.SR - - - * NR.EL.SR.WL - - * ER.SL.WR.NL - - - - * NR.EL - * NR.EL.SR - * NR.EL.WL - - - * NR.EL.ER - - - * NR.EL.ER.SL - - + + + + + + * CLOISTER + + + + + + * N + + + * NW + + + * NWSE + + + * NS + * WE + * _N + + + + * N + + + + * N + + + * NW + + + * _N + + + * NWSE + + + * NS + * WE + + + * NL + + + * NL.SR + * NL.ER + + + * NL.NR + + + * NL.NR.SL.SR + * WL.WR.EL.ER + + + * INNER_FARM + * NL.NR.EL.ER.SL.SR.WL.WR + * NL.NR.SL + * NL.NR.SR + + + * NL.NR.EL + * NL.NR.EL.ER + * NL.NR.EL.ER.SL.WR + * NL.NR.EL.ER.SL + + + * NR + + + * NR.EL.ER.WL + + + * NL.NR.EL.ER.SL.SR + + + * WR.EL.ER.SL + + + * NR.EL.ER.SL.SR + + + * NR.EL.SR.WL + + * ER.SL.WR.NL + + + + * NR.EL + * NR.EL.SR + * NR.EL.WL + + + * NR.EL.ER + + + * NR.EL.ER.SL + + \ No newline at end of file diff --git a/src/main/resources/defaults/shapes.xml b/src/main/resources/defaults/shapes.xml index 91bc7a2f4..bfbc31e66 100644 --- a/src/main/resources/defaults/shapes.xml +++ b/src/main/resources/defaults/shapes.xml @@ -1,53 +1,53 @@ - - - - - * N - - - - * WE - * NS - - - - - * NWSE - - - - upper-left quarter - - * NL.WR - * WR - * NL - - - upper-half - - * NL.NR.EL.WR - * NL.NR.WR - * NL.NR.EL - * NL.NR - * EL.WR - - - - * NL.NR.WL.WR.SL.SR.EL.ER - * INNER_FARM - * WL.WR.EL.ER - * NL.NR.SL.SR - * WL.WR.SL.SR.EL.ER - * NL.NR.SL.SR.EL.ER - * NL.NR.WL.WR.EL.ER - * NL.NR.WL.WR.SL.SR - * NL.NR.WL.WR - * NL.NR.EL.ER - * SL.SR.EL.ER - * SL.SR.WL.WR - * WR.NL.NR.EL.ER.SL - * NR.EL.ER.SL.SR.WL - * ER.SL.SR.WL.WR.NL - * SR.WL.WR.NL.NR.EL - + + + + + * N + + + + * WE + * NS + + + + + * NWSE + + + + upper-left quarter + + * NL.WR + * WR + * NL + + + upper-half + + * NL.NR.EL.WR + * NL.NR.WR + * NL.NR.EL + * NL.NR + * EL.WR + + + + * NL.NR.WL.WR.SL.SR.EL.ER + * INNER_FARM + * WL.WR.EL.ER + * NL.NR.SL.SR + * WL.WR.SL.SR.EL.ER + * NL.NR.SL.SR.EL.ER + * NL.NR.WL.WR.EL.ER + * NL.NR.WL.WR.SL.SR + * NL.NR.WL.WR + * NL.NR.EL.ER + * SL.SR.EL.ER + * SL.SR.WL.WR + * WR.NL.NR.EL.ER.SL + * NR.EL.ER.SL.SR.WL + * ER.SL.SR.WL.WR.NL + * SR.WL.WR.NL.NR.EL + \ No newline at end of file diff --git a/src/main/resources/plugins/classic/plugin.xml b/src/main/resources/plugins/classic/plugin.xml index 14d452c25..5a134124d 100644 --- a/src/main/resources/plugins/classic/plugin.xml +++ b/src/main/resources/plugins/classic/plugin.xml @@ -1,30 +1,30 @@ - - - Classic art - Graphics from original board game - - BASIC - WINTER - INNS_AND_CATHEDRALS - TRADERS_AND_BUILDERS - PRINCESS_AND_DRAGON - TOWER - ABBEY_AND_MAYOR - CATAPULT - BRIDGES_CASTLES_AND_BAZAARS - KING_AND_SCOUT - RIVER - RIVER_II - CATHARS - COUNT - GQ11 - CULT - TUNNEL - CORN_CIRCLES - PLAGUE - FESTIVAL - WIND_ROSE - FLIER - CORN_CIRCLES_II - + + + Classic art + Graphics from original board game + + BASIC + WINTER + INNS_AND_CATHEDRALS + TRADERS_AND_BUILDERS + PRINCESS_AND_DRAGON + TOWER + ABBEY_AND_MAYOR + CATAPULT + BRIDGES_CASTLES_AND_BAZAARS + KING_AND_SCOUT + RIVER + RIVER_II + CATHARS + COUNT + GQ11 + CULT + TUNNEL + CORN_CIRCLES + PLAGUE + FESTIVAL + WIND_ROSE + FLIER + CORN_CIRCLES_II + \ No newline at end of file diff --git a/src/main/resources/plugins/classic/tiles/aliases.xml b/src/main/resources/plugins/classic/tiles/aliases.xml index e3a9f5d51..9591756ae 100644 --- a/src/main/resources/plugins/classic/tiles/aliases.xml +++ b/src/main/resources/plugins/classic/tiles/aliases.xml @@ -1,54 +1,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/plugins/classic/tiles/points.xml b/src/main/resources/plugins/classic/tiles/points.xml index a270ebca5..36f4f2bfd 100644 --- a/src/main/resources/plugins/classic/tiles/points.xml +++ b/src/main/resources/plugins/classic/tiles/points.xml @@ -1,482 +1,482 @@ - - - - R1.LIRI CLOISTER - R2.LIFI CLOISTER - - - BB.LCFc CLOISTER - - - KS.LC CLOISTER - - - DG.LCcc.d CLOISTER - - - TO.L CLOISTER - - - CA.L CLOISTER - - - CU.SC CLOISTER - CU.SCFR CLOISTER - CU.SRCR CLOISTER - - - - BA.CccR S - BA.CccR+ S - TB.LRRR S - TB.LRRR E - DG.LRRR.d S - DG.LRRR.d E - KS.CcRR! E - TB.CcRR.w E - IC.LRFR W - - - TB.CcR!.w E - TB.CcRR!.c E - TB.LRRR W - DG.LRRR.d W - TO.CcR! E - CA.RRr.2 W - - - TB.CRcR.w N - TB.CRcR.w S - TB.CRc.w S - TB.CRc.g S - TB.CcRR!.c S - AM.LRRRR S - KS.CcRR! S - GQ.CRcR.1 N - GQ.CRcR.1 S - C2.RCR W - C2.RCR E - - - TB.CccR.w S - TB.RCc!.g S - - - AM.LRRRR N - AM.LRRRR E - BB.CFR! E - BB.RFR.bi N - BB.RFR.b S - CA.RrR.1 W - GQ.CRc S - IC.LRFR E - CU.SCFR S - TU.RRRR N - TU.RRRR E - TU.RRRR S - TU.RRRR W - TU.CRRR S - TU.CRRR E - TU.CRRR W - TU.RCR W - TU.RR E - C2.RRr E - C2.RRRr N - C2.RRRr E - C2.CFR S - - - GQ.RFI W - - - IC.CRcR+ N - IC.CRcR+ S - - - GQ.CcCR S - - - - R1.LIRI S - - - BA.CRRR E - IC.RRR.i E - DG.CRRR.p E - DG.RRR.g E - - - TU.RCR E - - - AM.CCRR S - - - DG.RFr.v WE - - - FL.RFr.d WE - - - FL.RFr.NS.o NS - - - FL.RFr.WE.o WE - - - R1.RIrI WE - TB.RRrr NS - TB.RRrr WE - TO.CRcr NS - - - DG.CRcr.d NS - AM.CRcr+ NS - - - TO.RCr WE - - - BA.Rr SW - IC.Rr.i SW - DG.Rr.d SW - - - SI.CcRr SE - FL.Rr.d SE - FL.Rr.NW.o NW - - - AM.RrC SW - - - AM.CRr SE - - - BB.LRFr WE - SI.RCr WE - - - WR.CFR W - - - BA.CcRr SE - BA.CcRr+ SE - CA.RrR.1 SE - IC.CcRr+.i SE - KS.CRrR SE - DG.RrRr.g SE - DG.CcRr.p SE - TO.RrRr.2 SE - GQ.CRRr SW - IC.RrRr SE - R1.RrII NE - R2.RrII NE - TO.RrRr.2 NW - FL.Rr.SW.o SW - C2.RRRr SW - WR.Rr SW - WR.RrC SW - - - - DG.CCc+.p N - - - BB.CFR! W - - - AM.C!+ W - CA.C! E - - - R1.CICI N - R1.CICI S - - - R2.CIcI WE - - - BA.CC.2 W - BA.RrC N - AM.CCc+ N - AM.CCRR W - BB.CCCR N - C2.CFC N - CC.CC.1 N - CU.SCFR N - CU.SC N - CU.SRCR N - DG.CC.v N - FE.CCc S - IC.CCCC N - IC.CCCC S - IC.CCC N - KS.CRrR N - TB.CcCC.c E - TO.CccC+ S - TO.CC.2 W - TU.CRRR N - TU.RCR N - - - TB.CCc.w S - TB.CCc.c S - WR.CFR E - - - - AM.CCcc+ NS - - - TB.CCc.w WE - TB.CCc.c WE - - - AM.CCc+ WE - - - AM.CCcc+ WE - - - BB.LCFc WE - - - AM.CRcr+ WE - - - TB.CcRR!.c NW - TB.CcR!.w NW - - - TO.CcR! NW - - - DG.LCcc.d _S - - - TO.CccR _S - - - TO.CccC+ _S - - - TO.CRcr WE - - - - KS.CcRR! EL - TB.CcR!.w EL - TB.CcRR!.c EL - - - KS.CcRR! SR - TB.RCc!.g SR - TB.CcRR!.c SR - TB.CccR.w SR - GQ.CRcR.1 NR - GQ.CRcR.1 SR - - - DG.CCc+.p WL.WR - - - R1.LIRI SR.WL - - - TO.RrC WR.EL.ER.SL - - - CU.SR NL.NR.WL.WR.SL.SR.EL.ER - CU.SRFR NL.SR.WL.WR - TU.RRRR NL.NR.EL.WR - - - AM.CRr SR.WL.WR - - - SI.RCr WL.SL.SR.ER - TO.RrRr.2 NR.EL.SR.WL - CU.SCFR EL.ER.SL.SR.WL.WR - CU.SC EL.ER.SL.SR.WL.WR - CA.C! WL.WR.SL.SR - C2.RCR WL.SL.SR.ER - WR.CFR WL.SL.SR - - - DG.LRRR.d NL.NR.EL.WR - CA.F NL.NR.EL.ER.SL.SR.WL.WR - CA.RRr.2 ER.SL.SR.WL.WR.NL - CU.S NL.NR.EL.ER.SL.SR.WL.WR - FL.RFr.NS.o NL.WR.WL.SR - C2.RRr NL.NR.EL.WR - - - TO.F NL.NR.EL.ER.SL.SR.WL.WR - FL.Rr.d NL.NR.WL.WR.SR.EL - - - DG.CRcr.d NL.NR - AM.CRcr+ SL.SR - - - TO.L NL.NR.WL.WR.SL.SR.EL.ER - - - TO.C EL.ER.SL.SR.WL.WR - BB.CFR.b EL.ER.SL.SR.WL.WR - - - DG.CRcr.d SL.SR - TO.CFR SR.WL.WR - - - TB.CcRR.w EL - - - TO.CC.2 SL.SR.EL.ER - - - BB.CFR! NL.NR - - - R1.IFI NL.NR.EL.WR - R1.IFI SL.SR.ER.WL - R2.III SL.SR.ER.WL - - - BA.CFc.1 NL.NR - BA.CFc+ NL.NR - AM.C!+ NL.NR - BB.CFc.b NL.NR - BB.LCFc SL.SR - DG.CFc+.d NL.NR - GQ.CRc NL.NR - GQ.Cc! EL.ER - IC.C! EL.ER - TB.CRc.w NL.NR - TB.RCc!.g EL.ER - TB.CCc.c NL.NR - TB.CCc.w NL.NR - TB.CFc.w NL.NR - TB.CRc.g NL.NR - WR.CFc WL.WR - - - R2.RIrI NR.EL - - - AM.CCc+ SL.SR - - - TB.LRRR NL.NR.EL.WR - FL.Rr.NW.o NR.EL.ER.SL.SR.WL - FL.F.d NL.NR.WL.WR.SL.SR.EL.ER - FL.F.o NL.NR.WL.WR.SL.SR.EL.ER - - - TO.Cc SL.SR.EL.ER - - - TB.CCc.w INNER_FARM - TB.CCc.c INNER_FARM - TO.CccC+ INNER_FARM - - - AM.R NL.NR.EL.ER.SL.SR.WL.WR - BB.F.b NL.NR.EL.ER.SL.SR.WL.WR - - - R1.LIRI NL.NR.EL.WR - BA.L NL.NR.EL.ER.SL.SR.WL.WR - BA.LR NL.NR.EL.ER.SL.SR.WL.WR - BB.LRFr WR.NL.NR.EL - CA.L WR.NL.NR.EL - CA.RrR.1 SR.WL.WR.NL.NR.EL - FL.RFr.WE.o WR.NL.NR.EL - FL.RFr.d WR.NL.NR.EL - - - BB.R.bi NL.NR.EL.ER.SL.SR.WL.WR - IC.LRFR ER.SL.SR.WL - FL.RFr.d ER.SL.SR.WL - FL.Rr.SW.o NL.NR.WR.SL.EL.ER - - - FL.RFr.NS.o NR.EL.ER.SL - R2.LIFI NL.NR.EL.WR - IC.LRFR NL.NR.EL.WR - - - TO.RCr SL.SR.ER.WL - - - R2.LIFI SL.SR.ER.WL - KS.LC EL.ER.SL.SR.WL.WR - CU.SRCR ER.SL.SR.WL - CU.SRFR NR.EL.ER.SL - BB.LRFr ER.SL.SR.WL - FL.RFr.WE.o ER.SL.SR.WL - - - BA.CcRr SL.ER - BA.CcRr+ SL.ER - CA.RrR.1 SL.ER - IC.CcRr+.i SL.ER - KS.CRrR SL.ER - DG.RrRr.g SL.ER - DG.CcRr.p SL.ER - TO.RrRr.2 SL.ER - GQ.CRRr SR.WL - IC.RrRr SL.ER - R1.RrII NR.EL - R2.RrII NR.EL - TO.RrRr.2 NL.WR - SI.CcRr ER.SL - FL.Rr.SW.o SR.WL - FL.Rr.NW.o WR.NL - FL.Rr.d ER.SL - WR.RrC SR.WL - WR.Rr SR.WL - - - * TOWER - - - TO.RRRR.1 TOWER - - - TO.RRR TOWER - - - TO.C TOWER - TO.CC.2 TOWER - - - TO.Cc TOWER - - - TO.L TOWER - TO.RrRr.2 TOWER - TO.CccR TOWER - - - TO.CRCr.2 TOWER - - - TO.CRcr TOWER - - - TO.CcR! TOWER - TO.CccC+ TOWER - - - TO.RrC TOWER - - - TO.RCr TOWER - - - TO.CFR TOWER - + + + + R1.LIRI CLOISTER + R2.LIFI CLOISTER + + + BB.LCFc CLOISTER + + + KS.LC CLOISTER + + + DG.LCcc.d CLOISTER + + + TO.L CLOISTER + + + CA.L CLOISTER + + + CU.SC CLOISTER + CU.SCFR CLOISTER + CU.SRCR CLOISTER + + + + BA.CccR S + BA.CccR+ S + TB.LRRR S + TB.LRRR E + DG.LRRR.d S + DG.LRRR.d E + KS.CcRR! E + TB.CcRR.w E + IC.LRFR W + + + TB.CcR!.w E + TB.CcRR!.c E + TB.LRRR W + DG.LRRR.d W + TO.CcR! E + CA.RRr.2 W + + + TB.CRcR.w N + TB.CRcR.w S + TB.CRc.w S + TB.CRc.g S + TB.CcRR!.c S + AM.LRRRR S + KS.CcRR! S + GQ.CRcR.1 N + GQ.CRcR.1 S + C2.RCR W + C2.RCR E + + + TB.CccR.w S + TB.RCc!.g S + + + AM.LRRRR N + AM.LRRRR E + BB.CFR! E + BB.RFR.bi N + BB.RFR.b S + CA.RrR.1 W + GQ.CRc S + IC.LRFR E + CU.SCFR S + TU.RRRR N + TU.RRRR E + TU.RRRR S + TU.RRRR W + TU.CRRR S + TU.CRRR E + TU.CRRR W + TU.RCR W + TU.RR E + C2.RRr E + C2.RRRr N + C2.RRRr E + C2.CFR S + + + GQ.RFI W + + + IC.CRcR+ N + IC.CRcR+ S + + + GQ.CcCR S + + + + R1.LIRI S + + + BA.CRRR E + IC.RRR.i E + DG.CRRR.p E + DG.RRR.g E + + + TU.RCR E + + + AM.CCRR S + + + DG.RFr.v WE + + + FL.RFr.d WE + + + FL.RFr.NS.o NS + + + FL.RFr.WE.o WE + + + R1.RIrI WE + TB.RRrr NS + TB.RRrr WE + TO.CRcr NS + + + DG.CRcr.d NS + AM.CRcr+ NS + + + TO.RCr WE + + + BA.Rr SW + IC.Rr.i SW + DG.Rr.d SW + + + SI.CcRr SE + FL.Rr.d SE + FL.Rr.NW.o NW + + + AM.RrC SW + + + AM.CRr SE + + + BB.LRFr WE + SI.RCr WE + + + WR.CFR W + + + BA.CcRr SE + BA.CcRr+ SE + CA.RrR.1 SE + IC.CcRr+.i SE + KS.CRrR SE + DG.RrRr.g SE + DG.CcRr.p SE + TO.RrRr.2 SE + GQ.CRRr SW + IC.RrRr SE + R1.RrII NE + R2.RrII NE + TO.RrRr.2 NW + FL.Rr.SW.o SW + C2.RRRr SW + WR.Rr SW + WR.RrC SW + + + + DG.CCc+.p N + + + BB.CFR! W + + + AM.C!+ W + CA.C! E + + + R1.CICI N + R1.CICI S + + + R2.CIcI WE + + + BA.CC.2 W + BA.RrC N + AM.CCc+ N + AM.CCRR W + BB.CCCR N + C2.CFC N + CC.CC.1 N + CU.SCFR N + CU.SC N + CU.SRCR N + DG.CC.v N + FE.CCc S + IC.CCCC N + IC.CCCC S + IC.CCC N + KS.CRrR N + TB.CcCC.c E + TO.CccC+ S + TO.CC.2 W + TU.CRRR N + TU.RCR N + + + TB.CCc.w S + TB.CCc.c S + WR.CFR E + + + + AM.CCcc+ NS + + + TB.CCc.w WE + TB.CCc.c WE + + + AM.CCc+ WE + + + AM.CCcc+ WE + + + BB.LCFc WE + + + AM.CRcr+ WE + + + TB.CcRR!.c NW + TB.CcR!.w NW + + + TO.CcR! NW + + + DG.LCcc.d _S + + + TO.CccR _S + + + TO.CccC+ _S + + + TO.CRcr WE + + + + KS.CcRR! EL + TB.CcR!.w EL + TB.CcRR!.c EL + + + KS.CcRR! SR + TB.RCc!.g SR + TB.CcRR!.c SR + TB.CccR.w SR + GQ.CRcR.1 NR + GQ.CRcR.1 SR + + + DG.CCc+.p WL.WR + + + R1.LIRI SR.WL + + + TO.RrC WR.EL.ER.SL + + + CU.SR NL.NR.WL.WR.SL.SR.EL.ER + CU.SRFR NL.SR.WL.WR + TU.RRRR NL.NR.EL.WR + + + AM.CRr SR.WL.WR + + + SI.RCr WL.SL.SR.ER + TO.RrRr.2 NR.EL.SR.WL + CU.SCFR EL.ER.SL.SR.WL.WR + CU.SC EL.ER.SL.SR.WL.WR + CA.C! WL.WR.SL.SR + C2.RCR WL.SL.SR.ER + WR.CFR WL.SL.SR + + + DG.LRRR.d NL.NR.EL.WR + CA.F NL.NR.EL.ER.SL.SR.WL.WR + CA.RRr.2 ER.SL.SR.WL.WR.NL + CU.S NL.NR.EL.ER.SL.SR.WL.WR + FL.RFr.NS.o NL.WR.WL.SR + C2.RRr NL.NR.EL.WR + + + TO.F NL.NR.EL.ER.SL.SR.WL.WR + FL.Rr.d NL.NR.WL.WR.SR.EL + + + DG.CRcr.d NL.NR + AM.CRcr+ SL.SR + + + TO.L NL.NR.WL.WR.SL.SR.EL.ER + + + TO.C EL.ER.SL.SR.WL.WR + BB.CFR.b EL.ER.SL.SR.WL.WR + + + DG.CRcr.d SL.SR + TO.CFR SR.WL.WR + + + TB.CcRR.w EL + + + TO.CC.2 SL.SR.EL.ER + + + BB.CFR! NL.NR + + + R1.IFI NL.NR.EL.WR + R1.IFI SL.SR.ER.WL + R2.III SL.SR.ER.WL + + + BA.CFc.1 NL.NR + BA.CFc+ NL.NR + AM.C!+ NL.NR + BB.CFc.b NL.NR + BB.LCFc SL.SR + DG.CFc+.d NL.NR + GQ.CRc NL.NR + GQ.Cc! EL.ER + IC.C! EL.ER + TB.CRc.w NL.NR + TB.RCc!.g EL.ER + TB.CCc.c NL.NR + TB.CCc.w NL.NR + TB.CFc.w NL.NR + TB.CRc.g NL.NR + WR.CFc WL.WR + + + R2.RIrI NR.EL + + + AM.CCc+ SL.SR + + + TB.LRRR NL.NR.EL.WR + FL.Rr.NW.o NR.EL.ER.SL.SR.WL + FL.F.d NL.NR.WL.WR.SL.SR.EL.ER + FL.F.o NL.NR.WL.WR.SL.SR.EL.ER + + + TO.Cc SL.SR.EL.ER + + + TB.CCc.w INNER_FARM + TB.CCc.c INNER_FARM + TO.CccC+ INNER_FARM + + + AM.R NL.NR.EL.ER.SL.SR.WL.WR + BB.F.b NL.NR.EL.ER.SL.SR.WL.WR + + + R1.LIRI NL.NR.EL.WR + BA.L NL.NR.EL.ER.SL.SR.WL.WR + BA.LR NL.NR.EL.ER.SL.SR.WL.WR + BB.LRFr WR.NL.NR.EL + CA.L WR.NL.NR.EL + CA.RrR.1 SR.WL.WR.NL.NR.EL + FL.RFr.WE.o WR.NL.NR.EL + FL.RFr.d WR.NL.NR.EL + + + BB.R.bi NL.NR.EL.ER.SL.SR.WL.WR + IC.LRFR ER.SL.SR.WL + FL.RFr.d ER.SL.SR.WL + FL.Rr.SW.o NL.NR.WR.SL.EL.ER + + + FL.RFr.NS.o NR.EL.ER.SL + R2.LIFI NL.NR.EL.WR + IC.LRFR NL.NR.EL.WR + + + TO.RCr SL.SR.ER.WL + + + R2.LIFI SL.SR.ER.WL + KS.LC EL.ER.SL.SR.WL.WR + CU.SRCR ER.SL.SR.WL + CU.SRFR NR.EL.ER.SL + BB.LRFr ER.SL.SR.WL + FL.RFr.WE.o ER.SL.SR.WL + + + BA.CcRr SL.ER + BA.CcRr+ SL.ER + CA.RrR.1 SL.ER + IC.CcRr+.i SL.ER + KS.CRrR SL.ER + DG.RrRr.g SL.ER + DG.CcRr.p SL.ER + TO.RrRr.2 SL.ER + GQ.CRRr SR.WL + IC.RrRr SL.ER + R1.RrII NR.EL + R2.RrII NR.EL + TO.RrRr.2 NL.WR + SI.CcRr ER.SL + FL.Rr.SW.o SR.WL + FL.Rr.NW.o WR.NL + FL.Rr.d ER.SL + WR.RrC SR.WL + WR.Rr SR.WL + + + * TOWER + + + TO.RRRR.1 TOWER + + + TO.RRR TOWER + + + TO.C TOWER + TO.CC.2 TOWER + + + TO.Cc TOWER + + + TO.L TOWER + TO.RrRr.2 TOWER + TO.CccR TOWER + + + TO.CRCr.2 TOWER + + + TO.CRcr TOWER + + + TO.CcR! TOWER + TO.CccC+ TOWER + + + TO.RrC TOWER + + + TO.RCr TOWER + + + TO.CFR TOWER + \ No newline at end of file diff --git a/src/main/resources/plugins/classic/tiles/shapes.xml b/src/main/resources/plugins/classic/tiles/shapes.xml index 563f044a6..c342250d8 100644 --- a/src/main/resources/plugins/classic/tiles/shapes.xml +++ b/src/main/resources/plugins/classic/tiles/shapes.xml @@ -1,910 +1,910 @@ - - - - - - - - - * CLOISTER - - - - BA.LR CLOISTER - AM.LRRRR CLOISTER - FE.LRR CLOISTER - - - - R1.LIRI CLOISTER - R2.LIFI CLOISTER - - - - KS.LC CLOISTER - - - - DG.LCcc.d CLOISTER - - - - TO.L CLOISTER - - - - TB.LRRR CLOISTER - - - - CA.L CLOISTER - - - - AM.A CLOISTER - - - - - CU.S CLOISTER - CU.SR CLOISTER - CU.SRFR CLOISTER - - - - CU.SC CLOISTER - CU.SCFR CLOISTER - CU.SRCR CLOISTER - - - - - - - - * _N - - - - * NW - - - - - * NWSE - - - - BA.CcRr SE - BA.CcRr+ SE - CA.RrR.1 SE - GQ.CRRr SW - IC.RrRr SE - KS.CRrR SE - DG.RrRr.g SE - DG.CcRr.p SE - R1.RrII NE - TO.RrRr.2 NW - TO.RrRr.2 SE - FL.Rr.SW.o SW - C2.RRRr SW - WR.Rr SW - WR.RrC SW - - - - BA.CRr SE - BA.RrC SW - CA.RRr.2 NE - IC.RrRr NW - DG.RrRr.g NW - DG.Rr.v SW - DG.CcRr.g SE - DG.RrC.d SW - DG.RrC.g SW - DG.CRr.d SE - DG.CRr.g SE - TO.RrC SW - CC.Rr SW - C2.RRr SW - - - - IC.RrC.i SW - - - - AM.R S - IC.CFR S - IC.CcR E - R1.CIRI S - TB.CcR.c E - TB.RRC W - TB.RRC S - BB.R.bi S - BB.RFR.b N - BB.RFR.bi S - - - - AM.LRRRR N - AM.LRRRR W - AM.LRRRR S - AM.LRRRR E - BA.LR S - BA.CccR+ S - BA.CccR N - BA.CRRR S - CA.RrR.1 W - GQ.CRc S - GQ.CRcR.1 S - GQ.CRcR.1 N - IC.LRFR E - IC.RRR.i S - KS.CcRR! S - KS.CcRR! E - DG.LRRR.d E - DG.RRR.g S - DG.CRRR.p S - TO.CccR S - TB.LRRR E - TU.CRRR W - TU.CRRR E - TU.CRRR S - TU.RCR W - TU.RR E - TU.RRRR N - TU.RRRR W - TU.RRRR E - TU.RRRR S - CC.CR E - BB.CFR! E - BB.CFR.b S - BB.RFR.b S - BB.RFR.bi N - CU.SRCR E - CU.SRCR W - CU.SR S - CU.SRFR N - CU.SRFR S - C2.RRr E - C2.RCR W - C2.RRRr N - C2.RRRr E - - - - CU.SCFR S - TB.CRc.w S - TB.CRc.g S - TB.CRcR.w N - TB.CRcR.w S - C2.CFR S - - - TB.RCc!.g S - TB.CcRR!.c S - TB.CccR.w S - - - - IC.CRcR+ N - - - - TO.CcR! E - TB.CcRR!.c E - TB.CcR!.w E - - - - IC.LRFR W - DG.LRRR.d W - TB.LRRR W - CA.RRr.2 W - - - - BA.CRRR W - IC.RRR.i W - DG.LRRR.d S - DG.RRR.g W - DG.CRRR.p W - TB.LRRR S - - - - C2.RCR E - - - - BA.CRRR E - IC.RRR.i E - DG.RRR.g E - DG.CRRR.p E - - - - AM.RC W - GQ.CcCR S - KS.CRrR W - - - - AM.CCRR E - GQ.CRRr E - TB.CcRC.c E - TB.CcRC.g E - TB.CR E - - - - IC.RCc.i S - TB.RCc.g S - TB.CcRR.w S - GQ.RCc S - - - - TB.CcRR.w E - - - - TU.RCR E - - - - - SI.RCr WE - BB.LRFr WE - - - - SI.CcRr SE - - - - TO.RCr WE - - - - AM.CRcr+ NS - DG.CRcr.d NS - - - - AM.RrC SW - - - - AM.CCRR S - - - - WR.CFR W - - - - AM.CRr SE - - - - FL.RFr.d WE - - - - FL.RFr.NS.o NS - - - - FL.RFr.WE.o WE - - - - FL.Rr.NW.o NW - - - - FL.Rr.d SE - - - - IC.CcRr+.i SE - - - - IC.CRcR+ S - - - - R1.LIRI S - - - - - - - * N - - - - * NW - - - - * _N - - - - * WE - * NS - - - - DG.CRcr.d WE - TB.CRcR.w WE - - - - TB.CCc.c WE - TB.CCc.w WE - - - - BA.C N - BA.CFC.2 N - CA.CFC N - IC.CCCC W - IC.CCC E - IC.CRCR N - IC.RrC.i N - R2.IFC E - CC.RrC N - WR.RrC N - - - - BA.CRr N - DG.RrC.g N - - - - BA.RCr N - BA.CFC.2 S - CA.CFC S - GQ.CRCr.2 S - IC.CRCR S - TO.CRCr.2 S - TB.CR N - AM.RC N - AM.RrC N - CC.CR N - - - - BA.CRRR N - CA.C N - IC.CFR N - DG.CRRR.p N - C2.RCR N - - - - BA.RrC N - GQ.CRRr N - KS.LC N - KS.CRrR N - DG.C.d N - DG.RrC.d N - DG.CRr.d N - DG.CRr.g N - TO.RrC N - TB.RRC N - - - - BA.CC.2 N - CC.CC.2 E - GQ.CcCR E - TO.CC.2 N - R1.CICI S - IC.CCC W - IC.CCCC E - IC.CCc+ S - DG.CC.v E - AM.CCRR N - TB.CcCC.c S - TB.CcRC.c S - TB.CcRC.g S - - - - BA.CC.2 W - CC.CC.2 N - IC.CCC N - IC.CCCC N - IC.CCCC S - DG.CC.v N - AM.CCRR W - TO.CC.2 W - TB.CcCC.c E - TU.CRRR N - TU.RCR N - CU.SCFR N - CU.SC N - CU.SRCR N - C2.CFC N - - - - TO.CccC+ S - TB.CCc.c S - TB.CCc.w S - R1.CICI N - - - - BB.CFR.b N - C2.CFR N - C2.CFC S - - - - WR.CFR E - - - - - BA.Cc.1 NW - BA.Cc+ NW - CA.Cc+ NW - DG.Cc.d NW - DG.Cc.p NW - TB.CcR.c NW - CC.Cc.1 NW - - - - TB.CcCc.w SE - C2.CcCc SE - - - - IC.CcRr+.i NW - - - - IC.CCc+ NW - TB.CcRC.c NW - TB.CcRC.g NW - - - - GQ.RCc NW - IC.RCc.i NW - TB.CcCC.c NW - TB.CcRR.w NW - TB.RCc.g NW - - - - DG.CCc+.p SE - C2.CcCc NW - - - - KS.CcRR! NW - DG.Cc!.p NW - TO.CcR! NW - TB.CcRR!.c NW - TB.CcR!.w NW - TB.RCc!.g NW - - - - - IC.C! N - BB.CFR! W - - - - TB.CccR.w _S - - - - - DG.CCc+.p N - - - - - DG.LCcc.d _S - - - - SI.Cc NW - SI.CcRr NW - - - - SI.C N - - - - SI.RCr N - - - - R2.CIcI WE - - - - TO.CccC+ _S - - - - CA.C! E - - - - R1.CIRI N - - - - AM.C!+ W - - - - AM.CCc+ N - - - - AM.CCc+ WE - AM.CCcc+ WE - - - - AM.CCcc+ NS - - - - BB.LCFc WE - - - - - - edge-W - - CA.C! NL.NR - BB.CFR! NL.NR - AM.C!+ NL.NR - IC.C! EL.ER - TB.RCc!.g EL.ER - DG.Cc!.p EL.ER - AM.C!+ EL.ER - TB.CcR!.w SL.SR - DG.LCcc.d SL.SR - DG.Cc!.p SL.SR - TO.CcR! SL.SR - AM.C!+ SL.SR - - - edge-NR - - TB.CcRR!.c ER - TB.CcR!.w ER - KS.CcRR! ER - TO.CcR! ER - AM.CRcr+ NR - - - edge-NL - - BB.CFR! EL - TB.CcRR!.c SL - TB.RCc!.g SL - AM.CRcr+ NL - KS.CcRR! SL - - - oblique-NL,WR - - R2.II+ NL.WR - R1.RrII NR.EL - BA.CcRr ER.SL - BA.CcRr+ ER.SL - CA.RrR.1 ER.SL - SI.CcRr ER.SL - IC.RrRr ER.SL - IC.CcRr+.i ER.SL - KS.CRrR ER.SL - DG.LCcc.d ER.SL - DG.CcRr.p ER.SL - DG.RrRr.g ER.SL - TO.RrRr.2 ER.SL - GQ.CRRr SR.WL - R1.CcII ER.SL - R1.II SR.WL - R1.RrII SR.WL - FL.Rr.SW.o SR.WL - C2.RRRr SR.WL - WR.Rr SR.WL - WR.RrC SR.WL - - - half-oblique-NL,WR - - DG.RrRr.g NL.WR - TO.RrRr.2 NL.WR - IC.RrRr NL.WR - CA.RRr.2 NR.EL - BA.CRr ER.SL - BA.CRRR ER.SL - IC.RRR.i ER.SL - DG.RRR.g ER.SL - DG.CRRR.p ER.SL - DG.CcRr.g ER.SL - DG.CRr.d ER.SL - DG.CRr.g ER.SL - BA.CRRR SR.WL - BA.RrC SR.WL - IC.RrC.i SR.WL - IC.RRR.i SR.WL - DG.RRR.g SR.WL - DG.CRRR.p SR.WL - DG.RrC.d SR.WL - DG.RrC.g SR.WL - TO.RrC SR.WL - CC.Rr SR.WL - C2.RRr SR.WL - - - under lcurved-NW - - IC.RCc.i SR - TB.RCc.g SR - TB.CcRR.w SR - GQ.RCc SR - - - - TB.CcRR.w EL - - - - SI.RCr ER.SL.SR.WL - BB.LRFr ER.SL.SR.WL - - - - DG.CCc+.p WL.WR - - - - AM.CRr ER.SL - - - - AM.RrC WR - - - - AM.CCRR SR - - - - TU.RCR ER.SL.SR.WL - - - - FL.RFr.d ER.SL.SR.WL - - - - FL.RFr.NS.o NR.EL.ER.SL - - - - FL.RFr.WE.o ER.SL.SR.WL - - - - FL.Rr.d ER.SL - - - - FL.Rr.NW.o NL.WR - - - - WR.CFR SL.SR.WL - - - - - - * TOWER - - - - TO.RRRR.1 TOWER - - - - TO.RRR TOWER - - - - TO.C TOWER - TO.CC.2 TOWER - - - - TO.Cc TOWER - - - - TO.L TOWER - TO.RrRr.2 TOWER - TO.CccR TOWER - - - - TO.CRCr.2 TOWER - - - - TO.CRcr TOWER - - - - TO.CcR! TOWER - TO.CccC+ TOWER - - - - TO.RrC TOWER - - - - TO.RCr TOWER - - - - TO.CFR TOWER - - - - BA.CcRr EL.SR - BA.CcRr+ EL.SR - BA.CRr EL.WL.WR.SR - BA.RrC WR.EL.ER.SL - IC.CCC SL.SR - IC.CCc+ EL.ER - IC.RCc.i SL.EL.ER - IC.RrC.i WR.EL.ER.SL - IC.CcRr+.i SR.EL - IC.RrRr NR.EL.SR.WL - TB.Ccc.g SL.SR - TB.CcRR.w SL.ER - TB.CcRC.c ER - TB.CcRC.g ER - TB.CcR.c ER.SL.SR - TB.CR WL.WR.SL.SR.ER - TB.RCc.g SL.EL.ER - TB.RRC EL.ER.SL - DG.RrRr.g NR.EL.SR.WL - DG.CcRr.p EL.SR - DG.CcRr.g EL.SR - DG.RrC.d WR.EL.ER.SL - DG.RrC.g WR.EL.ER.SL - DG.CRr.d EL.WL.WR.SR - DG.CRr.g EL.WL.WR.SR - TO.RrRr.2 NR.EL.SR.WL - TO.RrC WR.EL.ER.SL - TO.RCr WL.SL.SR.ER - AM.CCRR SL.ER - AM.RC EL.ER.SL.SR.WL - AM.RrC SR.WL - KS.CRrR EL.SR.WL - R1.CcII SR.EL - R1.RrII WR.NL.ER.SL - SI.RCr WR.EL - BB.LRFr WR.EL - SI.CcRr EL.SR - GQ.CRRr ER.SL.WR - GQ.RCc SL.EL.ER - GQ.CcCR SL - FL.RFr.d WR.NL.NR.EL - FL.RFr.NS.o SR.WL.WR.NL - FL.RFr.WE.o WR.NL.NR.EL - FL.Rr.d SR.WL.WR.NL.NR.EL - FL.Rr.NW.o NR.EL.ER.SL.SR.WL - C2.RRRr WR.NL.ER.SL - TU.RCR EL.WR - WR.CFR WR.NL.NR - WR.RrC EL.ER.SL.WR - - - - - BA.RRR - BA.RRRR - DG.CRRR - DG.RRR.d - DG.RRR.g - CA.RFR - CA.RR - CC.RRR - - - - C2.RRr - C2.RCR - - - - IC.CRCR - - - - C2.RRRr - - - - - R1.LIRI - R2.LIFI - - - - R1.CIRI - R2.CIcI - - - - R1.CICI - R1.IFI - R1.RIrI - - - - R1.RrII - R1.II - R2.II+ - R1.CcII - - - - R2.III - - - - R2.IFC - - - - - - TU.CRRR - - - - TU.RR - - - - TU.RRRR - - - - TU.RCR - + + + + + + + + + * CLOISTER + + + + BA.LR CLOISTER + AM.LRRRR CLOISTER + FE.LRR CLOISTER + + + + R1.LIRI CLOISTER + R2.LIFI CLOISTER + + + + KS.LC CLOISTER + + + + DG.LCcc.d CLOISTER + + + + TO.L CLOISTER + + + + TB.LRRR CLOISTER + + + + CA.L CLOISTER + + + + AM.A CLOISTER + + + + + CU.S CLOISTER + CU.SR CLOISTER + CU.SRFR CLOISTER + + + + CU.SC CLOISTER + CU.SCFR CLOISTER + CU.SRCR CLOISTER + + + + + + + + * _N + + + + * NW + + + + + * NWSE + + + + BA.CcRr SE + BA.CcRr+ SE + CA.RrR.1 SE + GQ.CRRr SW + IC.RrRr SE + KS.CRrR SE + DG.RrRr.g SE + DG.CcRr.p SE + R1.RrII NE + TO.RrRr.2 NW + TO.RrRr.2 SE + FL.Rr.SW.o SW + C2.RRRr SW + WR.Rr SW + WR.RrC SW + + + + BA.CRr SE + BA.RrC SW + CA.RRr.2 NE + IC.RrRr NW + DG.RrRr.g NW + DG.Rr.v SW + DG.CcRr.g SE + DG.RrC.d SW + DG.RrC.g SW + DG.CRr.d SE + DG.CRr.g SE + TO.RrC SW + CC.Rr SW + C2.RRr SW + + + + IC.RrC.i SW + + + + AM.R S + IC.CFR S + IC.CcR E + R1.CIRI S + TB.CcR.c E + TB.RRC W + TB.RRC S + BB.R.bi S + BB.RFR.b N + BB.RFR.bi S + + + + AM.LRRRR N + AM.LRRRR W + AM.LRRRR S + AM.LRRRR E + BA.LR S + BA.CccR+ S + BA.CccR N + BA.CRRR S + CA.RrR.1 W + GQ.CRc S + GQ.CRcR.1 S + GQ.CRcR.1 N + IC.LRFR E + IC.RRR.i S + KS.CcRR! S + KS.CcRR! E + DG.LRRR.d E + DG.RRR.g S + DG.CRRR.p S + TO.CccR S + TB.LRRR E + TU.CRRR W + TU.CRRR E + TU.CRRR S + TU.RCR W + TU.RR E + TU.RRRR N + TU.RRRR W + TU.RRRR E + TU.RRRR S + CC.CR E + BB.CFR! E + BB.CFR.b S + BB.RFR.b S + BB.RFR.bi N + CU.SRCR E + CU.SRCR W + CU.SR S + CU.SRFR N + CU.SRFR S + C2.RRr E + C2.RCR W + C2.RRRr N + C2.RRRr E + + + + CU.SCFR S + TB.CRc.w S + TB.CRc.g S + TB.CRcR.w N + TB.CRcR.w S + C2.CFR S + + + TB.RCc!.g S + TB.CcRR!.c S + TB.CccR.w S + + + + IC.CRcR+ N + + + + TO.CcR! E + TB.CcRR!.c E + TB.CcR!.w E + + + + IC.LRFR W + DG.LRRR.d W + TB.LRRR W + CA.RRr.2 W + + + + BA.CRRR W + IC.RRR.i W + DG.LRRR.d S + DG.RRR.g W + DG.CRRR.p W + TB.LRRR S + + + + C2.RCR E + + + + BA.CRRR E + IC.RRR.i E + DG.RRR.g E + DG.CRRR.p E + + + + AM.RC W + GQ.CcCR S + KS.CRrR W + + + + AM.CCRR E + GQ.CRRr E + TB.CcRC.c E + TB.CcRC.g E + TB.CR E + + + + IC.RCc.i S + TB.RCc.g S + TB.CcRR.w S + GQ.RCc S + + + + TB.CcRR.w E + + + + TU.RCR E + + + + + SI.RCr WE + BB.LRFr WE + + + + SI.CcRr SE + + + + TO.RCr WE + + + + AM.CRcr+ NS + DG.CRcr.d NS + + + + AM.RrC SW + + + + AM.CCRR S + + + + WR.CFR W + + + + AM.CRr SE + + + + FL.RFr.d WE + + + + FL.RFr.NS.o NS + + + + FL.RFr.WE.o WE + + + + FL.Rr.NW.o NW + + + + FL.Rr.d SE + + + + IC.CcRr+.i SE + + + + IC.CRcR+ S + + + + R1.LIRI S + + + + + + + * N + + + + * NW + + + + * _N + + + + * WE + * NS + + + + DG.CRcr.d WE + TB.CRcR.w WE + + + + TB.CCc.c WE + TB.CCc.w WE + + + + BA.C N + BA.CFC.2 N + CA.CFC N + IC.CCCC W + IC.CCC E + IC.CRCR N + IC.RrC.i N + R2.IFC E + CC.RrC N + WR.RrC N + + + + BA.CRr N + DG.RrC.g N + + + + BA.RCr N + BA.CFC.2 S + CA.CFC S + GQ.CRCr.2 S + IC.CRCR S + TO.CRCr.2 S + TB.CR N + AM.RC N + AM.RrC N + CC.CR N + + + + BA.CRRR N + CA.C N + IC.CFR N + DG.CRRR.p N + C2.RCR N + + + + BA.RrC N + GQ.CRRr N + KS.LC N + KS.CRrR N + DG.C.d N + DG.RrC.d N + DG.CRr.d N + DG.CRr.g N + TO.RrC N + TB.RRC N + + + + BA.CC.2 N + CC.CC.2 E + GQ.CcCR E + TO.CC.2 N + R1.CICI S + IC.CCC W + IC.CCCC E + IC.CCc+ S + DG.CC.v E + AM.CCRR N + TB.CcCC.c S + TB.CcRC.c S + TB.CcRC.g S + + + + BA.CC.2 W + CC.CC.2 N + IC.CCC N + IC.CCCC N + IC.CCCC S + DG.CC.v N + AM.CCRR W + TO.CC.2 W + TB.CcCC.c E + TU.CRRR N + TU.RCR N + CU.SCFR N + CU.SC N + CU.SRCR N + C2.CFC N + + + + TO.CccC+ S + TB.CCc.c S + TB.CCc.w S + R1.CICI N + + + + BB.CFR.b N + C2.CFR N + C2.CFC S + + + + WR.CFR E + + + + + BA.Cc.1 NW + BA.Cc+ NW + CA.Cc+ NW + DG.Cc.d NW + DG.Cc.p NW + TB.CcR.c NW + CC.Cc.1 NW + + + + TB.CcCc.w SE + C2.CcCc SE + + + + IC.CcRr+.i NW + + + + IC.CCc+ NW + TB.CcRC.c NW + TB.CcRC.g NW + + + + GQ.RCc NW + IC.RCc.i NW + TB.CcCC.c NW + TB.CcRR.w NW + TB.RCc.g NW + + + + DG.CCc+.p SE + C2.CcCc NW + + + + KS.CcRR! NW + DG.Cc!.p NW + TO.CcR! NW + TB.CcRR!.c NW + TB.CcR!.w NW + TB.RCc!.g NW + + + + + IC.C! N + BB.CFR! W + + + + TB.CccR.w _S + + + + + DG.CCc+.p N + + + + + DG.LCcc.d _S + + + + SI.Cc NW + SI.CcRr NW + + + + SI.C N + + + + SI.RCr N + + + + R2.CIcI WE + + + + TO.CccC+ _S + + + + CA.C! E + + + + R1.CIRI N + + + + AM.C!+ W + + + + AM.CCc+ N + + + + AM.CCc+ WE + AM.CCcc+ WE + + + + AM.CCcc+ NS + + + + BB.LCFc WE + + + + + + edge-W + + CA.C! NL.NR + BB.CFR! NL.NR + AM.C!+ NL.NR + IC.C! EL.ER + TB.RCc!.g EL.ER + DG.Cc!.p EL.ER + AM.C!+ EL.ER + TB.CcR!.w SL.SR + DG.LCcc.d SL.SR + DG.Cc!.p SL.SR + TO.CcR! SL.SR + AM.C!+ SL.SR + + + edge-NR + + TB.CcRR!.c ER + TB.CcR!.w ER + KS.CcRR! ER + TO.CcR! ER + AM.CRcr+ NR + + + edge-NL + + BB.CFR! EL + TB.CcRR!.c SL + TB.RCc!.g SL + AM.CRcr+ NL + KS.CcRR! SL + + + oblique-NL,WR + + R2.II+ NL.WR + R1.RrII NR.EL + BA.CcRr ER.SL + BA.CcRr+ ER.SL + CA.RrR.1 ER.SL + SI.CcRr ER.SL + IC.RrRr ER.SL + IC.CcRr+.i ER.SL + KS.CRrR ER.SL + DG.LCcc.d ER.SL + DG.CcRr.p ER.SL + DG.RrRr.g ER.SL + TO.RrRr.2 ER.SL + GQ.CRRr SR.WL + R1.CcII ER.SL + R1.II SR.WL + R1.RrII SR.WL + FL.Rr.SW.o SR.WL + C2.RRRr SR.WL + WR.Rr SR.WL + WR.RrC SR.WL + + + half-oblique-NL,WR + + DG.RrRr.g NL.WR + TO.RrRr.2 NL.WR + IC.RrRr NL.WR + CA.RRr.2 NR.EL + BA.CRr ER.SL + BA.CRRR ER.SL + IC.RRR.i ER.SL + DG.RRR.g ER.SL + DG.CRRR.p ER.SL + DG.CcRr.g ER.SL + DG.CRr.d ER.SL + DG.CRr.g ER.SL + BA.CRRR SR.WL + BA.RrC SR.WL + IC.RrC.i SR.WL + IC.RRR.i SR.WL + DG.RRR.g SR.WL + DG.CRRR.p SR.WL + DG.RrC.d SR.WL + DG.RrC.g SR.WL + TO.RrC SR.WL + CC.Rr SR.WL + C2.RRr SR.WL + + + under lcurved-NW + + IC.RCc.i SR + TB.RCc.g SR + TB.CcRR.w SR + GQ.RCc SR + + + + TB.CcRR.w EL + + + + SI.RCr ER.SL.SR.WL + BB.LRFr ER.SL.SR.WL + + + + DG.CCc+.p WL.WR + + + + AM.CRr ER.SL + + + + AM.RrC WR + + + + AM.CCRR SR + + + + TU.RCR ER.SL.SR.WL + + + + FL.RFr.d ER.SL.SR.WL + + + + FL.RFr.NS.o NR.EL.ER.SL + + + + FL.RFr.WE.o ER.SL.SR.WL + + + + FL.Rr.d ER.SL + + + + FL.Rr.NW.o NL.WR + + + + WR.CFR SL.SR.WL + + + + + + * TOWER + + + + TO.RRRR.1 TOWER + + + + TO.RRR TOWER + + + + TO.C TOWER + TO.CC.2 TOWER + + + + TO.Cc TOWER + + + + TO.L TOWER + TO.RrRr.2 TOWER + TO.CccR TOWER + + + + TO.CRCr.2 TOWER + + + + TO.CRcr TOWER + + + + TO.CcR! TOWER + TO.CccC+ TOWER + + + + TO.RrC TOWER + + + + TO.RCr TOWER + + + + TO.CFR TOWER + + + + BA.CcRr EL.SR + BA.CcRr+ EL.SR + BA.CRr EL.WL.WR.SR + BA.RrC WR.EL.ER.SL + IC.CCC SL.SR + IC.CCc+ EL.ER + IC.RCc.i SL.EL.ER + IC.RrC.i WR.EL.ER.SL + IC.CcRr+.i SR.EL + IC.RrRr NR.EL.SR.WL + TB.Ccc.g SL.SR + TB.CcRR.w SL.ER + TB.CcRC.c ER + TB.CcRC.g ER + TB.CcR.c ER.SL.SR + TB.CR WL.WR.SL.SR.ER + TB.RCc.g SL.EL.ER + TB.RRC EL.ER.SL + DG.RrRr.g NR.EL.SR.WL + DG.CcRr.p EL.SR + DG.CcRr.g EL.SR + DG.RrC.d WR.EL.ER.SL + DG.RrC.g WR.EL.ER.SL + DG.CRr.d EL.WL.WR.SR + DG.CRr.g EL.WL.WR.SR + TO.RrRr.2 NR.EL.SR.WL + TO.RrC WR.EL.ER.SL + TO.RCr WL.SL.SR.ER + AM.CCRR SL.ER + AM.RC EL.ER.SL.SR.WL + AM.RrC SR.WL + KS.CRrR EL.SR.WL + R1.CcII SR.EL + R1.RrII WR.NL.ER.SL + SI.RCr WR.EL + BB.LRFr WR.EL + SI.CcRr EL.SR + GQ.CRRr ER.SL.WR + GQ.RCc SL.EL.ER + GQ.CcCR SL + FL.RFr.d WR.NL.NR.EL + FL.RFr.NS.o SR.WL.WR.NL + FL.RFr.WE.o WR.NL.NR.EL + FL.Rr.d SR.WL.WR.NL.NR.EL + FL.Rr.NW.o NR.EL.ER.SL.SR.WL + C2.RRRr WR.NL.ER.SL + TU.RCR EL.WR + WR.CFR WR.NL.NR + WR.RrC EL.ER.SL.WR + + + + + BA.RRR + BA.RRRR + DG.CRRR + DG.RRR.d + DG.RRR.g + CA.RFR + CA.RR + CC.RRR + + + + C2.RRr + C2.RCR + + + + IC.CRCR + + + + C2.RRRr + + + + + R1.LIRI + R2.LIFI + + + + R1.CIRI + R2.CIcI + + + + R1.CICI + R1.IFI + R1.RIrI + + + + R1.RrII + R1.II + R2.II+ + R1.CcII + + + + R2.III + + + + R2.IFC + + + + + + TU.CRRR + + + + TU.RR + + + + TU.RRRR + + + + TU.RCR + \ No newline at end of file diff --git a/src/main/resources/plugins/fallback/plugin.xml b/src/main/resources/plugins/fallback/plugin.xml index cc360f11d..6d79b0f49 100644 --- a/src/main/resources/plugins/fallback/plugin.xml +++ b/src/main/resources/plugins/fallback/plugin.xml @@ -1,9 +1,9 @@ - - - Default tiles - Fallback graphics if no plugin is present - - BASIC - WINTER - + + + Default tiles + Fallback graphics if no plugin is present + + BASIC + WINTER + \ No newline at end of file diff --git a/src/main/resources/plugins/rgg_siege/plugin.xml b/src/main/resources/plugins/rgg_siege/plugin.xml index 32337cf61..07344da41 100644 --- a/src/main/resources/plugins/rgg_siege/plugin.xml +++ b/src/main/resources/plugins/rgg_siege/plugin.xml @@ -1,8 +1,8 @@ - - - RGG's siege - Graphics from RGG's version of The Cathars expansion - - CATHARS - + + + RGG's siege + Graphics from RGG's version of The Cathars expansion + + CATHARS + \ No newline at end of file diff --git a/src/main/resources/plugins/rgg_siege/tiles/points.xml b/src/main/resources/plugins/rgg_siege/tiles/points.xml index 5df995ba2..bea4f4dba 100644 --- a/src/main/resources/plugins/rgg_siege/tiles/points.xml +++ b/src/main/resources/plugins/rgg_siege/tiles/points.xml @@ -1,6 +1,6 @@ - - - - SI.CcRr SE - + + + + SI.CcRr SE + \ No newline at end of file diff --git a/src/main/resources/plugins/rgg_siege/tiles/shapes.xml b/src/main/resources/plugins/rgg_siege/tiles/shapes.xml index 7380ed5b0..9bd02724c 100644 --- a/src/main/resources/plugins/rgg_siege/tiles/shapes.xml +++ b/src/main/resources/plugins/rgg_siege/tiles/shapes.xml @@ -1,28 +1,28 @@ - - - - - SI.CcRr SE - - - - - SI.C N - SI.RCr N - - - - SI.Cc NW - SI.CcRr NW - - - - - SI.CcRr ER.SL - - - - SI.CcRr EL.SR - SI.RCr EL.WR - + + + + + SI.CcRr SE + + + + + SI.C N + SI.RCr N + + + + SI.Cc NW + SI.CcRr NW + + + + + SI.CcRr ER.SL + + + + SI.CcRr EL.SR + SI.RCr EL.WR + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/abbey_and_mayor.xml b/src/main/resources/tile-definitions/abbey_and_mayor.xml index c62762a20..6faa3ebbe 100644 --- a/src/main/resources/tile-definitions/abbey_and_mayor.xml +++ b/src/main/resources/tile-definitions/abbey_and_mayor.xml @@ -1,94 +1,94 @@ - - - - - - - N E S W - - - N S - W E - - - N - W E - SL SR - - - N - W - E - S - EL - SR - ER SL - - N E - S W - - - - - N - W - S - E - WR NL - NR EL - ER SL - SR WL - - CLOISTER N - CLOISTER W - CLOISTER E - CLOISTER S - - - - N - W - WR - EL ER SL SR WL - - N W - - - - N - S E - WL WR SR - EL - ER SL - - - N - W S - EL ER SL - WR - SR WL - - - W - NL NR - EL ER - SL SR - - - S - NL NR EL ER SL SR WL WR - - - N W E - WR NL - NR EL - ER SL SR WL - - - W E - N S - SL SR - NL - NR - + + + + + + + N E S W + + + N S + W E + + + N + W E + SL SR + + + N + W + E + S + EL + SR + ER SL + + N E + S W + + + + + N + W + S + E + WR NL + NR EL + ER SL + SR WL + + CLOISTER N + CLOISTER W + CLOISTER E + CLOISTER S + + + + N + W + WR + EL ER SL SR WL + + N W + + + + N + S E + WL WR SR + EL + ER SL + + + N + W S + EL ER SL + WR + SR WL + + + W + NL NR + EL ER + SL SR + + + S + NL NR EL ER SL SR WL WR + + + N W E + WR NL + NR EL + ER SL SR WL + + + W E + N S + SL SR + NL + NR + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/basic.xml b/src/main/resources/tile-definitions/basic.xml index 3a9dcc855..5b5cb06ab 100644 --- a/src/main/resources/tile-definitions/basic.xml +++ b/src/main/resources/tile-definitions/basic.xml @@ -1,155 +1,155 @@ - - - - - NL NR EL ER SL SR WL WR - - - - S - NL NR EL ER SL SR WL WR - - CLOISTER S - - - - - W E - N - EL WR - ER SL SR WL - - - - - N W S E - - - S - N W E - SL - SR - - N S - - - - S - N W E - SL - SR - - N S - - - - W E - NL NR - SL SR - - - W E - NL NR - SL SR - - - N W - SL SR EL ER - - - N W - SL SR EL ER - - - E S - N W - EL SR - ER SL - - - E S - N W - EL SR - ER SL - - - N E W - SL SR - - - N E W - SL SR - - - E S - N - EL WL WR SR - ER SL - - - E - S - W - N - WR EL - WL SR - ER SL - - W S E - - - - S W - N - WR EL ER SL - WL SR - - - N - WL WR SL SR EL ER - - - N - S - WL WR EL ER - - - N - W - EL ER SL SR - - - N - E - S - W - WR NL - NR EL - ER SL - SR WL - - N E S W - - - - E - S - W - WR NL NR EL - ER SL - SR WL - - E S W - - - - W S - WR NL NR EL ER SL - SR WL - - - W E - WR NL NR EL - ER SL SR WL - + + + + + NL NR EL ER SL SR WL WR + + + + S + NL NR EL ER SL SR WL WR + + CLOISTER S + + + + + W E + N + EL WR + ER SL SR WL + + + + + N W S E + + + S + N W E + SL + SR + + N S + + + + S + N W E + SL + SR + + N S + + + + W E + NL NR + SL SR + + + W E + NL NR + SL SR + + + N W + SL SR EL ER + + + N W + SL SR EL ER + + + E S + N W + EL SR + ER SL + + + E S + N W + EL SR + ER SL + + + N E W + SL SR + + + N E W + SL SR + + + E S + N + EL WL WR SR + ER SL + + + E + S + W + N + WR EL + WL SR + ER SL + + W S E + + + + S W + N + WR EL ER SL + WL SR + + + N + WL WR SL SR EL ER + + + N + S + WL WR EL ER + + + N + W + EL ER SL SR + + + N + E + S + W + WR NL + NR EL + ER SL + SR WL + + N E S W + + + + E + S + W + WR NL NR EL + ER SL + SR WL + + E S W + + + + W S + WR NL NR EL ER SL + SR WL + + + W E + WR NL NR EL + ER SL SR WL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/bridges_castles_and_bazaars.xml b/src/main/resources/tile-definitions/bridges_castles_and_bazaars.xml index b43e34b35..7d3569439 100644 --- a/src/main/resources/tile-definitions/bridges_castles_and_bazaars.xml +++ b/src/main/resources/tile-definitions/bridges_castles_and_bazaars.xml @@ -1,81 +1,81 @@ - - - - - N E S W - - - W - N - E - S - SR - SL - - S E - - - - - W E - NL NR - SL SR - - - W - E - NL NR - EL - ER SL SR - - W E - - - - - N - S - EL ER SL SR WL WR - - - - NL NR EL ER SL SR WL WR - - - - W E - NL NR - SL SR - - - - W E - WR NL NR EL - ER SL SR WL - - - - S - NL NR EL ER SL SR WL WR - - - - N - S - SR WL WR NL - NR EL ER SL - - N S - - - - - N - S - SR WL WR NL - NR EL ER SL - - N S - - + + + + + N E S W + + + W + N + E + S + SR + SL + + S E + + + + + W E + NL NR + SL SR + + + W + E + NL NR + EL + ER SL SR + + W E + + + + + N + S + EL ER SL SR WL WR + + + + NL NR EL ER SL SR WL WR + + + + W E + NL NR + SL SR + + + + W E + WR NL NR EL + ER SL SR WL + + + + S + NL NR EL ER SL SR WL WR + + + + N + S + SR WL WR NL + NR EL ER SL + + N S + + + + + N + S + SR WL WR NL + NR EL ER SL + + N S + + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/catapult.xml b/src/main/resources/tile-definitions/catapult.xml index fbc62c3f3..b3eff4a81 100644 --- a/src/main/resources/tile-definitions/catapult.xml +++ b/src/main/resources/tile-definitions/catapult.xml @@ -1,70 +1,70 @@ - - - - N - WL WR SL SR EL ER - - - E - NL NR - WL WR SL SR - - - N W - SL SR EL ER - - - N W S E - - - N - S - WL WR - EL ER - - - NL NR EL ER SL SR WL WR - - - - WR NL NR EL - WL SL SR ER - - - N - S - NR EL ER SL - SR WL WR NL - - N S - - - - W - S - WR NL NR EL ER SL - WL SR - - W S - - - - W - S E - SR WL WR NL NR EL - ER SL - - - W - N E - NL WL WR SL SR ER - NR EL - - - N E S W - WR NL - NR EL - ER SL - SR WL - - + + + + N + WL WR SL SR EL ER + + + E + NL NR + WL WR SL SR + + + N W + SL SR EL ER + + + N W S E + + + N + S + WL WR + EL ER + + + NL NR EL ER SL SR WL WR + + + + WR NL NR EL + WL SL SR ER + + + N + S + NR EL ER SL + SR WL WR NL + + N S + + + + W + S + WR NL NR EL ER SL + WL SR + + W S + + + + W + S E + SR WL WR NL NR EL + ER SL + + + W + N E + NL WL WR SL SR ER + NR EL + + + N E S W + WR NL + NR EL + ER SL + SR WL + + diff --git a/src/main/resources/tile-definitions/cathars.xml b/src/main/resources/tile-definitions/cathars.xml index 8461429ba..b67082ee2 100644 --- a/src/main/resources/tile-definitions/cathars.xml +++ b/src/main/resources/tile-definitions/cathars.xml @@ -1,23 +1,23 @@ - - - - N - WL WR SL SR EL ER - - - N - W E - WR EL - WL SL SR ER - - - N W - EL ER SL SR - - - N W - S E - EL SR - ER SL - + + + + N + WL WR SL SR EL ER + + + N + W E + WR EL + WL SL SR ER + + + N W + EL ER SL SR + + + N W + S E + EL SR + ER SL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/corn_circles.xml b/src/main/resources/tile-definitions/corn_circles.xml index d6fc5f14f..1db83be7c 100644 --- a/src/main/resources/tile-definitions/corn_circles.xml +++ b/src/main/resources/tile-definitions/corn_circles.xml @@ -1,42 +1,42 @@ - - - - - N W - SL SR EL ER - - - - N - E - SL SR WL WR - - - - N - E - WL WR SL SR EL ER - - - - W S - WR NL NR EL ER SL - SR WL - - - - S W - N - WR EL ER SL - WL SR - - - - N - W - S - NR EL ER SL - SR WL - WR NL - + + + + + N W + SL SR EL ER + + + + N + E + SL SR WL WR + + + + N + E + WL WR SL SR EL ER + + + + W S + WR NL NR EL ER SL + SR WL + + + + S W + N + WR EL ER SL + WL SR + + + + N + W + S + NR EL ER SL + SR WL + WR NL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/corn_circles_ii.xml b/src/main/resources/tile-definitions/corn_circles_ii.xml index 04f2b5954..34d4f9a6a 100644 --- a/src/main/resources/tile-definitions/corn_circles_ii.xml +++ b/src/main/resources/tile-definitions/corn_circles_ii.xml @@ -1,46 +1,46 @@ - - - - - W S - E - WR NL NR EL - ER SL - SR WL - - - - W S - N - E - WR NL ER SL - NR EL - SR WL - - - - N - S - ER ER SL SR EL ER - - - - N - W - E - WR EL - ER SL SR WL - - - - N - S - WL WR - EL ER - - - - W N - E S - + + + + + W S + E + WR NL NR EL + ER SL + SR WL + + + + W S + N + E + WR NL ER SL + NR EL + SR WL + + + + N + S + ER ER SL SR EL ER + + + + N + W + E + WR EL + ER SL SR WL + + + + N + S + WL WR + EL ER + + + + W N + E S + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/count.xml b/src/main/resources/tile-definitions/count.xml index 4346482ff..ae8c24bfd 100644 --- a/src/main/resources/tile-definitions/count.xml +++ b/src/main/resources/tile-definitions/count.xml @@ -1,57 +1,57 @@ - - - - W - WR NL NR EL - WL SR - - - - WR NL NR EL - - - - WR NL NR EL - - - - N - WR NL - NR EL ER SL - - - - SR WL WR NL - - - - - - - - - - NR EL ER SL - - - - S - WL WR NL ER - - - - ER SL SR WL - - - - S - ER SL - SR WL - - - - E - NR SL SR WL - - + + + + W + WR NL NR EL + WL SR + + + + WR NL NR EL + + + + WR NL NR EL + + + + N + WR NL + NR EL ER SL + + + + SR WL WR NL + + + + + + + + + + NR EL ER SL + + + + S + WL WR NL ER + + + + ER SL SR WL + + + + S + ER SL + SR WL + + + + E + NR SL SR WL + + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/cult.xml b/src/main/resources/tile-definitions/cult.xml index a2c56e883..24b7d90db 100644 --- a/src/main/resources/tile-definitions/cult.xml +++ b/src/main/resources/tile-definitions/cult.xml @@ -1,52 +1,52 @@ - - - - - NL NR SL SR WL WR EL ER - - - - N - SL SR WL WR EL ER - - - - S - NL NR SL SR WL WR EL ER - - CLOISTER S - - - - - N - S - SL SR WL WR EL ER - - CLOISTER S - - - - - N - S - NL WL WR SR - NR EL ER SL - - CLOISTER N - CLOISTER S - - - - - N - W - E - WR EL - WL SL SR ER - - CLOISTER W - CLOISTER E - - + + + + + NL NR SL SR WL WR EL ER + + + + N + SL SR WL WR EL ER + + + + S + NL NR SL SR WL WR EL ER + + CLOISTER S + + + + + N + S + SL SR WL WR EL ER + + CLOISTER S + + + + + N + S + NL WL WR SR + NR EL ER SL + + CLOISTER N + CLOISTER S + + + + + N + W + E + WR EL + WL SL SR ER + + CLOISTER W + CLOISTER E + + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/festival.xml b/src/main/resources/tile-definitions/festival.xml index 5acf90116..95137abd7 100644 --- a/src/main/resources/tile-definitions/festival.xml +++ b/src/main/resources/tile-definitions/festival.xml @@ -1,94 +1,94 @@ - - - - - W E - S - NL NR - INNER_FARM - - - - N W - S E - INNER_FARM - - - - N - S - WL WR SR - EL ER SL - - N S - - - - - N - E - EL - WL WR SL SR ER - - N E - - - - - N - S - W - E - ER - WL - EL - WR - - N S W E - - - - - E S - N - EL WL WR SR - ER SL - - - - - S - W - WR NL NR EL ER SL - WL SR - - CLOISTER W - CLOISTER S - - - - - N - W - WR - EL ER SL SR WL - - N W - - - - - S W - N - WR EL ER SL - WL SR - - - - N W - S E - NL WR - SL ER - NR EL SR WL - + + + + + W E + S + NL NR + INNER_FARM + + + + N W + S E + INNER_FARM + + + + N + S + WL WR SR + EL ER SL + + N S + + + + + N + E + EL + WL WR SL SR ER + + N E + + + + + N + S + W + E + ER + WL + EL + WR + + N S W E + + + + + E S + N + EL WL WR SR + ER SL + + + + + S + W + WR NL NR EL ER SL + WL SR + + CLOISTER W + CLOISTER S + + + + + N + W + WR + EL ER SL SR WL + + N W + + + + + S W + N + WR EL ER SL + WL SR + + + + N W + S E + NL WR + SL ER + NR EL SR WL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/flier.xml b/src/main/resources/tile-definitions/flier.xml index fd6787837..89b659a3d 100644 --- a/src/main/resources/tile-definitions/flier.xml +++ b/src/main/resources/tile-definitions/flier.xml @@ -1,47 +1,47 @@ - - - - NW - NL NR SL SR WL WR EL ER - - - W - NL NR SL SR WL WR EL ER - - - NW - W E - WR NL NR EL - ER SL SR WL - - - W - N S - SR WL WR NL - NR EL ER SL - - - W - W E - WR NL NR EL - ER SL SR WL - - - NW - S E - SR WL WR NL NR EL - ER SL - - - W - N W - WR NL - NR EL ER SL SR WL - - - W - S W - SR WL - WR NL NR EL ER SL - + + + + NW + NL NR SL SR WL WR EL ER + + + W + NL NR SL SR WL WR EL ER + + + NW + W E + WR NL NR EL + ER SL SR WL + + + W + N S + SR WL WR NL + NR EL ER SL + + + W + W E + WR NL NR EL + ER SL SR WL + + + NW + S E + SR WL WR NL NR EL + ER SL + + + W + N W + WR NL + NR EL ER SL SR WL + + + W + S W + SR WL + WR NL NR EL ER SL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/gq11.xml b/src/main/resources/tile-definitions/gq11.xml index 822f05655..7934abfd7 100644 --- a/src/main/resources/tile-definitions/gq11.xml +++ b/src/main/resources/tile-definitions/gq11.xml @@ -1,117 +1,117 @@ - - - - - - - E - W - WR NL NR EL - ER SL SR WL - - - - W E - N - S - WR EL - WL ER - - - - N - W - S - E - WR NL - NR EL - ER SL - SR WL - - CLOISTER N - CLOISTER W - CLOISTER E - CLOISTER S - - - - NL NR SL SR WL WR EL ER - - - W E - S - NL NR - SR - SL - - W S - - - - W E - S - N - NR - NL - SR - SL - - W S - W N - - - - W E - N - S - WR EL - ER WL - - - E - S W - N - EL - ER SL WR - SR WL - - N E - - - - N W - SL SR - EL ER - - - N W - S - SR - SL EL ER - - N S - - - - N W - S - E - SR - EL - SL ER - - N S - N E - - - - N W - E - S - SR - SL - - W S - - + + + + + + + E + W + WR NL NR EL + ER SL SR WL + + + + W E + N + S + WR EL + WL ER + + + + N + W + S + E + WR NL + NR EL + ER SL + SR WL + + CLOISTER N + CLOISTER W + CLOISTER E + CLOISTER S + + + + NL NR SL SR WL WR EL ER + + + W E + S + NL NR + SR + SL + + W S + + + + W E + S + N + NR + NL + SR + SL + + W S + W N + + + + W E + N + S + WR EL + ER WL + + + E + S W + N + EL + ER SL WR + SR WL + + N E + + + + N W + SL SR + EL ER + + + N W + S + SR + SL EL ER + + N S + + + + N W + S + E + SR + EL + SL ER + + N S + N E + + + + N W + E + S + SR + SL + + W S + + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/inns_and_cathedrals.xml b/src/main/resources/tile-definitions/inns_and_cathedrals.xml index 1fd66d1af..876f8ca77 100644 --- a/src/main/resources/tile-definitions/inns_and_cathedrals.xml +++ b/src/main/resources/tile-definitions/inns_and_cathedrals.xml @@ -1,133 +1,133 @@ - - - - - W - E - ER SL SR WL - EL NL NR WR - - CLOISTER W - CLOISTER E - - - - N W S E - - - N - W - E - S - INNER_FARM - - - N - W - E - SL SR - - - N - S - W - E - ER - WL - EL - WR - - N S W E - - - - N W - S - EL ER - - - N - EL ER - WL WR SL SR - - - N - S - WL WR SR - EL ER SL - - N S - - - - N W - E - EL - ER SL SR - - N E - - - - E W - N - S - NL - NR - SL - SR - - N W - S W - - - - N W - S - SR - SL EL ER - - N S - - - - N - W S - SR WL - WR EL ER SL - - - N W - E S - SL ER - SR EL - - - E - W - S - WR NL NR EL - WL SR - ER SL - - E W S - - - - W E - WR NL NR EL - ER SL SR WL - - - W S - WR NL NR EL ER SL - SR WL - - - N W - S E - NL WR - SL ER - NR EL SR WL - + + + + + W + E + ER SL SR WL + EL NL NR WR + + CLOISTER W + CLOISTER E + + + + N W S E + + + N + W + E + S + INNER_FARM + + + N + W + E + SL SR + + + N + S + W + E + ER + WL + EL + WR + + N S W E + + + + N W + S + EL ER + + + N + EL ER + WL WR SL SR + + + N + S + WL WR SR + EL ER SL + + N S + + + + N W + E + EL + ER SL SR + + N E + + + + E W + N + S + NL + NR + SL + SR + + N W + S W + + + + N W + S + SR + SL EL ER + + N S + + + + N + W S + SR WL + WR EL ER SL + + + N W + E S + SL ER + SR EL + + + E + W + S + WR NL NR EL + WL SR + ER SL + + E W S + + + + W E + WR NL NR EL + ER SL SR WL + + + W S + WR NL NR EL ER SL + SR WL + + + N W + S E + NL WR + SL ER + NR EL SR WL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/king_and_scout.xml b/src/main/resources/tile-definitions/king_and_scout.xml index 0a37b7f64..8055dada6 100644 --- a/src/main/resources/tile-definitions/king_and_scout.xml +++ b/src/main/resources/tile-definitions/king_and_scout.xml @@ -1,45 +1,45 @@ - - - - - N - EL ER SL SR WL WR - - - W - N - WR - EL ER SL SR WL - - N W - - - - W - S E - N - WR - EL SR WL - SL ER - - N W - - - - S - E - N W - SR - SL - ER - EL - - N E - N S - - - - W E - N S - + + + + + N + EL ER SL SR WL WR + + + W + N + WR + EL ER SL SR WL + + N W + + + + W + S E + N + WR + EL SR WL + SL ER + + N W + + + + S + E + N W + SR + SL + ER + EL + + N E + N S + + + + W E + N S + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/phantom.xml b/src/main/resources/tile-definitions/phantom.xml index 3930b9399..ef9a99126 100644 --- a/src/main/resources/tile-definitions/phantom.xml +++ b/src/main/resources/tile-definitions/phantom.xml @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/plague.xml b/src/main/resources/tile-definitions/plague.xml index 3ddbb292c..5417681ce 100644 --- a/src/main/resources/tile-definitions/plague.xml +++ b/src/main/resources/tile-definitions/plague.xml @@ -1,60 +1,60 @@ - - - - - N W - SL SR EL ER - - - - N - W - SL SR EL ER - - - - N - W - E - S - EL - SR - ER SL - - N E - S W - - - - - N - W - S - WR - WL SR - EL ER SL - - N S - - - - - N - E - S - W - WR NL - NR EL - ER SL - SR WL - - N E S W - - - - - W S - WR NL NR EL ER SL - SR WL - + + + + + N W + SL SR EL ER + + + + N + W + SL SR EL ER + + + + N + W + E + S + EL + SR + ER SL + + N E + S W + + + + + N + W + S + WR + WL SR + EL ER SL + + N S + + + + + N + E + S + W + WR NL + NR EL + ER SL + SR WL + + N E S W + + + + + W S + WR NL NR EL ER SL + SR WL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/princess_and_dragon.xml b/src/main/resources/tile-definitions/princess_and_dragon.xml index c71a408d2..1501a8a04 100644 --- a/src/main/resources/tile-definitions/princess_and_dragon.xml +++ b/src/main/resources/tile-definitions/princess_and_dragon.xml @@ -1,207 +1,207 @@ - - - - - NL NR EL ER SL SR WL WR - - - - N W - S E - NL WR - SL ER - NR EL SR WL - - - - - S - NL NR EL ER SL SR WL WR - - - - - N - EL ER SL SR WL WR - - - - - N - EL ER SL SR WL WR - - - - - - E - S - W - WR NL NR EL - ER SL - WL SR - - CLOISTER W - CLOISTER S - CLOISTER E - - - - - E - S - W - WR NL NR EL - ER SL - SR WL - - E S W - - - - - E - S - W - WR NL NR EL - ER SL - SR WL - - E S W - - - - E - S - W - N - WR EL - WL SR - ER SL - - E S W - - - - N - E S - WL WR - INNER_FARM - - - N E W - SL SR - - - - N E W - SL SR - - - - - N E W - SL SR - - CLOISTER N - - - - - W S - WR NL NR EL ER SL - SR WL - - - - W S - WR NL NR EL ER SL - SR WL - - - - W E - WR NL NR EL - WL SL SR ER - - - - W E - WR NL NR EL - WL SL SR ER - - - N W - EL ER - SL SR - - - - N W - SL SR EL ER - - - N W - SL SR EL ER - - - - E - N - WL WR SL SR - - - - W E - NL NR - SL SR - - - E S - N W - EL SR - ER SL - - - - E S - N W - EL SR - ER SL - - - - E W - N S - NL NR - SL SR - - - - S W - N - WR EL ER SL - WL SR - - - - S W - N - WR EL ER SL - WL SR - - - - E S - N - EL WL WR SR - ER SL - - - - E S - N - EL WL WR SR - ER SL - + + + + + NL NR EL ER SL SR WL WR + + + + N W + S E + NL WR + SL ER + NR EL SR WL + + + + + S + NL NR EL ER SL SR WL WR + + + + + N + EL ER SL SR WL WR + + + + + N + EL ER SL SR WL WR + + + + + + E + S + W + WR NL NR EL + ER SL + WL SR + + CLOISTER W + CLOISTER S + CLOISTER E + + + + + E + S + W + WR NL NR EL + ER SL + SR WL + + E S W + + + + + E + S + W + WR NL NR EL + ER SL + SR WL + + E S W + + + + E + S + W + N + WR EL + WL SR + ER SL + + E S W + + + + N + E S + WL WR + INNER_FARM + + + N E W + SL SR + + + + N E W + SL SR + + + + + N E W + SL SR + + CLOISTER N + + + + + W S + WR NL NR EL ER SL + SR WL + + + + W S + WR NL NR EL ER SL + SR WL + + + + W E + WR NL NR EL + WL SL SR ER + + + + W E + WR NL NR EL + WL SL SR ER + + + N W + EL ER + SL SR + + + + N W + SL SR EL ER + + + N W + SL SR EL ER + + + + E + N + WL WR SL SR + + + + W E + NL NR + SL SR + + + E S + N W + EL SR + ER SL + + + + E S + N W + EL SR + ER SL + + + + E W + N S + NL NR + SL SR + + + + S W + N + WR EL ER SL + WL SR + + + + S W + N + WR EL ER SL + WL SR + + + + E S + N + EL WL WR SR + ER SL + + + + E S + N + EL WL WR SR + ER SL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/river.xml b/src/main/resources/tile-definitions/river.xml index 2f44cf083..fa92b25c0 100644 --- a/src/main/resources/tile-definitions/river.xml +++ b/src/main/resources/tile-definitions/river.xml @@ -1,73 +1,73 @@ - - - - NL NR EL ER SL SR WL WR - E - - - - NL NR EL ER SL SR WL WR - W - - - N - S - EL WR - ER WL - W E - - - N - S - EL - WR - ER SL - WL SR - W E - - N S - - - - - S - WR NL NR EL - ER SL - WL SR - W E - - CLOISTER S - - - - W E - WR NL - NR EL - ER SL - WL SR - N S - - - WR NL NR EL - WL SL SR ER - W E - - - N W - SR EL - ER SL - S E - - - N E - WR NL ER SL - NR EL - WL SR - W S - - - WR NL NR EL ER SL - WL SR - W S - + + + + NL NR EL ER SL SR WL WR + E + + + + NL NR EL ER SL SR WL WR + W + + + N + S + EL WR + ER WL + W E + + + N + S + EL + WR + ER SL + WL SR + W E + + N S + + + + + S + WR NL NR EL + ER SL + WL SR + W E + + CLOISTER S + + + + W E + WR NL + NR EL + ER SL + WL SR + N S + + + WR NL NR EL + WL SL SR ER + W E + + + N W + SR EL + ER SL + S E + + + N E + WR NL ER SL + NR EL + WL SR + W S + + + WR NL NR EL ER SL + WL SR + W S + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/river_ii.xml b/src/main/resources/tile-definitions/river_ii.xml index ffc368509..0f45b6e56 100644 --- a/src/main/resources/tile-definitions/river_ii.xml +++ b/src/main/resources/tile-definitions/river_ii.xml @@ -1,85 +1,85 @@ - - - - - - - NL NR EL ER SL SR WL WR - E - - - - E - NL NR WR - SL SR WL - W - - - - NL NR EL ER SL SR WL WR - W - - - WR NL - NR EL - ER SL SR WL - W N E - - - W E - NR - NL - SL - SR - N S - - - - WR NL NR EL - WL SL SR ER - W E - - - W E - WR NL - NR EL - ER SL - WL SR - N S - - - N - S - EL - WR - ER SL - WL SR - W E - - N S - - - - WR NL NR EL ER SL - WL SR - W S - - - N W - SR EL - ER SL - S E - - - WL SL SR EL ER NR - WR NL - W N - - - N E - WR NL ER SL - NR EL - WL SR - W S - + + + + + + + NL NR EL ER SL SR WL WR + E + + + + E + NL NR WR + SL SR WL + W + + + + NL NR EL ER SL SR WL WR + W + + + WR NL + NR EL + ER SL SR WL + W N E + + + W E + NR + NL + SL + SR + N S + + + + WR NL NR EL + WL SL SR ER + W E + + + W E + WR NL + NR EL + ER SL + WL SR + N S + + + N + S + EL + WR + ER SL + WL SR + W E + + N S + + + + WR NL NR EL ER SL + WL SR + W S + + + N W + SR EL + ER SL + S E + + + WL SL SR EL ER NR + WR NL + W N + + + N E + WR NL ER SL + NR EL + WL SR + W S + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/tower.xml b/src/main/resources/tile-definitions/tower.xml index 3b9e3b818..59bf86cec 100644 --- a/src/main/resources/tile-definitions/tower.xml +++ b/src/main/resources/tile-definitions/tower.xml @@ -1,129 +1,129 @@ - - - - - N - WL WR SL SR EL ER - - - - NL NR EL ER SL SR WL WR - - - - - NL NR EL ER SL SR WL WR - - - - W - S - WR NL NR EL ER SL - WL SR - - - - W - N - E - WR NL - NR EL - ER SL SR WL - - - - N W - S E - NL WR - SL ER - NR EL SR WL - - - - N - E - S - W - WR NL - NR EL - ER SL - SR WL - - - - N S - W E - NL - NR - SL - SR - - - - N - S - WL WR SR - EL ER SL - - - - S W - N - WR EL ER SL - WL SR - - - - N - W E - WR - EL - WL SL SR ER - - - - N W - SL SR EL ER - - - - E - N W - EL - ER - SL SR - - N E - - - - - N - W - EL ER SL SR - - - - W E - N - S - WR EL - ER WL - - - - S - N W E - SL - SR - - N S - - - - - N W E - S - INNER_FARM - + + + + + N + WL WR SL SR EL ER + + + + NL NR EL ER SL SR WL WR + + + + + NL NR EL ER SL SR WL WR + + + + W + S + WR NL NR EL ER SL + WL SR + + + + W + N + E + WR NL + NR EL + ER SL SR WL + + + + N W + S E + NL WR + SL ER + NR EL SR WL + + + + N + E + S + W + WR NL + NR EL + ER SL + SR WL + + + + N S + W E + NL + NR + SL + SR + + + + N + S + WL WR SR + EL ER SL + + + + S W + N + WR EL ER SL + WL SR + + + + N + W E + WR + EL + WL SL SR ER + + + + N W + SL SR EL ER + + + + E + N W + EL + ER + SL SR + + N E + + + + + N + W + EL ER SL SR + + + + W E + N + S + WR EL + ER WL + + + + S + N W E + SL + SR + + N S + + + + + N W E + S + INNER_FARM + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/traders_and_builders.xml b/src/main/resources/tile-definitions/traders_and_builders.xml index 2215feb05..3753fd1fc 100644 --- a/src/main/resources/tile-definitions/traders_and_builders.xml +++ b/src/main/resources/tile-definitions/traders_and_builders.xml @@ -1,210 +1,210 @@ - - - - N W - SL SR EL ER - - - N W - SL SR EL ER - - - W E - S - NL NR - INNER_FARM - - - W E - S - NL NR - INNER_FARM - - - N W E - SL SR - - - N W - S - E - INNER_FARM - - - S - E - N W - SR - SL - ER - EL - - N E - N S - - - - N W - S - E - SR - SL ER - EL - - N E - N S - - - - N W - S - E - EL - ER - - N E - - - - N W - S - E - EL - ER - - N E - - - - N W - E - EL - ER SL SR - - N E - - - - E - N W - EL - ER - SL SR - - N E - - - - N W E - S - SR - SL - - N S - - - - N W - E S - INNER_FARM - - - W E - NL NR - SL SR - - - N - E - EL - WL WR SL SR ER - - N E - - - - W E - S - NL NR - SR - SL - - W S - - - - W E - S - NL NR - SR - SL - - W S - - - - E W - N - S - NL - NR - SL - SR - - W N - W S - - - - - E - S - W - WR NL NR EL - ER SL - WL SR - - CLOISTER W - CLOISTER S - CLOISTER E - - - - N W - S - SR - SL EL ER - - N S - - - - S - N W - SR - SL - EL ER - - N S - - - - N - W - S - WR - WL SR - EL ER SL - - N S - - - - N S - W E - WR NL - NR EL - ER SL - SR WL - + + + + N W + SL SR EL ER + + + N W + SL SR EL ER + + + W E + S + NL NR + INNER_FARM + + + W E + S + NL NR + INNER_FARM + + + N W E + SL SR + + + N W + S + E + INNER_FARM + + + S + E + N W + SR + SL + ER + EL + + N E + N S + + + + N W + S + E + SR + SL ER + EL + + N E + N S + + + + N W + S + E + EL + ER + + N E + + + + N W + S + E + EL + ER + + N E + + + + N W + E + EL + ER SL SR + + N E + + + + E + N W + EL + ER + SL SR + + N E + + + + N W E + S + SR + SL + + N S + + + + N W + E S + INNER_FARM + + + W E + NL NR + SL SR + + + N + E + EL + WL WR SL SR ER + + N E + + + + W E + S + NL NR + SR + SL + + W S + + + + W E + S + NL NR + SR + SL + + W S + + + + E W + N + S + NL + NR + SL + SR + + W N + W S + + + + + E + S + W + WR NL NR EL + ER SL + WL SR + + CLOISTER W + CLOISTER S + CLOISTER E + + + + N W + S + SR + SL EL ER + + N S + + + + S + N W + SR + SL + EL ER + + N S + + + + N + W + S + WR + WL SR + EL ER SL + + N S + + + + N S + W E + WR NL + NR EL + ER SL + SR WL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/tunnel.xml b/src/main/resources/tile-definitions/tunnel.xml index c4363fd06..2aee8955c 100644 --- a/src/main/resources/tile-definitions/tunnel.xml +++ b/src/main/resources/tile-definitions/tunnel.xml @@ -1,34 +1,34 @@ - - - - N - W - E - S - WR EL - ER SL - SR WL - - - N - W - E - WR EL - ER SL SR WL - - - E - S - SR WL WR NL NR EL - ER SL - - - N - W - E - S - WR NL NR EL - ER SL - SR WL - + + + + N + W + E + S + WR EL + ER SL + SR WL + + + N + W + E + WR EL + ER SL SR WL + + + E + S + SR WL WR NL NR EL + ER SL + + + N + W + E + S + WR NL NR EL + ER SL + SR WL + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/wind_rose.xml b/src/main/resources/tile-definitions/wind_rose.xml index 8e3d0142e..bbfd48802 100644 --- a/src/main/resources/tile-definitions/wind_rose.xml +++ b/src/main/resources/tile-definitions/wind_rose.xml @@ -1,38 +1,38 @@ - - - - N W - SL SR EL ER - - - N - W - EL ER SL SR - - - N S - WL WR - EL ER - - - E - W - WR NL NR - WL SL SR - - W E - - - - - S W - WR NL NR EL ER SL - SR WL - - - N - S W - WR EL ER SL - WL SR - + + + + N W + SL SR EL ER + + + N + W + EL ER SL SR + + + N S + WL WR + EL ER + + + E + W + WR NL NR + WL SL SR + + W E + + + + + S W + WR NL NR EL ER SL + SR WL + + + N + S W + WR EL ER SL + WL SR + \ No newline at end of file diff --git a/src/main/resources/tile-definitions/winter.xml b/src/main/resources/tile-definitions/winter.xml index 8e76c8e24..52c637f60 100644 --- a/src/main/resources/tile-definitions/winter.xml +++ b/src/main/resources/tile-definitions/winter.xml @@ -1,102 +1,102 @@ - - - - E - S - W - WR NL NR EL - ER SL - SR WL - - E S W - - - - N - W - WR - EL ER SL SR WL - - N W - - - - N - E - EL - WL WR SL SR ER - - N E - - - - - S - NL NR EL ER SL SR WL WR - - CLOISTER S - - - - N W - S - SR - SL EL ER - - N S - - - - - W - E - ER SL SR WL - EL NL NR WR - - CLOISTER W - CLOISTER E - - - - N - S E - WL WR SR - EL - ER SL - - - N - S - WL WR SR - EL ER SL - - N S - - - - W S - N E - SR WL - NR EL - NL WR SL ER - - - N W - E - EL - ER SL SR - - N E - - - - S - NL NR EL ER SL SR WL WR - - - N - W S - SR WL - WR EL ER SL - + + + + E + S + W + WR NL NR EL + ER SL + SR WL + + E S W + + + + N + W + WR + EL ER SL SR WL + + N W + + + + N + E + EL + WL WR SL SR ER + + N E + + + + + S + NL NR EL ER SL SR WL WR + + CLOISTER S + + + + N W + S + SR + SL EL ER + + N S + + + + + W + E + ER SL SR WL + EL NL NR WR + + CLOISTER W + CLOISTER E + + + + N + S E + WL WR SR + EL + ER SL + + + N + S + WL WR SR + EL ER SL + + N S + + + + W S + N E + SR WL + NR EL + NL WR SL ER + + + N W + E + EL + ER SL SR + + N E + + + + S + NL NR EL ER SL SR WL WR + + + N + W S + SR WL + WR EL ER SL + \ No newline at end of file diff --git a/src/test/java/com/jcloisterzone/board/AbstractTileTest.java b/src/test/java/com/jcloisterzone/board/AbstractTileTest.java index 296743819..3c583eb88 100644 --- a/src/test/java/com/jcloisterzone/board/AbstractTileTest.java +++ b/src/test/java/com/jcloisterzone/board/AbstractTileTest.java @@ -1,43 +1,43 @@ -package com.jcloisterzone.board; - -import org.ini4j.Ini; -import org.junit.Before; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.game.Game; - -public class AbstractTileTest { - - protected Game game = new Game(); - protected TilePackFactory packFactory = new TilePackFactory(); - protected TileFactory tileFactory = new TileFactory(); - - protected void setUpGame(Game game) { - game.getExpansions().add(Expansion.BASIC); - } - - @Before - public void initFactories() { - Ini config = new Ini(); - game.setConfig(config); - setUpGame(game); - packFactory.setGame(game); - packFactory.setConfig(config); - tileFactory.setGame(game); - } - - protected Tile createTile(Expansion exp, String id) { - Element el = packFactory.getExpansionDefinition(exp); - NodeList nl = el.getElementsByTagName("tile"); - for (int i = 0; i < nl.getLength(); i++) { - Element card = (Element) nl.item(i); - if (id.equals(card.getAttribute("id"))) { - return tileFactory.createTile(exp, id, card, false); - } - } - throw new IllegalArgumentException("Invalid tile id"); - } - -} +package com.jcloisterzone.board; + +import org.ini4j.Ini; +import org.junit.Before; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.game.Game; + +public class AbstractTileTest { + + protected Game game = new Game(); + protected TilePackFactory packFactory = new TilePackFactory(); + protected TileFactory tileFactory = new TileFactory(); + + protected void setUpGame(Game game) { + game.getExpansions().add(Expansion.BASIC); + } + + @Before + public void initFactories() { + Ini config = new Ini(); + game.setConfig(config); + setUpGame(game); + packFactory.setGame(game); + packFactory.setConfig(config); + tileFactory.setGame(game); + } + + protected Tile createTile(Expansion exp, String id) { + Element el = packFactory.getExpansionDefinition(exp); + NodeList nl = el.getElementsByTagName("tile"); + for (int i = 0; i < nl.getLength(); i++) { + Element card = (Element) nl.item(i); + if (id.equals(card.getAttribute("id"))) { + return tileFactory.createTile(exp, id, card, false); + } + } + throw new IllegalArgumentException("Invalid tile id"); + } + +} diff --git a/src/test/java/com/jcloisterzone/board/LocationTest.java b/src/test/java/com/jcloisterzone/board/LocationTest.java index 70521fad5..bf7a676bc 100644 --- a/src/test/java/com/jcloisterzone/board/LocationTest.java +++ b/src/test/java/com/jcloisterzone/board/LocationTest.java @@ -1,112 +1,112 @@ -package com.jcloisterzone.board; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import org.junit.Test; - -public class LocationTest { - -// @Test -// public void isSpecialLocation() { -// assertTrue(Location.E.isSideLocation()); -// assertTrue(Location.NW.isSideLocation()); -// assertTrue(Location.create(135).isSideLocation()); -// assertFalse(Location.CENTER.isSideLocation()); -// assertFalse(Location.CLOISTER.isSideLocation()); -// assertFalse(Location.TOWER.isSideLocation()); -// } - - @Test - public void isPartOf() { - assertTrue(Location.E.isPartOf(Location.E)); - assertTrue(Location.N.isPartOf(Location.NW)); - assertFalse(Location.E.isPartOf(Location.NW)); - assertFalse(Location.INNER_FARM.isPartOf(Location.N)); - assertTrue(Location._N.isPartOf(Location.NWSE)); - } - - @Test - public void union() { - assertEquals(Location.SW, Location.S.union(Location.W)); - assertEquals(Location.SW, Location.W.union(Location.S)); - assertEquals(Location.NWSE, Location.N.union(Location._N)); - - } - - @Test - public void unionExcept() { - try { - Location.N.union(Location.CLOISTER); - fail(); - } catch (AssertionError ae) { - } - try { - Location.N.union(Location.INNER_FARM); - fail(); - } catch (AssertionError ae) { - } - } - - @Test - public void substract() { - assertEquals(Location.S, Location.SW.substract(Location.W)); - assertEquals(Location.W, Location.SW.substract(Location.S)); - assertEquals(Location.N, Location.NWSE.substract(Location._N)); - } - - @Test() - public void substractExcept() { - try { - Location.N.substract(Location.CLOISTER); - fail(); - } catch (AssertionError ae) { - } - } - - @Test - public void rev() { - assertEquals(Location.S, Location.N.rev()); - assertEquals(Location.NL, Location.SR.rev()); - assertEquals(Location.NW, Location.SE.rev()); - assertEquals(Location._N, Location._S.rev()); - assertEquals(Location.N.union(Location.EL), Location.S.union(Location.WR).rev()); - } - - @Test - public void rotate() { - assertEquals(Location.E, Location.N.rotateCW(Rotation.R90)); - assertEquals(Location.W, Location.N.rotateCCW(Rotation.R90)); - assertEquals(Location.W, Location.E.rotateCW(Rotation.R180)); - assertEquals(Location.S, Location.S.rotateCCW(Rotation.R0)); - } - - @Test - public void isRotationOf() { - assertTrue(Location.E.isRotationOf(Location.E)); - assertTrue(Location.E.isRotationOf(Location.N)); - assertTrue(Location.N.isRotationOf(Location.E)); - assertTrue(Location._N.isRotationOf(Location._S)); - assertTrue(Location.NW.isRotationOf(Location.NE)); - } - - @Test - public void getRotationOf() { - assertEquals(Rotation.R0, Location.E.getRotationOf(Location.E)); - assertEquals(Rotation.R90, Location.E.getRotationOf(Location.N)); - assertEquals(Rotation.R270, Location.S.getRotationOf(Location.W)); - } - - @Test - public void intersect() { - assertEquals(Location.E, Location.E.intersect(Location.E)); - assertNull(Location.E.intersect(Location.W)); - assertEquals(Location.E, Location.WE.intersect(Location.SE)); - assertNull(Location.NW.intersect(Location.NR.union(Location.EL))); - } -} - - +package com.jcloisterzone.board; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +public class LocationTest { + +// @Test +// public void isSpecialLocation() { +// assertTrue(Location.E.isSideLocation()); +// assertTrue(Location.NW.isSideLocation()); +// assertTrue(Location.create(135).isSideLocation()); +// assertFalse(Location.CENTER.isSideLocation()); +// assertFalse(Location.CLOISTER.isSideLocation()); +// assertFalse(Location.TOWER.isSideLocation()); +// } + + @Test + public void isPartOf() { + assertTrue(Location.E.isPartOf(Location.E)); + assertTrue(Location.N.isPartOf(Location.NW)); + assertFalse(Location.E.isPartOf(Location.NW)); + assertFalse(Location.INNER_FARM.isPartOf(Location.N)); + assertTrue(Location._N.isPartOf(Location.NWSE)); + } + + @Test + public void union() { + assertEquals(Location.SW, Location.S.union(Location.W)); + assertEquals(Location.SW, Location.W.union(Location.S)); + assertEquals(Location.NWSE, Location.N.union(Location._N)); + + } + + @Test + public void unionExcept() { + try { + Location.N.union(Location.CLOISTER); + fail(); + } catch (AssertionError ae) { + } + try { + Location.N.union(Location.INNER_FARM); + fail(); + } catch (AssertionError ae) { + } + } + + @Test + public void substract() { + assertEquals(Location.S, Location.SW.substract(Location.W)); + assertEquals(Location.W, Location.SW.substract(Location.S)); + assertEquals(Location.N, Location.NWSE.substract(Location._N)); + } + + @Test() + public void substractExcept() { + try { + Location.N.substract(Location.CLOISTER); + fail(); + } catch (AssertionError ae) { + } + } + + @Test + public void rev() { + assertEquals(Location.S, Location.N.rev()); + assertEquals(Location.NL, Location.SR.rev()); + assertEquals(Location.NW, Location.SE.rev()); + assertEquals(Location._N, Location._S.rev()); + assertEquals(Location.N.union(Location.EL), Location.S.union(Location.WR).rev()); + } + + @Test + public void rotate() { + assertEquals(Location.E, Location.N.rotateCW(Rotation.R90)); + assertEquals(Location.W, Location.N.rotateCCW(Rotation.R90)); + assertEquals(Location.W, Location.E.rotateCW(Rotation.R180)); + assertEquals(Location.S, Location.S.rotateCCW(Rotation.R0)); + } + + @Test + public void isRotationOf() { + assertTrue(Location.E.isRotationOf(Location.E)); + assertTrue(Location.E.isRotationOf(Location.N)); + assertTrue(Location.N.isRotationOf(Location.E)); + assertTrue(Location._N.isRotationOf(Location._S)); + assertTrue(Location.NW.isRotationOf(Location.NE)); + } + + @Test + public void getRotationOf() { + assertEquals(Rotation.R0, Location.E.getRotationOf(Location.E)); + assertEquals(Rotation.R90, Location.E.getRotationOf(Location.N)); + assertEquals(Rotation.R270, Location.S.getRotationOf(Location.W)); + } + + @Test + public void intersect() { + assertEquals(Location.E, Location.E.intersect(Location.E)); + assertNull(Location.E.intersect(Location.W)); + assertEquals(Location.E, Location.WE.intersect(Location.SE)); + assertNull(Location.NW.intersect(Location.NR.union(Location.EL))); + } +} + + diff --git a/src/test/java/com/jcloisterzone/board/TileTest.java b/src/test/java/com/jcloisterzone/board/TileTest.java index 0f381e01b..02fdbfdbc 100644 --- a/src/test/java/com/jcloisterzone/board/TileTest.java +++ b/src/test/java/com/jcloisterzone/board/TileTest.java @@ -1,56 +1,56 @@ -package com.jcloisterzone.board; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -import org.junit.Before; -import org.junit.Test; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.feature.City; -import com.jcloisterzone.feature.Road; - -public class TileTest extends AbstractTileTest { - - Tile BA_RRR, BA_Cc1, BA_Cc1_rot; - - - @Before - public void initTiles() { - BA_RRR = createTile(Expansion.BASIC, "RRR"); - BA_Cc1 = createTile(Expansion.BASIC, "Cc.1"); - BA_Cc1_rot = createTile(Expansion.BASIC, "Cc.1"); - BA_Cc1_rot.setRotation(Rotation.R90); - } - - - @Test - public void getPiece() { - assertEquals(Road.class, BA_RRR.getFeature(Location.E).getClass()); - assertNull(BA_RRR.getFeature(Location.N)); - assertEquals(City.class, BA_Cc1.getFeature(Location.NW).getClass()); - assertNull(BA_Cc1.getFeature(Location.N)); - - assertEquals(City.class, BA_Cc1_rot.getFeature(Location.NE).getClass()); - assertNull(BA_Cc1_rot.getFeature(Location.NW)); - } - - @Test - public void getPiecePartOf() { - assertEquals(Road.class, BA_RRR.getFeaturePartOf(Location.E).getClass()); - assertEquals(City.class, BA_Cc1.getFeaturePartOf(Location.NW).getClass()); - assertEquals(City.class, BA_Cc1.getFeaturePartOf(Location.N).getClass()); - assertNull(BA_Cc1.getFeature(Location.E)); - - assertNull(BA_Cc1_rot.getFeature(Location.W)); - assertEquals(City.class, BA_Cc1_rot.getFeaturePartOf(Location.N).getClass()); - assertEquals(City.class, BA_Cc1_rot.getFeaturePartOf(Location.E).getClass()); - } - -// @Test -// public void getSideMaskAt() { -// assertEquals('C', BA_Cc1_rot.getSideMaskAt(Location.N)); -// assertEquals('F', BA_Cc1_rot.getSideMaskAt(Location.S)); -// } - -} +package com.jcloisterzone.board; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Before; +import org.junit.Test; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.feature.City; +import com.jcloisterzone.feature.Road; + +public class TileTest extends AbstractTileTest { + + Tile BA_RRR, BA_Cc1, BA_Cc1_rot; + + + @Before + public void initTiles() { + BA_RRR = createTile(Expansion.BASIC, "RRR"); + BA_Cc1 = createTile(Expansion.BASIC, "Cc.1"); + BA_Cc1_rot = createTile(Expansion.BASIC, "Cc.1"); + BA_Cc1_rot.setRotation(Rotation.R90); + } + + + @Test + public void getPiece() { + assertEquals(Road.class, BA_RRR.getFeature(Location.E).getClass()); + assertNull(BA_RRR.getFeature(Location.N)); + assertEquals(City.class, BA_Cc1.getFeature(Location.NW).getClass()); + assertNull(BA_Cc1.getFeature(Location.N)); + + assertEquals(City.class, BA_Cc1_rot.getFeature(Location.NE).getClass()); + assertNull(BA_Cc1_rot.getFeature(Location.NW)); + } + + @Test + public void getPiecePartOf() { + assertEquals(Road.class, BA_RRR.getFeaturePartOf(Location.E).getClass()); + assertEquals(City.class, BA_Cc1.getFeaturePartOf(Location.NW).getClass()); + assertEquals(City.class, BA_Cc1.getFeaturePartOf(Location.N).getClass()); + assertNull(BA_Cc1.getFeature(Location.E)); + + assertNull(BA_Cc1_rot.getFeature(Location.W)); + assertEquals(City.class, BA_Cc1_rot.getFeaturePartOf(Location.N).getClass()); + assertEquals(City.class, BA_Cc1_rot.getFeaturePartOf(Location.E).getClass()); + } + +// @Test +// public void getSideMaskAt() { +// assertEquals('C', BA_Cc1_rot.getSideMaskAt(Location.N)); +// assertEquals('F', BA_Cc1_rot.getSideMaskAt(Location.S)); +// } + +} diff --git a/src/test/java/com/jcloisterzone/feature/AbstractScoringTest.java b/src/test/java/com/jcloisterzone/feature/AbstractScoringTest.java index 20d086739..b2947b18f 100644 --- a/src/test/java/com/jcloisterzone/feature/AbstractScoringTest.java +++ b/src/test/java/com/jcloisterzone/feature/AbstractScoringTest.java @@ -1,48 +1,48 @@ -package com.jcloisterzone.feature; - -import java.util.Arrays; - -import org.junit.After; -import org.junit.Before; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.AbstractTileTest; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.game.Game; - -public class AbstractScoringTest extends AbstractTileTest { - - protected void setUpGame(Game game) { - game.getExpansions().add(Expansion.BASIC); - game.getExpansions().add(Expansion.INNS_AND_CATHEDRALS); - game.getExpansions().add(Expansion.TRADERS_AND_BUILDERS); - game.getExpansions().add(Expansion.ABBEY_AND_MAYOR); - game.getExpansions().add(Expansion.CATHARS); - - for (Expansion exp : game.getExpansions()) { - game.getCapabilityClasses().addAll(Arrays.asList(exp.getCapabilities())); - } - } - - @Before - public void setUp() { - game.start(); - } - - @After - public void tearDown() { - game.getCustomRules().clear(); - } - - protected Tile putTile(Position pos, Rotation rot, Expansion exp, String id) { - Tile tile = createTile(exp, id); - tile.setRotation(rot); - game.getBoard().refreshAvailablePlacements(tile); - game.getBoard().add(tile, pos, true); - game.getBoard().mergeFeatures(tile); - return tile; - } - -} +package com.jcloisterzone.feature; + +import java.util.Arrays; + +import org.junit.After; +import org.junit.Before; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.AbstractTileTest; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.game.Game; + +public class AbstractScoringTest extends AbstractTileTest { + + protected void setUpGame(Game game) { + game.getExpansions().add(Expansion.BASIC); + game.getExpansions().add(Expansion.INNS_AND_CATHEDRALS); + game.getExpansions().add(Expansion.TRADERS_AND_BUILDERS); + game.getExpansions().add(Expansion.ABBEY_AND_MAYOR); + game.getExpansions().add(Expansion.CATHARS); + + for (Expansion exp : game.getExpansions()) { + game.getCapabilityClasses().addAll(Arrays.asList(exp.getCapabilities())); + } + } + + @Before + public void setUp() { + game.start(); + } + + @After + public void tearDown() { + game.getCustomRules().clear(); + } + + protected Tile putTile(Position pos, Rotation rot, Expansion exp, String id) { + Tile tile = createTile(exp, id); + tile.setRotation(rot); + game.getBoard().refreshAvailablePlacements(tile); + game.getBoard().add(tile, pos, true); + game.getBoard().mergeFeatures(tile); + return tile; + } + +} diff --git a/src/test/java/com/jcloisterzone/feature/CityScoring.java b/src/test/java/com/jcloisterzone/feature/CityScoring.java index 95cf0ac58..5cedc8ceb 100644 --- a/src/test/java/com/jcloisterzone/feature/CityScoring.java +++ b/src/test/java/com/jcloisterzone/feature/CityScoring.java @@ -1,133 +1,133 @@ -package com.jcloisterzone.feature; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.visitor.score.CityScoreContext; -import com.jcloisterzone.game.CustomRule; - -public class CityScoring extends AbstractScoringTest { - - protected void assertScore(int expected, Tile tile, Location loc) { - City city = (City) tile.getFeaturePartOf(loc); - CityScoreContext ctx = city.getScoreContext(); - city.walk(ctx); - - assertEquals(expected, ctx.getPoints()); - } - - @Test - public void tiny() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(0,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); - - assertScore(4, t, Location.N); - } - - @Test - public void tinyCustomRule() { - game.getCustomRules().add(CustomRule.TINY_CITY_2_POINTS); - - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(0,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); - - assertScore(2, t, Location.N); - } - - @Test - public void simple() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(0,-1), Rotation.R180, Expansion.BASIC, "CcRr"); - putTile(new Position(1,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); - - assertScore(6, t, Location.N); - } - - @Test - public void pennant() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(0,-1), Rotation.R180, Expansion.BASIC, "CcRr+"); - putTile(new Position(1,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); - - assertScore(8, t, Location.N); - } - - @Test - public void morePennants() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(0,-1), Rotation.R180, Expansion.BASIC, "CcRr+"); - putTile(new Position(1,-1), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "C!+"); - - assertScore(10, t, Location.N); - } - - @Test - public void twoPennantTile() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "C++"); - putTile(new Position(-1,0), Rotation.R90, Expansion.ABBEY_AND_MAYOR, "CCRR"); - putTile(new Position(1,0), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "C!+"); - putTile(new Position(0,1), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "CCc+"); - putTile(new Position(0,-1), Rotation.R180, Expansion.ABBEY_AND_MAYOR, "CRr"); - - assertScore(18, t, Location.N); - } - - @Test - public void unfinshedCathedral() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); - putTile(new Position(0, -1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCc+"); - - assertScore(0, t, Location.N); - } - - @Test - public void finshedCathedral() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); - putTile(new Position(0,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCc+"); - putTile(new Position(0,1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "C!"); - putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCC"); - putTile(new Position(-1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCC"); - - assertScore(15, t, Location.N); - } - - @Test - public void twoCathedrals() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); - putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); - putTile(new Position(0,-1), Rotation.R180, Expansion.INNS_AND_CATHEDRALS, "CcRr+.i"); - putTile(new Position(1,-1), Rotation.R270, Expansion.INNS_AND_CATHEDRALS, "CcRr+.i"); - putTile(new Position(0,1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CFR"); - putTile(new Position(1,1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CFR"); - putTile(new Position(2,0), Rotation.R270, Expansion.INNS_AND_CATHEDRALS, "CFR"); - putTile(new Position(-1,0), Rotation.R90, Expansion.INNS_AND_CATHEDRALS, "CFR"); - - assertScore(30, t, Location.N); - } - - @Test - public void siege() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.CATHARS, "C"); - putTile(new Position(0,-1), Rotation.R270, Expansion.CATHARS, "Cc"); - putTile(new Position(-1,-1), Rotation.R90, Expansion.CATHARS, "C"); - - assertScore(3, t, Location.N); - } - -} +package com.jcloisterzone.feature; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.visitor.score.CityScoreContext; +import com.jcloisterzone.game.CustomRule; + +public class CityScoring extends AbstractScoringTest { + + protected void assertScore(int expected, Tile tile, Location loc) { + City city = (City) tile.getFeaturePartOf(loc); + CityScoreContext ctx = city.getScoreContext(); + city.walk(ctx); + + assertEquals(expected, ctx.getPoints()); + } + + @Test + public void tiny() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(0,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); + + assertScore(4, t, Location.N); + } + + @Test + public void tinyCustomRule() { + game.getCustomRules().add(CustomRule.TINY_CITY_2_POINTS); + + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(0,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); + + assertScore(2, t, Location.N); + } + + @Test + public void simple() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(0,-1), Rotation.R180, Expansion.BASIC, "CcRr"); + putTile(new Position(1,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); + + assertScore(6, t, Location.N); + } + + @Test + public void pennant() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(0,-1), Rotation.R180, Expansion.BASIC, "CcRr+"); + putTile(new Position(1,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCCC"); + + assertScore(8, t, Location.N); + } + + @Test + public void morePennants() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(0,-1), Rotation.R180, Expansion.BASIC, "CcRr+"); + putTile(new Position(1,-1), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "C!+"); + + assertScore(10, t, Location.N); + } + + @Test + public void twoPennantTile() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "C++"); + putTile(new Position(-1,0), Rotation.R90, Expansion.ABBEY_AND_MAYOR, "CCRR"); + putTile(new Position(1,0), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "C!+"); + putTile(new Position(0,1), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "CCc+"); + putTile(new Position(0,-1), Rotation.R180, Expansion.ABBEY_AND_MAYOR, "CRr"); + + assertScore(18, t, Location.N); + } + + @Test + public void unfinshedCathedral() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); + putTile(new Position(0, -1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCc+"); + + assertScore(0, t, Location.N); + } + + @Test + public void finshedCathedral() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); + putTile(new Position(0,-1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCc+"); + putTile(new Position(0,1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "C!"); + putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCC"); + putTile(new Position(-1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CCC"); + + assertScore(15, t, Location.N); + } + + @Test + public void twoCathedrals() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); + putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "Cccc.c"); + putTile(new Position(0,-1), Rotation.R180, Expansion.INNS_AND_CATHEDRALS, "CcRr+.i"); + putTile(new Position(1,-1), Rotation.R270, Expansion.INNS_AND_CATHEDRALS, "CcRr+.i"); + putTile(new Position(0,1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CFR"); + putTile(new Position(1,1), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "CFR"); + putTile(new Position(2,0), Rotation.R270, Expansion.INNS_AND_CATHEDRALS, "CFR"); + putTile(new Position(-1,0), Rotation.R90, Expansion.INNS_AND_CATHEDRALS, "CFR"); + + assertScore(30, t, Location.N); + } + + @Test + public void siege() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.CATHARS, "C"); + putTile(new Position(0,-1), Rotation.R270, Expansion.CATHARS, "Cc"); + putTile(new Position(-1,-1), Rotation.R90, Expansion.CATHARS, "C"); + + assertScore(3, t, Location.N); + } + +} diff --git a/src/test/java/com/jcloisterzone/feature/CloisterScoring.java b/src/test/java/com/jcloisterzone/feature/CloisterScoring.java index 06ef22cff..61c7d1614 100644 --- a/src/test/java/com/jcloisterzone/feature/CloisterScoring.java +++ b/src/test/java/com/jcloisterzone/feature/CloisterScoring.java @@ -1,59 +1,59 @@ -package com.jcloisterzone.feature; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; - -public class CloisterScoring extends AbstractScoringTest { - - protected void assertScore(int expected, Tile tile) { - Cloister cl = (Cloister) tile.getCloister(); - CompletableScoreContext ctx = cl.getScoreContext(); - cl.walk(ctx); - - assertEquals(expected, ctx.getPoints()); - } - - @Test - public void single() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "L"); - - assertScore(1, t); - } - - @Test - public void incomplete() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(1,0), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(1,1), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(0,1), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "L"); - - assertScore(5, t); - } - - @Test - public void completed() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "LR"); - putTile(new Position(1,0), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(1,1), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(0,1), Rotation.R90, Expansion.BASIC, "RFr"); - putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(-1,-1), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(0,-1), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(1,-1), Rotation.R0, Expansion.BASIC, "L"); - putTile(new Position(-1,1), Rotation.R0, Expansion.BASIC, "L"); - - assertScore(9, t); - } - -} +package com.jcloisterzone.feature; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.visitor.score.CompletableScoreContext; + +public class CloisterScoring extends AbstractScoringTest { + + protected void assertScore(int expected, Tile tile) { + Cloister cl = (Cloister) tile.getCloister(); + CompletableScoreContext ctx = cl.getScoreContext(); + cl.walk(ctx); + + assertEquals(expected, ctx.getPoints()); + } + + @Test + public void single() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "L"); + + assertScore(1, t); + } + + @Test + public void incomplete() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(1,0), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(1,1), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(0,1), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "L"); + + assertScore(5, t); + } + + @Test + public void completed() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "LR"); + putTile(new Position(1,0), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(1,1), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(0,1), Rotation.R90, Expansion.BASIC, "RFr"); + putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(-1,-1), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(0,-1), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(1,-1), Rotation.R0, Expansion.BASIC, "L"); + putTile(new Position(-1,1), Rotation.R0, Expansion.BASIC, "L"); + + assertScore(9, t); + } + +} diff --git a/src/test/java/com/jcloisterzone/feature/RoadScoring.java b/src/test/java/com/jcloisterzone/feature/RoadScoring.java index 9f16a81c2..e86151de3 100644 --- a/src/test/java/com/jcloisterzone/feature/RoadScoring.java +++ b/src/test/java/com/jcloisterzone/feature/RoadScoring.java @@ -1,89 +1,89 @@ -package com.jcloisterzone.feature; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.jcloisterzone.Expansion; -import com.jcloisterzone.board.Location; -import com.jcloisterzone.board.Position; -import com.jcloisterzone.board.Rotation; -import com.jcloisterzone.board.Tile; -import com.jcloisterzone.feature.visitor.score.RoadScoreContext; - -public class RoadScoring extends AbstractScoringTest { - - protected void assertScore(int expected, Tile tile, Location loc) { - Road road = (Road) tile.getFeaturePartOf(Location.W); - RoadScoreContext ctx = road.getScoreContext(); - road.walk(ctx); - - assertEquals(expected, ctx.getPoints()); - } - - @Test - public void simple() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(1,0), Rotation.R0, Expansion.BASIC, "RFr"); - putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "RRRR"); - putTile(new Position(2,0), Rotation.R90, Expansion.BASIC, "LR"); - - assertScore(4, t, Location.W); - } - - @Test - public void circle() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "Rr"); - putTile(new Position(-1,0), Rotation.R270, Expansion.BASIC, "Rr"); - putTile(new Position(0,1), Rotation.R90, Expansion.BASIC, "RrC"); - putTile(new Position(-1,1), Rotation.R270, Expansion.BASIC, "CcRr"); - - assertScore(4, t, Location.W); - } - - @Test - public void circleWithCross() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "Rr"); - putTile(new Position(-1,0), Rotation.R270, Expansion.BASIC, "Rr"); - putTile(new Position(0,1), Rotation.R90, Expansion.BASIC, "RrC"); - putTile(new Position(-1,1), Rotation.R0, Expansion.BASIC, "RRRR"); - - assertScore(4, t, Location.W); - } - - @Test - public void inn() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "RRRR"); - putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "RFr.i"); - putTile(new Position(2,0), Rotation.R90, Expansion.BASIC, "LR"); - - assertScore(8, t, Location.W); - } - - @Test - public void unfinishedInn() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); - putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "RRRR"); - putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "RFr.i"); - - assertScore(0, t, Location.W); - } - - @Test - public void well() { - Tile t; - t = putTile(new Position(0,0), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "Rrr"); - putTile(new Position(0,-1), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "R"); - putTile(new Position(-1, 0), Rotation.R270, Expansion.ABBEY_AND_MAYOR, "R"); - putTile(new Position(1, 0), Rotation.R90, Expansion.ABBEY_AND_MAYOR, "R"); - - assertScore(4, t, Location.W); - } - -} +package com.jcloisterzone.feature; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.jcloisterzone.Expansion; +import com.jcloisterzone.board.Location; +import com.jcloisterzone.board.Position; +import com.jcloisterzone.board.Rotation; +import com.jcloisterzone.board.Tile; +import com.jcloisterzone.feature.visitor.score.RoadScoreContext; + +public class RoadScoring extends AbstractScoringTest { + + protected void assertScore(int expected, Tile tile, Location loc) { + Road road = (Road) tile.getFeaturePartOf(Location.W); + RoadScoreContext ctx = road.getScoreContext(); + road.walk(ctx); + + assertEquals(expected, ctx.getPoints()); + } + + @Test + public void simple() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(1,0), Rotation.R0, Expansion.BASIC, "RFr"); + putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "RRRR"); + putTile(new Position(2,0), Rotation.R90, Expansion.BASIC, "LR"); + + assertScore(4, t, Location.W); + } + + @Test + public void circle() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "Rr"); + putTile(new Position(-1,0), Rotation.R270, Expansion.BASIC, "Rr"); + putTile(new Position(0,1), Rotation.R90, Expansion.BASIC, "RrC"); + putTile(new Position(-1,1), Rotation.R270, Expansion.BASIC, "CcRr"); + + assertScore(4, t, Location.W); + } + + @Test + public void circleWithCross() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "Rr"); + putTile(new Position(-1,0), Rotation.R270, Expansion.BASIC, "Rr"); + putTile(new Position(0,1), Rotation.R90, Expansion.BASIC, "RrC"); + putTile(new Position(-1,1), Rotation.R0, Expansion.BASIC, "RRRR"); + + assertScore(4, t, Location.W); + } + + @Test + public void inn() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "RRRR"); + putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "RFr.i"); + putTile(new Position(2,0), Rotation.R90, Expansion.BASIC, "LR"); + + assertScore(8, t, Location.W); + } + + @Test + public void unfinishedInn() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.BASIC, "RCr"); + putTile(new Position(-1,0), Rotation.R0, Expansion.BASIC, "RRRR"); + putTile(new Position(1,0), Rotation.R0, Expansion.INNS_AND_CATHEDRALS, "RFr.i"); + + assertScore(0, t, Location.W); + } + + @Test + public void well() { + Tile t; + t = putTile(new Position(0,0), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "Rrr"); + putTile(new Position(0,-1), Rotation.R0, Expansion.ABBEY_AND_MAYOR, "R"); + putTile(new Position(-1, 0), Rotation.R270, Expansion.ABBEY_AND_MAYOR, "R"); + putTile(new Position(1, 0), Rotation.R90, Expansion.ABBEY_AND_MAYOR, "R"); + + assertScore(4, t, Location.W); + } + +} diff --git a/src/test/java/com/jcloisterzone/ui/ImmutablePointTest.java b/src/test/java/com/jcloisterzone/ui/ImmutablePointTest.java index 1c9ccd4b9..c7143c8ce 100644 --- a/src/test/java/com/jcloisterzone/ui/ImmutablePointTest.java +++ b/src/test/java/com/jcloisterzone/ui/ImmutablePointTest.java @@ -1,20 +1,20 @@ -package com.jcloisterzone.ui; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -public class ImmutablePointTest { - - @Test - public void scale() { - ImmutablePoint p = new ImmutablePoint(50, 1); - assertEquals(100, p.scale(200).getX()); - assertEquals(25, p.scale(50).getX()); - - p = new ImmutablePoint(10, 1); - assertEquals(10, p.scale(100).getX()); - assertEquals(8, p.scale(80).getX()); - } - -} +package com.jcloisterzone.ui; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class ImmutablePointTest { + + @Test + public void scale() { + ImmutablePoint p = new ImmutablePoint(50, 1); + assertEquals(100, p.scale(200).getX()); + assertEquals(25, p.scale(50).getX()); + + p = new ImmutablePoint(10, 1); + assertEquals(10, p.scale(100).getX()); + assertEquals(8, p.scale(80).getX()); + } + +} diff --git a/src/test/resources/tile-definitions/basic-1card.xml b/src/test/resources/tile-definitions/basic-1card.xml index 7f4829c92..8efd2e3a9 100644 --- a/src/test/resources/tile-definitions/basic-1card.xml +++ b/src/test/resources/tile-definitions/basic-1card.xml @@ -1,16 +1,16 @@ - - - - W E - N - EL WR - ER SL SR WL - - - + + + + W E + N + EL WR + ER SL SR WL + + + \ No newline at end of file