Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding haveResources and checkAIPlayer to RulesAttachment #11969

Closed
wants to merge 13 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class UnitTypeList extends GameDataComponent implements Iterable<UnitType
// Cached support rules. Marked transient as the cache does not need to be part of saved games.
private transient @Nullable Set<UnitSupportAttachment> supportRules;
private transient @Nullable Set<UnitSupportAttachment> supportAaRules;
private transient @Nullable Set<UnitSupportAttachment> supportAirRules;

public UnitTypeList(final GameData data) {
super(data);
Expand Down Expand Up @@ -81,6 +82,21 @@ public Set<UnitSupportAttachment> getSupportAaRules() {
return supportAaRules;
}

/**
* Returns the unit support rules for the unit types. Computed once and cached afterwards.
*
* @return The unit support rules.
*/
public Set<UnitSupportAttachment> getSupportAirRules() {
if (supportAirRules == null) {
supportAirRules =
UnitSupportAttachment.get(this).stream()
.filter(usa -> (usa.getAirRoll() || usa.getAirStrength()))
.collect(Collectors.toSet());
}
return supportAirRules;
}

public int size() {
return unitTypes.size();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.annotations.VisibleForTesting;
import games.strategy.engine.data.Attachable;
import games.strategy.engine.data.BattleRecordsList;
import games.strategy.engine.data.GameData;
Expand All @@ -13,6 +14,7 @@
import games.strategy.engine.data.MutableProperty;
import games.strategy.engine.data.RelationshipTracker.Relationship;
import games.strategy.engine.data.RelationshipType;
import games.strategy.engine.data.Resource;
import games.strategy.engine.data.TechnologyFrontier;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
Expand Down Expand Up @@ -55,9 +57,13 @@ public class RulesAttachment extends AbstractPlayerRulesAttachment {
private int techCount = -1;
// condition for having specific relationships
private @Nullable List<String> relationship = null;
// condition for checking ai player
private boolean checkAIPlayer = false;
// condition for being at war
private @Nullable Set<GamePlayer> atWarPlayers = null;
private int atWarCount = -1;
// condition for checking resources
private @Nullable String[] haveResources = null;
// condition for having destroyed at least X enemy non-neutral TUV (total unit value) [according
// to
// the prices the defender pays for the units]
Expand Down Expand Up @@ -145,6 +151,41 @@ public static Set<RulesAttachment> getNationalObjectives(final GamePlayer player
return natObjs;
}

@VisibleForTesting
public void setHaveResources(final String value) throws GameParseException {
final String[] s = splitOnColon(value);
if (s.length <= 1) {
throw new GameParseException(
"haveResources must have at least 2 fields. Format value=resource1 count=number, or "
+ "value=resource1:resource2:resource3 count=number"
+ thisErrorMsg());
}
final int n = getInt(s[0]);
if (n < 1) {
throw new GameParseException("haveResources must be a positive integer" + thisErrorMsg());
}
for (int i = 1; i < s.length; i++) {
// validate that this resource exists in the xml
final Resource r = getData().getResourceList().getResource(s[i]);
if (r == null) {
throw new GameParseException("No resource called: " + s[i] + thisErrorMsg());
}
}
haveResources = s;
}

private void setHaveResources(final String[] value) {
haveResources = value;
}

public String[] getHaveResources() {
return haveResources;
}

private void resetHaveResources() {
haveResources = null;
}

private void setDestroyedTuv(final String value) throws GameParseException {
final String[] s = splitOnColon(value);
if (s.length != 2) {
Expand Down Expand Up @@ -489,6 +530,22 @@ private void resetUnitPresence() {
unitPresence = null;
}

private void setCheckAIPlayer(final String s) {
checkAIPlayer = getBool(s);
}

private void setCheckAIPlayer(final Boolean s) {
checkAIPlayer = s;
}

public boolean getCheckAIPlayer() {
return checkAIPlayer;
}

private void resetCheckAIPlayer() {
checkAIPlayer = false;
}

private int getAtWarCount() {
return atWarCount;
}
Expand Down Expand Up @@ -735,11 +792,21 @@ public boolean isSatisfied(
}
objectiveMet = checkDirectOwnership(listedTerritories, players);
}
// check for ai controlled player
if (objectiveMet && getCheckAIPlayer()) {
objectiveMet = checkCheckAIPlayer(players);
}
// check for resources
if (objectiveMet && haveResources != null) {
objectiveMet = checkHaveResources(players);
}
// get attached to player
final GamePlayer playerAttachedTo = (GamePlayer) getAttachedTo();
// check for players at war
if (objectiveMet && !getAtWarPlayers().isEmpty()) {
objectiveMet = checkAtWar(playerAttachedTo, getAtWarPlayers(), getAtWarCount());
}
// check for techs
if (objectiveMet && !getTechs().isEmpty()) {
objectiveMet = checkTechs(playerAttachedTo, data.getTechnologyFrontier());
}
Expand Down Expand Up @@ -1001,6 +1068,14 @@ private boolean matchTerritories(
return numberMet >= getTerritoryCount();
}

private boolean checkCheckAIPlayer(final List<GamePlayer> players) {
boolean bcheck = true;
for (GamePlayer player : players) {
bcheck = (bcheck && player.isAi());
}
return bcheck;
}

private boolean checkAtWar(
final GamePlayer player, final Set<GamePlayer> enemies, final int count) {
int found = CollectionUtils.countMatches(enemies, player::isAtWar);
Expand Down Expand Up @@ -1031,6 +1106,18 @@ private boolean checkTechs(final GamePlayer player, final TechnologyFrontier tec
return found >= techCount;
}

@VisibleForTesting
public boolean checkHaveResources(final List<GamePlayer> players) {
int itotal = 0;
for (GamePlayer player : players) {
for (int i = 1; i < haveResources.length; i++) {
final Resource resource = getData().getResourceList().getResource(haveResources[i]);
itotal += player.getResources().getQuantity(resource);
}
}
return itotal >= getInt(haveResources[0]);
}

@Override
public void validate(final GameState data) {
validateNames(alliedOwnershipTerritories);
Expand All @@ -1057,6 +1144,12 @@ public MutableProperty<?> getPropertyOrNull(String propertyName) {
this::setRelationship,
this::getRelationship,
this::resetRelationship);
case "checkAIPlayer":
return MutableProperty.of(
this::setCheckAIPlayer,
this::setCheckAIPlayer,
this::getCheckAIPlayer,
this::resetCheckAIPlayer);
case "atWarPlayers":
return MutableProperty.of(
this::setAtWarPlayers,
Expand All @@ -1065,6 +1158,12 @@ public MutableProperty<?> getPropertyOrNull(String propertyName) {
this::resetAtWarPlayers);
case "atWarCount":
return MutableProperty.ofReadOnly(this::getAtWarCount);
case "haveResources":
return MutableProperty.of(
this::setHaveResources,
this::setHaveResources,
this::getHaveResources,
this::resetHaveResources);
case "destroyedTUV":
return MutableProperty.ofString(
this::setDestroyedTuv, this::getDestroyedTuv, this::resetDestroyedTuv);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class TechAbilityAttachment extends DefaultAttachment {
private @Nullable IntegerMap<UnitType> attackRollsBonus = null;
private @Nullable IntegerMap<UnitType> defenseRollsBonus = null;
private @Nullable IntegerMap<UnitType> bombingBonus = null;
private @Nullable IntegerMap<UnitType> tuvBonus = null;

public TechAbilityAttachment(
final String name, final Attachable attachable, final GameData gameData) {
Expand Down Expand Up @@ -692,6 +693,24 @@ private void resetBombingBonus() {
bombingBonus = null;
}

private void setTUVBonus(final String value) throws GameParseException {
if (tuvBonus == null) {
tuvBonus = new IntegerMap<>();
}
applyCheckedValue("tuvBonus", value, tuvBonus::put);
}

private void setTUVBonus(final IntegerMap<UnitType> value) {
tuvBonus = value;
}

public IntegerMap<UnitType> getTUVBonus() {
return getIntegerMapProperty(tuvBonus);
}

private void resetTUVBonus() {
tuvBonus = null;
}
public static boolean getAllowAirborneForces(final Collection<TechAdvance> techAdvances) {
return techAdvances.stream()
.map(TechAbilityAttachment::get)
Expand Down Expand Up @@ -1029,6 +1048,12 @@ public MutableProperty<?> getPropertyOrNull(String propertyName) {
this::setBombingBonus,
this::getBombingBonus,
this::resetBombingBonus);
case "tuvBonus":
return MutableProperty.of(
this::setTUVBonus,
this::setTUVBonus,
this::getTUVBonus,
this::resetTUVBonus);
default:
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2525,13 +2525,19 @@ private void setTuv(final String s) throws GameParseException {
tuv = getInt(s);
}

private void setTuv(final Integer s) {
@VisibleForTesting
public void setTuv(final Integer s) {
tuv = s;
}

public int getTuv() {
private int getTuv() {
return tuv;
}
public int getTuv(final GamePlayer player) {
// must account for -1 value, so that TUV can be calculated
final int bonus = getTechTracker().tuv(player, getUnitType());
return Math.max(-1, bonus + tuv);
}

private void resetTuv() {
tuv = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class UnitSupportAttachment extends DefaultAttachment {
private boolean strength = false;
private boolean aaRoll = false;
private boolean aaStrength = false;
private boolean airRoll = false;
private boolean airStrength = false;
private int bonus = 0;
private int number = 0;
private boolean allied = false;
Expand Down Expand Up @@ -184,9 +186,13 @@ public UnitSupportAttachment setDice(final String dice) throws GameParseExceptio
aaRoll = true;
} else if (element.equalsIgnoreCase("AAstrength")) {
aaStrength = true;
} else if (element.equalsIgnoreCase("airRoll")) {
airRoll = true;
} else if (element.equalsIgnoreCase("airStrength")) {
airStrength = true;
} else {
throw new GameParseException(
dice + " dice must be roll, strength, AAroll, or AAstrength: " + thisErrorMsg());
dice + " dice must be roll, strength, AAroll, AAstrength, airRoll, or airStrength: " + thisErrorMsg());
}
}
return this;
Expand All @@ -203,6 +209,8 @@ private void resetDice() {
strength = false;
aaRoll = false;
aaStrength = false;
airRoll = false;
airStrength = false;
}

private void setBonus(final String bonus) {
Expand Down Expand Up @@ -327,6 +335,14 @@ public boolean getAaStrength() {
return aaStrength;
}

public boolean getAirRoll() {
return airRoll;
}

public boolean getAirStrength() {
return airStrength;
}

public boolean getDefence() {
return defence;
}
Expand Down Expand Up @@ -437,6 +453,10 @@ public MutableProperty<?> getPropertyOrNull(String propertyName) {
return MutableProperty.ofReadOnly(this::getAaRoll);
case "aaStrength":
return MutableProperty.ofReadOnly(this::getAaStrength);
case "airRoll":
return MutableProperty.ofReadOnly(this::getAirRoll);
case "airStrength":
return MutableProperty.ofReadOnly(this::getAirStrength);
case BONUS:
return MutableProperty.of(this::setBonus, this::setBonus, this::getBonus, this::resetBonus);
case "number":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@ public boolean canBombard(GamePlayer player, UnitType type) {
return getCached(player, type, "canBombard", getter);
}

public int tuv(GamePlayer player, UnitType type) {
//sum will be 0 if there are no TUV bonus
//the return value must be checked against -1 calculate
final Supplier<Integer> getter =
() -> getSumOfBonuses(TechAbilityAttachment::getTUVBonus, type, player);
return getCached(player, type, "getTUVBonus", getter);
}

public int getMinimumTerritoryValueForProductionBonus(final GamePlayer player) {
final Supplier<Integer> getter =
() ->
Expand Down
Loading
Loading