use of games.strategy.engine.data.Unit in project triplea by triplea-game.
the class BattleDelegate method markDamaged.
static void markDamaged(final Collection<Unit> damaged, final IDelegateBridge bridge) {
if (damaged.size() == 0) {
return;
}
final IntegerMap<Unit> damagedMap = new IntegerMap<>();
for (final Unit u : damaged) {
damagedMap.add(u, 1);
}
bridge.addChange(createDamageChange(damagedMap, bridge));
}
use of games.strategy.engine.data.Unit in project triplea by triplea-game.
the class BattleDelegate method addBombardmentSources.
/**
* Add bombardment units to battles. Made public for test purposes only.
*/
void addBombardmentSources() {
final PlayerID attacker = bridge.getPlayerId();
final ITripleAPlayer remotePlayer = getRemotePlayer();
final Predicate<Unit> ownedAndCanBombard = Matches.unitCanBombard(attacker).and(Matches.unitIsOwnedBy(attacker));
final Map<Territory, Collection<IBattle>> adjBombardment = getPossibleBombardingTerritories();
final boolean shoreBombardPerGroundUnitRestricted = isShoreBombardPerGroundUnitRestricted(getData());
for (final Territory t : adjBombardment.keySet()) {
if (!battleTracker.hasPendingBattle(t, false)) {
Collection<IBattle> battles = adjBombardment.get(t);
battles = CollectionUtils.getMatches(battles, Matches.battleIsAmphibious());
if (!battles.isEmpty()) {
final Collection<Unit> bombardUnits = t.getUnits().getMatches(ownedAndCanBombard);
final List<Unit> listedBombardUnits = new ArrayList<>(bombardUnits);
sortUnitsToBombard(listedBombardUnits, attacker);
if (!bombardUnits.isEmpty()) {
// ask if they want to bombard
if (!remotePlayer.selectShoreBombard(t)) {
continue;
}
}
for (final Unit u : listedBombardUnits) {
final IBattle battle = selectBombardingBattle(u, t, battles);
if (battle != null) {
if (shoreBombardPerGroundUnitRestricted) {
if (battle.getAmphibiousLandAttackers().size() <= battle.getBombardingUnits().size()) {
battles.remove(battle);
break;
}
}
battle.addBombardingUnit(u);
}
}
}
}
}
}
use of games.strategy.engine.data.Unit in project triplea by triplea-game.
the class BattleDelegate method setupUnitsInSameTerritoryBattles.
/**
* Setup the battles where the battle occurs because units are in the
* same territory. This happens when subs emerge (after being submerged), and
* when naval units are placed in enemy occupied sea zones, and also
* when political relationships change and potentially leave units in now-hostile territories.
*/
private static void setupUnitsInSameTerritoryBattles(final BattleTracker battleTracker, final IDelegateBridge bridge) {
final PlayerID player = bridge.getPlayerId();
final GameData data = bridge.getData();
final boolean ignoreTransports = isIgnoreTransportInMovement(data);
final boolean ignoreSubs = isIgnoreSubInMovement(data);
final Predicate<Unit> seaTransports = Matches.unitIsTransportButNotCombatTransport().and(Matches.unitIsSea());
final Predicate<Unit> seaTranportsOrSubs = seaTransports.or(Matches.unitIsSub());
// we want to match all sea zones with our units and enemy units
final Predicate<Territory> anyTerritoryWithOwnAndEnemy = Matches.territoryHasUnitsOwnedBy(player).and(Matches.territoryHasEnemyUnits(player, data));
final Predicate<Territory> enemyTerritoryAndOwnUnits = Matches.isTerritoryEnemyAndNotUnownedWater(player, data).and(Matches.territoryHasUnitsOwnedBy(player));
final Predicate<Territory> enemyUnitsOrEnemyTerritory = anyTerritoryWithOwnAndEnemy.or(enemyTerritoryAndOwnUnits);
final List<Territory> battleTerritories = CollectionUtils.getMatches(data.getMap().getTerritories(), enemyUnitsOrEnemyTerritory);
for (final Territory territory : battleTerritories) {
final List<Unit> attackingUnits = territory.getUnits().getMatches(Matches.unitIsOwnedBy(player));
// now make sure to add any units that must move with these attacking units, so that they get included as
// dependencies
final Map<Unit, Collection<Unit>> transportMap = TransportTracker.transporting(territory.getUnits());
final HashSet<Unit> dependants = new HashSet<>();
for (final Entry<Unit, Collection<Unit>> entry : transportMap.entrySet()) {
// only consider those transports that we are attacking with. allied and enemy transports are not added.
if (attackingUnits.contains(entry.getKey())) {
dependants.addAll(entry.getValue());
}
}
// no duplicates
dependants.removeAll(attackingUnits);
// add the dependants to the attacking list
attackingUnits.addAll(dependants);
final List<Unit> enemyUnits = territory.getUnits().getMatches(Matches.enemyUnit(player, data));
final IBattle bombingBattle = battleTracker.getPendingBattle(territory, true, null);
if (bombingBattle != null) {
// we need to remove any units which are participating in bombing raids
attackingUnits.removeAll(bombingBattle.getAttackingUnits());
}
if (attackingUnits.stream().allMatch(Matches.unitIsInfrastructure())) {
continue;
}
IBattle battle = battleTracker.getPendingBattle(territory, false, BattleType.NORMAL);
if (battle == null) {
// fires)
if (enemyUnits.stream().allMatch(Matches.unitIsInfrastructure())) {
landParatroopers(player, territory, bridge);
}
bridge.getHistoryWriter().startEvent(player.getName() + " creates battle in territory " + territory.getName());
battleTracker.addBattle(new RouteScripted(territory), attackingUnits, player, bridge, null, null);
battle = battleTracker.getPendingBattle(territory, false, BattleType.NORMAL);
}
if (battle == null) {
continue;
}
if (bombingBattle != null) {
battleTracker.addDependency(battle, bombingBattle);
}
if (battle.isEmpty()) {
battle.addAttackChange(new RouteScripted(territory), attackingUnits, null);
}
if (!battle.getAttackingUnits().containsAll(attackingUnits)) {
List<Unit> attackingUnitsNeedToBeAdded = new ArrayList<>(attackingUnits);
attackingUnitsNeedToBeAdded.removeAll(battle.getAttackingUnits());
attackingUnitsNeedToBeAdded.removeAll(battle.getDependentUnits(battle.getAttackingUnits()));
if (territory.isWater()) {
attackingUnitsNeedToBeAdded = CollectionUtils.getMatches(attackingUnitsNeedToBeAdded, Matches.unitIsLand().negate());
} else {
attackingUnitsNeedToBeAdded = CollectionUtils.getMatches(attackingUnitsNeedToBeAdded, Matches.unitIsSea().negate());
}
if (!attackingUnitsNeedToBeAdded.isEmpty()) {
battle.addAttackChange(new RouteScripted(territory), attackingUnitsNeedToBeAdded, null);
}
}
// Reach stalemate if all attacking and defending units are transports
if ((ignoreTransports && !attackingUnits.isEmpty() && attackingUnits.stream().allMatch(seaTransports) && !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(seaTransports)) || (!attackingUnits.isEmpty() && attackingUnits.stream().allMatch(Matches.unitHasAttackValueOfAtLeast(1).negate()) && !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(Matches.unitHasDefendValueOfAtLeast(1).negate()))) {
final BattleResults results = new BattleResults(battle, WhoWon.DRAW, data);
battleTracker.getBattleRecords().addResultToBattle(player, battle.getBattleId(), null, 0, 0, BattleRecord.BattleResultDescription.STALEMATE, results);
battle.cancelBattle(bridge);
battleTracker.removeBattle(battle);
continue;
}
// possibility to ignore battle altogether
if (!attackingUnits.isEmpty()) {
final ITripleAPlayer remotePlayer = getRemotePlayer(bridge);
if (territory.isWater() && Properties.getSeaBattlesMayBeIgnored(data)) {
if (!remotePlayer.selectAttackUnits(territory)) {
final BattleResults results = new BattleResults(battle, WhoWon.NOTFINISHED, data);
battleTracker.getBattleRecords().addResultToBattle(player, battle.getBattleId(), null, 0, 0, BattleRecord.BattleResultDescription.NO_BATTLE, results);
battle.cancelBattle(bridge);
battleTracker.removeBattle(battle);
}
continue;
}
// Check for ignored units
if (ignoreTransports || ignoreSubs) {
// if only enemy transports... attack them?
if (ignoreTransports && !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(seaTransports)) {
if (!remotePlayer.selectAttackTransports(territory)) {
final BattleResults results = new BattleResults(battle, WhoWon.NOTFINISHED, data);
battleTracker.getBattleRecords().addResultToBattle(player, battle.getBattleId(), null, 0, 0, BattleRecord.BattleResultDescription.NO_BATTLE, results);
battle.cancelBattle(bridge);
battleTracker.removeBattle(battle);
}
continue;
}
// if only enemy subs... attack them?
if (ignoreSubs && !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(Matches.unitIsSub())) {
if (!remotePlayer.selectAttackSubs(territory)) {
final BattleResults results = new BattleResults(battle, WhoWon.NOTFINISHED, data);
battleTracker.getBattleRecords().addResultToBattle(player, battle.getBattleId(), null, 0, 0, BattleRecord.BattleResultDescription.NO_BATTLE, results);
battle.cancelBattle(bridge);
battleTracker.removeBattle(battle);
}
continue;
}
// if only enemy transports and subs... attack them?
if (ignoreSubs && ignoreTransports && !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(seaTranportsOrSubs)) {
if (!remotePlayer.selectAttackUnits(territory)) {
final BattleResults results = new BattleResults(battle, WhoWon.NOTFINISHED, data);
battleTracker.getBattleRecords().addResultToBattle(player, battle.getBattleId(), null, 0, 0, BattleRecord.BattleResultDescription.NO_BATTLE, results);
battle.cancelBattle(bridge);
battleTracker.removeBattle(battle);
}
}
}
}
}
}
use of games.strategy.engine.data.Unit 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.Unit 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