use of games.strategy.engine.data.Change in project triplea by triplea-game.
the class BattleDelegate method moveAirAndLand.
private static void moveAirAndLand(final IDelegateBridge bridge, final Collection<Unit> defendingAirBeingMoved, final Collection<Unit> defendingAirTotal, final Territory newTerritory, final Territory battleSite) {
bridge.getHistoryWriter().addChildToEvent(MyFormatter.unitsToText(defendingAirBeingMoved) + " forced to land in " + newTerritory.getName(), new ArrayList<>(defendingAirBeingMoved));
final Change change = ChangeFactory.moveUnits(battleSite, newTerritory, defendingAirBeingMoved);
bridge.addChange(change);
// remove those that landed in case it was a carrier
defendingAirTotal.removeAll(defendingAirBeingMoved);
}
use of games.strategy.engine.data.Change in project triplea by triplea-game.
the class BattleDelegate method createDamageChange.
private static Change createDamageChange(final IntegerMap<Unit> damagedMap, final IDelegateBridge bridge) {
final Set<Unit> units = new HashSet<>(damagedMap.keySet());
for (final Unit u : units) {
damagedMap.add(u, u.getHits());
}
final Change damagedChange = ChangeFactory.unitsHit(damagedMap);
bridge.getHistoryWriter().addChildToEvent("Units damaged: " + MyFormatter.unitsToText(units), units);
return damagedChange;
}
use of games.strategy.engine.data.Change in project triplea by triplea-game.
the class BattleDelegate method checkDefendingPlanesCanLand.
private void checkDefendingPlanesCanLand() {
final GameData data = getData();
final Map<Territory, Collection<Unit>> defendingAirThatCanNotLand = battleTracker.getDefendingAirThatCanNotLand();
final boolean isWW2v2orIsSurvivingAirMoveToLand = Properties.getWW2V2(data) || Properties.getSurvivingAirMoveToLand(data);
final Predicate<Unit> alliedDefendingAir = Matches.unitIsAir().and(Matches.unitWasScrambled().negate());
for (final Entry<Territory, Collection<Unit>> entry : defendingAirThatCanNotLand.entrySet()) {
final Territory battleSite = entry.getKey();
final Collection<Unit> defendingAir = entry.getValue();
if (defendingAir == null || defendingAir.isEmpty()) {
continue;
}
defendingAir.retainAll(battleSite.getUnits());
if (defendingAir.isEmpty()) {
continue;
}
final PlayerID defender = AbstractBattle.findDefender(battleSite, player, data);
// Get all land territories where we can land
final Set<Territory> neighbors = data.getMap().getNeighbors(battleSite);
final Predicate<Territory> alliedLandTerritories = Matches.airCanLandOnThisAlliedNonConqueredLandTerritory(defender, data);
// Get those that are neighbors
final Collection<Territory> canLandHere = CollectionUtils.getMatches(neighbors, alliedLandTerritories);
// Get all sea territories where there are allies
final Predicate<Territory> neighboringSeaZonesWithAlliedUnits = Matches.territoryIsWater().and(Matches.territoryHasAlliedUnits(defender, data));
// Get those that are neighbors
final Collection<Territory> areSeaNeighbors = CollectionUtils.getMatches(neighbors, neighboringSeaZonesWithAlliedUnits);
// Set up match criteria for allied carriers
final Predicate<Unit> alliedCarrier = Matches.unitIsCarrier().and(Matches.alliedUnit(defender, data));
// Set up match criteria for allied planes
final Predicate<Unit> alliedPlane = Matches.unitIsAir().and(Matches.alliedUnit(defender, data));
// See if neighboring carriers have any capacity available
for (final Territory currentTerritory : areSeaNeighbors) {
// get the capacity of the carriers and cost of fighters
final Collection<Unit> alliedCarriers = currentTerritory.getUnits().getMatches(alliedCarrier);
final Collection<Unit> alliedPlanes = currentTerritory.getUnits().getMatches(alliedPlane);
final int alliedCarrierCapacity = AirMovementValidator.carrierCapacity(alliedCarriers, currentTerritory);
final int alliedPlaneCost = AirMovementValidator.carrierCost(alliedPlanes);
// if there is free capacity, add the territory to landing possibilities
if (alliedCarrierCapacity - alliedPlaneCost >= 1) {
canLandHere.add(currentTerritory);
}
}
if (isWW2v2orIsSurvivingAirMoveToLand) {
Territory territory;
while (canLandHere.size() > 1 && defendingAir.size() > 0) {
territory = getRemotePlayer(defender).selectTerritoryForAirToLand(canLandHere, battleSite, "Select territory for air units to land. (Current territory is " + battleSite.getName() + "): " + MyFormatter.unitsToText(defendingAir));
// added for test script
if (territory == null) {
territory = canLandHere.iterator().next();
}
if (territory.isWater()) {
landPlanesOnCarriers(bridge, alliedDefendingAir, defendingAir, alliedCarrier, alliedPlane, territory, battleSite);
} else {
moveAirAndLand(bridge, defendingAir, defendingAir, territory, battleSite);
continue;
}
// remove the territory from those available
canLandHere.remove(territory);
}
// Land in the last remaining territory
if (canLandHere.size() > 0 && defendingAir.size() > 0) {
territory = canLandHere.iterator().next();
if (territory.isWater()) {
landPlanesOnCarriers(bridge, alliedDefendingAir, defendingAir, alliedCarrier, alliedPlane, territory, battleSite);
} else {
moveAirAndLand(bridge, defendingAir, defendingAir, territory, battleSite);
continue;
}
}
} else if (canLandHere.size() > 0) {
// check for an island in this sea zone
for (final Territory currentTerritory : canLandHere) {
// only one neighbor, its an island.
if (data.getMap().getNeighbors(currentTerritory).size() == 1) {
moveAirAndLand(bridge, defendingAir, defendingAir, currentTerritory, battleSite);
}
}
}
if (defendingAir.size() > 0) {
// no where to go, they must die
bridge.getHistoryWriter().addChildToEvent(MyFormatter.unitsToText(defendingAir) + " could not land and were killed", new ArrayList<>(defendingAir));
final Change change = ChangeFactory.removeUnits(battleSite, defendingAir);
bridge.addChange(change);
}
}
}
use of games.strategy.engine.data.Change in project triplea by triplea-game.
the class BattleTracker method addBombingBattle.
private void addBombingBattle(final Route route, final Collection<Unit> units, final PlayerID attacker, final GameData data, final HashMap<Unit, HashSet<Unit>> targets) {
IBattle battle = getPendingBattle(route.getEnd(), true, BattleType.BOMBING_RAID);
if (battle == null) {
battle = new StrategicBombingRaidBattle(route.getEnd(), data, attacker, this);
m_pendingBattles.add(battle);
getBattleRecords().addBattle(attacker, battle.getBattleId(), route.getEnd(), battle.getBattleType());
}
final Change change = battle.addAttackChange(route, units, targets);
// when state is moved to the game data, this will change
if (!change.isEmpty()) {
throw new IllegalStateException("Non empty change");
}
// dont let land battles in the same territory occur before bombing battles
final IBattle dependent = getPendingBattle(route.getEnd(), false, BattleType.NORMAL);
if (dependent != null) {
addDependency(dependent, battle);
}
final IBattle dependentAirBattle = getPendingBattle(route.getEnd(), false, BattleType.AIR_BATTLE);
if (dependentAirBattle != null) {
addDependency(dependentAirBattle, battle);
}
}
use of games.strategy.engine.data.Change in project triplea by triplea-game.
the class BattleTracker method captureOrDestroyUnits.
/**
* Called when a territory is conquered to determine if remaining enemy units should be
* captured, destroyed, or take damage.
*/
public static void captureOrDestroyUnits(final Territory territory, final PlayerID id, final PlayerID newOwner, final IDelegateBridge bridge, final UndoableMove changeTracker) {
final GameData data = bridge.getData();
// destroy any units that should be destroyed on capture
if (Properties.getUnitsCanBeDestroyedInsteadOfCaptured(data)) {
final Predicate<Unit> enemyToBeDestroyed = Matches.enemyUnit(id, data).and(Matches.unitDestroyedWhenCapturedByOrFrom(id));
final Collection<Unit> destroyed = territory.getUnits().getMatches(enemyToBeDestroyed);
if (!destroyed.isEmpty()) {
final Change destroyUnits = ChangeFactory.removeUnits(territory, destroyed);
bridge.getHistoryWriter().addChildToEvent("Some non-combat units are destroyed: ", destroyed);
bridge.addChange(destroyUnits);
if (changeTracker != null) {
changeTracker.addChange(destroyUnits);
}
}
}
// destroy any capture on entering units, IF the property to destroy them instead of capture is turned on
if (Properties.getOnEnteringUnitsDestroyedInsteadOfCaptured(data)) {
final Collection<Unit> destroyed = territory.getUnits().getMatches(Matches.unitCanBeCapturedOnEnteringToInThisTerritory(id, territory, data));
if (!destroyed.isEmpty()) {
final Change destroyUnits = ChangeFactory.removeUnits(territory, destroyed);
bridge.getHistoryWriter().addChildToEvent(id.getName() + " destroys some units instead of capturing them", destroyed);
bridge.addChange(destroyUnits);
if (changeTracker != null) {
changeTracker.addChange(destroyUnits);
}
}
}
// destroy any disabled units owned by the enemy that are NOT infrastructure or factories
final Predicate<Unit> enemyToBeDestroyed = Matches.enemyUnit(id, data).and(Matches.unitIsDisabled()).and(Matches.unitIsInfrastructure().negate());
final Collection<Unit> destroyed = territory.getUnits().getMatches(enemyToBeDestroyed);
if (!destroyed.isEmpty()) {
final Change destroyUnits = ChangeFactory.removeUnits(territory, destroyed);
bridge.getHistoryWriter().addChildToEvent(id.getName() + " destroys some disabled combat units", destroyed);
bridge.addChange(destroyUnits);
if (changeTracker != null) {
changeTracker.addChange(destroyUnits);
}
}
// take over non combatants
final Predicate<Unit> enemyNonCom = Matches.enemyUnit(id, data).and(Matches.unitIsInfrastructure());
final Predicate<Unit> willBeCaptured = enemyNonCom.or(Matches.unitCanBeCapturedOnEnteringToInThisTerritory(id, territory, data));
final Collection<Unit> nonCom = territory.getUnits().getMatches(willBeCaptured);
// change any units that change unit types on capture
if (Properties.getUnitsCanBeChangedOnCapture(data)) {
final Collection<Unit> toReplace = CollectionUtils.getMatches(nonCom, Matches.unitWhenCapturedChangesIntoDifferentUnitType());
for (final Unit u : toReplace) {
final Map<String, Tuple<String, IntegerMap<UnitType>>> map = UnitAttachment.get(u.getType()).getWhenCapturedChangesInto();
final PlayerID currentOwner = u.getOwner();
for (final String value : map.keySet()) {
final String[] s = value.split(":");
if (!(s[0].equals("any") || data.getPlayerList().getPlayerId(s[0]).equals(currentOwner))) {
continue;
}
// we could use "id" or "newOwner" here... not sure which to use
if (!(s[1].equals("any") || data.getPlayerList().getPlayerId(s[1]).equals(id))) {
continue;
}
final CompositeChange changes = new CompositeChange();
final Collection<Unit> toAdd = new ArrayList<>();
final Tuple<String, IntegerMap<UnitType>> toCreate = map.get(value);
final boolean translateAttributes = toCreate.getFirst().equalsIgnoreCase("true");
for (final UnitType ut : toCreate.getSecond().keySet()) {
toAdd.addAll(ut.create(toCreate.getSecond().getInt(ut), newOwner));
}
if (!toAdd.isEmpty()) {
if (translateAttributes) {
final Change translate = TripleAUnit.translateAttributesToOtherUnits(u, toAdd, territory);
if (!translate.isEmpty()) {
changes.add(translate);
}
}
changes.add(ChangeFactory.removeUnits(territory, Collections.singleton(u)));
changes.add(ChangeFactory.addUnits(territory, toAdd));
changes.add(ChangeFactory.markNoMovementChange(toAdd));
bridge.getHistoryWriter().addChildToEvent(id.getName() + " converts " + u.toStringNoOwner() + " into different units", toAdd);
bridge.addChange(changes);
if (changeTracker != null) {
changeTracker.addChange(changes);
}
// don't forget to remove this unit from the list
nonCom.remove(u);
break;
}
}
}
}
if (!nonCom.isEmpty()) {
// FYI: a dummy delegate will not do anything with this change,
// meaning that the battle calculator will think this unit lived,
// even though it died or was captured, etc!
final Change capture = ChangeFactory.changeOwner(nonCom, newOwner, territory);
bridge.addChange(capture);
if (changeTracker != null) {
changeTracker.addChange(capture);
}
final Change noMovementChange = ChangeFactory.markNoMovementChange(nonCom);
bridge.addChange(noMovementChange);
if (changeTracker != null) {
changeTracker.addChange(noMovementChange);
}
final IntegerMap<Unit> damageMap = new IntegerMap<>();
for (final Unit unit : CollectionUtils.getMatches(nonCom, Matches.unitWhenCapturedSustainsDamage())) {
final TripleAUnit taUnit = (TripleAUnit) unit;
final int damageLimit = taUnit.getHowMuchMoreDamageCanThisUnitTake(unit, territory);
final int sustainedDamage = UnitAttachment.get(unit.getType()).getWhenCapturedSustainsDamage();
final int actualDamage = Math.max(0, Math.min(sustainedDamage, damageLimit));
final int totalDamage = taUnit.getUnitDamage() + actualDamage;
damageMap.put(unit, totalDamage);
}
if (!damageMap.isEmpty()) {
final Change damageChange = ChangeFactory.bombingUnitDamage(damageMap);
bridge.addChange(damageChange);
if (changeTracker != null) {
changeTracker.addChange(damageChange);
}
// Kill any units that can die if they have reached max damage
if (damageMap.keySet().stream().anyMatch(Matches.unitCanDieFromReachingMaxDamage())) {
final List<Unit> unitsCanDie = CollectionUtils.getMatches(damageMap.keySet(), Matches.unitCanDieFromReachingMaxDamage());
unitsCanDie.retainAll(CollectionUtils.getMatches(unitsCanDie, Matches.unitIsAtMaxDamageOrNotCanBeDamaged(territory)));
if (!unitsCanDie.isEmpty()) {
final Change removeDead = ChangeFactory.removeUnits(territory, unitsCanDie);
bridge.addChange(removeDead);
if (changeTracker != null) {
changeTracker.addChange(removeDead);
}
}
}
}
}
}
Aggregations