package games.strategy.triplea.attachments; import java.util.ArrayList; import java.util.HashMap; import games.strategy.engine.data.Attachable; import games.strategy.engine.data.GameData; import games.strategy.engine.data.GameParseException; import games.strategy.engine.data.PlayerID; import games.strategy.engine.data.annotations.GameProperty; import games.strategy.engine.data.annotations.InternalDoNotExport; import games.strategy.engine.data.changefactory.ChangeFactory; import games.strategy.engine.delegate.IDelegateBridge; import games.strategy.util.Match; /** * Abstract class for holding various action/condition things for PoliticalActionAttachment and UserActionAttachment. */ public abstract class AbstractUserActionAttachment extends AbstractConditionsAttachment { private static final long serialVersionUID = 3569461523853104614L; public static final String ATTEMPTS_LEFT_THIS_TURN = "attemptsLeftThisTurn"; public AbstractUserActionAttachment(final String name, final Attachable attachable, final GameData gameData) { super(name, attachable, gameData); } // a key referring to politicaltexts.properties or other .properties for all the UI messages belonging to this action. protected String m_text = ""; // cost in PU to attempt this action protected int m_costPU = 0; // how many times can you perform this action each round? protected int m_attemptsPerTurn = 1; // how many times are left to perform this action each round? @InternalDoNotExport // Do Not Export (do not include in IAttachment). protected int m_attemptsLeftThisTurn = 1; // which players should accept this action? this could be the player who is the target of this action in the case of // proposing a treaty or // the players in your 'alliance' in case you want to declare war... // especially for actions such as when france declares war on germany and it automatically causes UK to declare war as // well. it is good to // set "actionAccept" to "UK" so UK can accept this action to go through. protected ArrayList<PlayerID> m_actionAccept = new ArrayList<>(); public static Match<AbstractUserActionAttachment> isSatisfiedMatch( final HashMap<ICondition, Boolean> testedConditions) { return new Match<AbstractUserActionAttachment>() { @Override public boolean match(final AbstractUserActionAttachment value) { return value.isSatisfied(testedConditions); } }; } /** * @return true if there is no condition to this action or if the condition is satisfied. */ public boolean canPerform(final HashMap<ICondition, Boolean> testedConditions) { return m_conditions == null || isSatisfied(testedConditions); } /** * @param text * the Key that is used in politicstext.properties or other .properties for all the texts */ @GameProperty(xmlProperty = true, gameProperty = true, adds = false) public void setText(final String text) { m_text = text; } /** * @return The Key that is used in politicstext.properties or other .properties for all the texts. */ public String getText() { return m_text; } public void resetText() { m_text = ""; } /** * @param s * the amount you need to pay to perform the action. */ @GameProperty(xmlProperty = true, gameProperty = true, adds = false) public void setCostPU(final String s) { m_costPU = getInt(s); } @GameProperty(xmlProperty = true, gameProperty = true, adds = false) public void setCostPU(final Integer s) { m_costPU = s; } /** * @return The amount you need to pay to perform the action. */ public int getCostPU() { return m_costPU; } public void resetCostPU() { m_costPU = 0; } /** * Adds to, not sets. Anything that adds to instead of setting needs a clear function as well. */ @GameProperty(xmlProperty = true, gameProperty = true, adds = true) public void setActionAccept(final String value) throws GameParseException { final String[] temp = value.split(":"); for (final String name : temp) { final PlayerID tempPlayer = getData().getPlayerList().getPlayerID(name); if (tempPlayer != null) { m_actionAccept.add(tempPlayer); } else { throw new GameParseException("No player named: " + name + thisErrorMsg()); } } } @GameProperty(xmlProperty = true, gameProperty = true, adds = false) public void setActionAccept(final ArrayList<PlayerID> value) { m_actionAccept = value; } /** * @return a list of players that must accept this action before it takes effect. */ public ArrayList<PlayerID> getActionAccept() { return m_actionAccept; } public void clearActionAccept() { m_actionAccept.clear(); } public void resetActionAccept() { m_actionAccept = new ArrayList<>(); } /** * @param s * the amount of times you can try this Action per Round. */ @GameProperty(xmlProperty = true, gameProperty = true, adds = false) public void setAttemptsPerTurn(final String s) { m_attemptsPerTurn = getInt(s); setAttemptsLeftThisTurn(m_attemptsPerTurn); } @GameProperty(xmlProperty = true, gameProperty = true, adds = false) public void setAttemptsPerTurn(final Integer s) { m_attemptsPerTurn = s; setAttemptsLeftThisTurn(m_attemptsPerTurn); } /** * @return The amount of times you can try this Action per Round. */ public int getAttemptsPerTurn() { return m_attemptsPerTurn; } public void resetAttemptsPerTurn() { m_attemptsPerTurn = 1; } /** * @param attempts * left this turn. */ @GameProperty(xmlProperty = false, gameProperty = true, adds = false) public void setAttemptsLeftThisTurn(final int attempts) { m_attemptsLeftThisTurn = attempts; } @GameProperty(xmlProperty = false, gameProperty = true, adds = false) public void setAttemptsLeftThisTurn(final Integer attempts) { m_attemptsLeftThisTurn = attempts; } /** * @return attempts that are left this turn. */ public int getAttemptsLeftThisTurn() { return m_attemptsLeftThisTurn; } public void resetAttemptsLeftThisTurn() { m_attemptsLeftThisTurn = 1; } public void resetAttempts(final IDelegateBridge aBridge) { if (m_attemptsLeftThisTurn != m_attemptsPerTurn) { aBridge.addChange(ChangeFactory.attachmentPropertyChange(this, m_attemptsPerTurn, ATTEMPTS_LEFT_THIS_TURN)); } } public void useAttempt(final IDelegateBridge aBridge) { aBridge .addChange(ChangeFactory.attachmentPropertyChange(this, (m_attemptsLeftThisTurn - 1), ATTEMPTS_LEFT_THIS_TURN)); } public boolean hasAttemptsLeft() { return m_attemptsLeftThisTurn > 0; } @Override public void validate(final GameData data) throws GameParseException { super.validate(data); if (m_text.trim().length() <= 0) { throw new GameParseException("value: text can't be empty" + thisErrorMsg()); } } }