package games.strategy.triplea.delegate;
import java.util.HashSet;
import java.util.Set;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.GameStep;
import games.strategy.engine.data.PlayerID;
/**
* A helper class for determining Game Step Properties.
* These are things such as whether a move phase is combat move or noncombat move,
* or whether we are going to post to a forum during this end turn phase.
*/
public class GameStepPropertiesHelper {
/**
* Indicates we skip posting the game summary and save to a forum or email.
*/
public static boolean isSkipPosting(final GameData data) {
final boolean skipPosting;
data.acquireReadLock();
try {
skipPosting = Boolean.parseBoolean(
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_skipPosting, "false"));
} finally {
data.releaseReadLock();
}
return skipPosting;
}
/**
* What players is this turn summary for? If more than 1 player, whose phases are touching or intermeshed, then we
* will summarize for all
* those phases.
*
* @return colon separated list of player names. could be empty. can be null if not set.
*/
public static Set<PlayerID> getTurnSummaryPlayers(final GameData data) {
final Set<PlayerID> allowedIDs;
data.acquireReadLock();
try {
final String allowedPlayers =
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_turnSummaryPlayers);
if (allowedPlayers != null) {
allowedIDs = new HashSet<>();
for (final String p : allowedPlayers.split(":")) {
final PlayerID id = data.getPlayerList().getPlayerID(p);
if (id == null) {
System.err.println("gamePlay sequence step: " + data.getSequence().getStep().getName() + " stepProperty: "
+ GameStep.PROPERTY_turnSummaryPlayers + " player: " + p + " DOES NOT EXIST");
} else {
allowedIDs.add(id);
}
}
} else {
allowedIDs = null;
}
} finally {
data.releaseReadLock();
}
return allowedIDs;
}
/**
* For various things related to movement validation.
*/
public static boolean isAirborneMove(final GameData data) {
final boolean isAirborneMove;
data.acquireReadLock();
try {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_airborneMove);
if (prop != null) {
isAirborneMove = Boolean.parseBoolean(prop);
} else {
isAirborneMove = isAirborneDelegate(data);
}
} finally {
data.releaseReadLock();
}
return isAirborneMove;
}
/**
* For various things related to movement validation.
*/
static boolean isCombatMove(final GameData data) {
final boolean isCombatMove;
data.acquireReadLock();
try {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_combatMove);
if (prop != null) {
isCombatMove = Boolean.parseBoolean(prop);
} else if (isCombatDelegate(data)) {
isCombatMove = true;
} else if (isNonCombatDelegate(data)) {
isCombatMove = false;
} else {
throw new IllegalStateException("Cannot determine combat or not: " + data.getSequence().getStep().getName());
}
} finally {
data.releaseReadLock();
}
return isCombatMove;
}
/**
* For various things related to movement validation.
*/
public static boolean isNonCombatMove(final GameData data, final boolean doNotThrowErrorIfNotMoveDelegate) {
final boolean isNonCombatMove;
data.acquireReadLock();
try {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_nonCombatMove);
if (prop != null) {
isNonCombatMove = Boolean.parseBoolean(prop);
} else if (isNonCombatDelegate(data)) {
isNonCombatMove = true;
} else if (isCombatDelegate(data)) {
isNonCombatMove = false;
} else if (doNotThrowErrorIfNotMoveDelegate) {
isNonCombatMove = false;
} else {
throw new IllegalStateException("Cannot determine combat or not: " + data.getSequence().getStep().getName());
}
} finally {
data.releaseReadLock();
}
return isNonCombatMove;
}
/**
* Fire rockets after phase is over. Normally would occur after combat move for WW2v2 and WW2v3, and after noncombat
* move for WW2v1.
*/
static boolean isFireRockets(final GameData data) {
final boolean isFireRockets;
data.acquireReadLock();
try {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_fireRockets);
if (prop != null) {
isFireRockets = Boolean.parseBoolean(prop);
} else if (games.strategy.triplea.Properties.getWW2V2(data) || games.strategy.triplea.Properties.getWW2V3(data)) {
isFireRockets = isCombatDelegate(data);
} else {
isFireRockets = isNonCombatDelegate(data);
}
} finally {
data.releaseReadLock();
}
return isFireRockets;
}
/**
* Repairs damaged units. Normally would occur at either start of combat move or end of turn, depending.
*/
static boolean isRepairUnits(final GameData data) {
final boolean isRepairUnits;
data.acquireReadLock();
try {
final boolean repairAtStartAndOnlyOwn =
games.strategy.triplea.Properties.getBattleshipsRepairAtBeginningOfRound(data);
final boolean repairAtEndAndAll = games.strategy.triplea.Properties.getBattleshipsRepairAtEndOfRound(data);
// if both are off, we do no repairing, no matter what
if (!repairAtStartAndOnlyOwn && !repairAtEndAndAll) {
isRepairUnits = false;
} else {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_repairUnits);
if (prop != null) {
isRepairUnits = Boolean.parseBoolean(prop);
} else {
isRepairUnits = (isCombatDelegate(data) && repairAtStartAndOnlyOwn)
|| (data.getSequence().getStep().getName().endsWith("EndTurn") && repairAtEndAndAll);
}
}
} finally {
data.releaseReadLock();
}
return isRepairUnits;
}
/**
* Resets then gives bonus movement. Normally would occur at the start of combat movement phase.
*/
static boolean isGiveBonusMovement(final GameData data) {
final boolean isBonus;
data.acquireReadLock();
try {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_giveBonusMovement);
if (prop != null) {
isBonus = Boolean.parseBoolean(prop);
} else {
isBonus = isCombatDelegate(data);
}
} finally {
data.releaseReadLock();
}
return isBonus;
}
/**
* Kills all air that cannot land. Normally would occur both at the end of noncombat movement and also at end of
* placement phase.
*/
public static boolean isRemoveAirThatCanNotLand(final GameData data) {
final boolean isRemoveAir;
data.acquireReadLock();
try {
final String prop =
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_removeAirThatCanNotLand);
if (prop != null) {
isRemoveAir = Boolean.parseBoolean(prop);
} else if (data.getSequence().getStep().getDelegate() != null
&& NoAirCheckPlaceDelegate.class.equals(data.getSequence().getStep().getDelegate().getClass())) {
isRemoveAir = false;
} else {
isRemoveAir = isNonCombatDelegate(data) || data.getSequence().getStep().getName().endsWith("Place");
}
} finally {
data.releaseReadLock();
}
return isRemoveAir;
}
/**
* For situations where player phases are intermeshed.
* Effects so far:
* Lets air live if the other players could put a carrier under it.
*
* @return a set of player ids. if argument player is not null this set will definitely include that player, but if
* not the set could be
* empty. never null.
*/
public static Set<PlayerID> getCombinedTurns(final GameData data, final PlayerID player) {
final Set<PlayerID> allowedIDs = new HashSet<>();
data.acquireReadLock();
try {
final String allowedPlayers =
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_combinedTurns);
if (player != null) {
allowedIDs.add(player);
}
if (allowedPlayers != null) {
for (final String p : allowedPlayers.split(":")) {
final PlayerID id = data.getPlayerList().getPlayerID(p);
if (id == null) {
System.err.println("gamePlay sequence step: " + data.getSequence().getStep().getName() + " stepProperty: "
+ GameStep.PROPERTY_combinedTurns + " player: " + p + " DOES NOT EXIST");
} else {
allowedIDs.add(id);
}
}
}
} finally {
data.releaseReadLock();
}
return allowedIDs;
}
/**
* Resets unit state, such as movement, submerged, transport unload/load, airborne, etc. Normally does not occur.
*/
static boolean isResetUnitStateAtStart(final GameData data) {
final boolean isReset;
data.acquireReadLock();
try {
final String prop =
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_resetUnitStateAtStart);
isReset = (prop != null) && Boolean.parseBoolean(prop);
} finally {
data.releaseReadLock();
}
return isReset;
}
/**
* Resets unit state, such as movement, submerged, transport unload/load, airborne, etc. Normally occurs at end of
* noncombat move phase.
*/
static boolean isResetUnitStateAtEnd(final GameData data) {
final boolean isReset;
data.acquireReadLock();
try {
final String prop =
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_resetUnitStateAtEnd);
if (prop != null) {
isReset = Boolean.parseBoolean(prop);
} else {
isReset = isNonCombatDelegate(data);
}
} finally {
data.releaseReadLock();
}
return isReset;
}
public static boolean isBid(final GameData data) {
final boolean isBid;
data.acquireReadLock();
try {
final String prop = data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_bid);
if (prop != null) {
isBid = Boolean.parseBoolean(prop);
} else {
isBid = isBidPurchaseDelegate(data) || isBidPlaceDelegate(data);
}
} finally {
data.releaseReadLock();
}
return isBid;
}
/**
* @return a set of player ids. if argument player is not null this set will definitely include that player, but if
* not the set could be
* empty. never null.
*/
public static Set<PlayerID> getRepairPlayers(final GameData data, final PlayerID player) {
final Set<PlayerID> allowedIDs = new HashSet<>();
data.acquireReadLock();
try {
final String allowedPlayers =
data.getSequence().getStep().getProperties().getProperty(GameStep.PROPERTY_repairPlayers);
if (player != null) {
allowedIDs.add(player);
}
if (allowedPlayers != null) {
for (final String p : allowedPlayers.split(":")) {
final PlayerID id = data.getPlayerList().getPlayerID(p);
if (id == null) {
System.err.println("gamePlay sequence step: " + data.getSequence().getStep().getName() + " stepProperty: "
+ GameStep.PROPERTY_repairPlayers + " player: " + p + " DOES NOT EXIST");
} else {
allowedIDs.add(id);
}
}
}
} finally {
data.releaseReadLock();
}
return allowedIDs;
}
// private static members for testing default situation based on name of delegate
private static boolean isNonCombatDelegate(final GameData data) {
return data.getSequence().getStep().getName().endsWith("NonCombatMove");
}
private static boolean isCombatDelegate(final GameData data) {
if (data.getSequence().getStep().getName().endsWith("NonCombatMove")) {
return false;
} else if (data.getSequence().getStep().getName().endsWith("CombatMove")) {
return true;
}
return false;
}
private static boolean isAirborneDelegate(final GameData data) {
return data.getSequence().getStep().getName().endsWith("AirborneCombatMove");
}
private static boolean isBidPurchaseDelegate(final GameData data) {
return data.getSequence().getStep().getName().endsWith("Bid");
}
private static boolean isBidPlaceDelegate(final GameData data) {
return data.getSequence().getStep().getName().endsWith("BidPlace");
}
}