use of games.strategy.engine.data.CompositeChange in project triplea by triplea-game.
the class BattleDelegate method scramblingCleanup.
private void scramblingCleanup() {
// return scrambled units to their original territories, or let them move 1 or x to a new territory.
final GameData data = getData();
if (!Properties.getScrambleRulesInEffect(data)) {
return;
}
final boolean mustReturnToBase = Properties.getScrambledUnitsReturnToBase(data);
for (final Territory t : data.getMap().getTerritories()) {
int carrierCostOfCurrentTerr = 0;
final Collection<Unit> wasScrambled = t.getUnits().getMatches(Matches.unitWasScrambled());
for (final Unit u : wasScrambled) {
final CompositeChange change = new CompositeChange();
final Territory originatedFrom = TripleAUnit.get(u).getOriginatedFrom();
Territory landingTerr = null;
final String historyText;
if (!mustReturnToBase || !Matches.isTerritoryAllied(u.getOwner(), data).test(originatedFrom)) {
final Collection<Territory> possible = whereCanAirLand(Collections.singletonList(u), t, u.getOwner(), data, battleTracker, carrierCostOfCurrentTerr, 1, !mustReturnToBase);
if (possible.size() > 1) {
landingTerr = getRemotePlayer(u.getOwner()).selectTerritoryForAirToLand(possible, t, "Select territory for air units to land. (Current territory is " + t.getName() + "): " + MyFormatter.unitsToText(Collections.singletonList(u)));
} else if (possible.size() == 1) {
landingTerr = possible.iterator().next();
}
if (landingTerr == null || landingTerr.equals(t)) {
carrierCostOfCurrentTerr += AirMovementValidator.carrierCost(Collections.singletonList(u));
historyText = "Scrambled unit stays in territory " + t.getName();
} else {
historyText = "Moving scrambled unit from " + t.getName() + " to " + landingTerr.getName();
}
} else {
landingTerr = originatedFrom;
historyText = "Moving scrambled unit from " + t.getName() + " back to originating territory: " + landingTerr.getName();
}
// if null, we leave it to die
if (landingTerr != null) {
change.add(ChangeFactory.moveUnits(t, landingTerr, Collections.singletonList(u)));
change.add(Route.getFuelChanges(Collections.singleton(u), new Route(t, landingTerr), u.getOwner(), data));
}
change.add(ChangeFactory.unitPropertyChange(u, null, TripleAUnit.ORIGINATED_FROM));
change.add(ChangeFactory.unitPropertyChange(u, false, TripleAUnit.WAS_SCRAMBLED));
if (!change.isEmpty()) {
bridge.getHistoryWriter().startEvent(historyText, u);
bridge.addChange(change);
}
}
}
}
use of games.strategy.engine.data.CompositeChange in project triplea by triplea-game.
the class BattleDelegate method resetMaxScrambleCount.
private static void resetMaxScrambleCount(final IDelegateBridge bridge) {
// reset the tripleaUnit property for all airbases that were used
final GameData data = bridge.getData();
if (!Properties.getScrambleRulesInEffect(data)) {
return;
}
final CompositeChange change = new CompositeChange();
for (final Territory t : data.getMap().getTerritories()) {
final Collection<Unit> airbases = t.getUnits().getMatches(Matches.unitIsAirBase());
for (final Unit u : airbases) {
final UnitAttachment ua = UnitAttachment.get(u.getType());
final int currentMax = ((TripleAUnit) u).getMaxScrambleCount();
final int allowedMax = ua.getMaxScrambleCount();
if (currentMax != allowedMax) {
change.add(ChangeFactory.unitPropertyChange(u, allowedMax, TripleAUnit.MAX_SCRAMBLE_COUNT));
}
}
}
if (!change.isEmpty()) {
bridge.getHistoryWriter().startEvent("Preparing Airbases for Possible Scrambling");
bridge.addChange(change);
}
}
use of games.strategy.engine.data.CompositeChange in project triplea by triplea-game.
the class BattleDelegate method landParatroopers.
private static void landParatroopers(final PlayerID player, final Territory battleSite, final IDelegateBridge bridge) {
if (TechTracker.hasParatroopers(player)) {
final Collection<Unit> airTransports = CollectionUtils.getMatches(battleSite.getUnits(), Matches.unitIsAirTransport());
final Collection<Unit> paratroops = CollectionUtils.getMatches(battleSite.getUnits(), Matches.unitIsAirTransportable());
if (!airTransports.isEmpty() && !paratroops.isEmpty()) {
final CompositeChange change = new CompositeChange();
for (final Unit u : paratroops) {
final TripleAUnit taUnit = (TripleAUnit) u;
final Unit transport = taUnit.getTransportedBy();
if (transport == null || !airTransports.contains(transport)) {
continue;
}
change.add(TransportTracker.unloadAirTransportChange(taUnit, battleSite, false));
}
if (!change.isEmpty()) {
bridge.getHistoryWriter().startEvent(player.getName() + " lands units in " + battleSite.getName());
bridge.addChange(change);
}
}
}
}
use of games.strategy.engine.data.CompositeChange in project triplea by triplea-game.
the class BattleTracker method undoBattle.
void undoBattle(final Route route, final Collection<Unit> units, final PlayerID player, final IDelegateBridge bridge) {
for (final IBattle battle : new ArrayList<>(m_pendingBattles)) {
if (battle.getTerritory().equals(route.getEnd())) {
battle.removeAttack(route, units);
if (battle.isEmpty()) {
removeBattleForUndo(player, battle);
}
}
}
final RelationshipTracker relationshipTracker = bridge.getData().getRelationshipTracker();
// because we could have conquered the end territory if there are no units there
for (final Territory current : route.getAllTerritories()) {
if (!relationshipTracker.isAllied(current.getOwner(), player) && m_conquered.contains(current)) {
m_conquered.remove(current);
m_blitzed.remove(current);
}
}
// say they weren't in combat
final CompositeChange change = new CompositeChange();
for (final Unit unit : units) {
change.add(ChangeFactory.unitPropertyChange(unit, false, TripleAUnit.WAS_IN_COMBAT));
}
bridge.addChange(change);
}
use of games.strategy.engine.data.CompositeChange 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