use of games.strategy.engine.delegate.IDelegateBridge in project triplea by triplea-game.
the class MovePerformer method populateStack.
/**
* We assume that the move is valid.
*/
private void populateStack(final Collection<Unit> units, final Route route, final PlayerID id, final Collection<Unit> transportsToLoad) {
final IExecutable preAaFire = new IExecutable() {
private static final long serialVersionUID = -7945930782650355037L;
@Override
public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
// this can happen for air units moving out of a battle zone
for (final IBattle battle : getBattleTracker().getPendingBattles(route.getStart(), null)) {
for (final Unit unit : units) {
final Route routeUnitUsedToMove = moveDelegate.getRouteUsedToMoveInto(unit, route.getStart());
if (battle != null) {
battle.removeAttack(routeUnitUsedToMove, Collections.singleton(unit));
}
}
}
}
};
// hack to allow the executables to share state
final IExecutable fireAa = new IExecutable() {
private static final long serialVersionUID = -3780228078499895244L;
@Override
public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
final Collection<Unit> aaCasualties = fireAa(route, units);
final Set<Unit> aaCasualtiesWithDependents = new HashSet<>();
// need to remove any dependents here
if (aaCasualties != null) {
aaCasualtiesWithDependents.addAll(aaCasualties);
final Map<Unit, Collection<Unit>> dependencies = TransportTracker.transporting(units, units);
for (final Unit u : aaCasualties) {
final Collection<Unit> dependents = dependencies.get(u);
if (dependents != null) {
aaCasualtiesWithDependents.addAll(dependents);
}
// we might have new dependents too (ie: paratroopers)
final Collection<Unit> newDependents = m_newDependents.get(u);
if (newDependents != null) {
aaCasualtiesWithDependents.addAll(newDependents);
}
}
}
arrivingUnits = CollectionUtils.difference(units, aaCasualtiesWithDependents);
}
};
final IExecutable postAaFire = new IExecutable() {
private static final long serialVersionUID = 670783657414493643L;
@Override
public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
// if any non enemy territories on route
// or if any enemy units on route the
// battles on (note water could have enemy but its
// not owned)
final GameData data = bridge.getData();
final Predicate<Territory> mustFightThrough = getMustFightThroughMatch(id, data);
final Collection<Unit> arrived = Collections.unmodifiableList(CollectionUtils.intersection(units, arrivingUnits));
// Reset Optional
arrivingUnits = new ArrayList<>();
final Collection<Unit> arrivedCopyForBattles = new ArrayList<>(arrived);
final Map<Unit, Unit> transporting = TransportUtils.mapTransports(route, arrived, transportsToLoad);
// If we have paratrooper land units being carried by air units, they should be dropped off in the last
// territory. This means they
// are still dependent during the middle steps of the route.
final Collection<Unit> dependentOnSomethingTilTheEndOfRoute = new ArrayList<>();
final Collection<Unit> airTransports = CollectionUtils.getMatches(arrived, Matches.unitIsAirTransport());
final Collection<Unit> paratroops = CollectionUtils.getMatches(arrived, Matches.unitIsAirTransportable());
if (!airTransports.isEmpty() && !paratroops.isEmpty()) {
final Map<Unit, Unit> transportingAir = TransportUtils.mapTransportsToLoad(paratroops, airTransports);
dependentOnSomethingTilTheEndOfRoute.addAll(transportingAir.keySet());
}
final Collection<Unit> presentFromStartTilEnd = new ArrayList<>(arrived);
presentFromStartTilEnd.removeAll(dependentOnSomethingTilTheEndOfRoute);
final CompositeChange change = new CompositeChange();
// markFuelCostResourceChange must be done before we load/unload units
change.add(Route.getFuelChanges(units, route, id, data));
markTransportsMovement(arrived, transporting, route);
if (route.anyMatch(mustFightThrough) && arrived.size() != 0) {
boolean bombing = false;
boolean ignoreBattle = false;
// could it be a bombing raid
final Collection<Unit> enemyUnits = route.getEnd().getUnits().getMatches(Matches.enemyUnit(id, data));
final Collection<Unit> enemyTargetsTotal = CollectionUtils.getMatches(enemyUnits, Matches.unitCanBeDamaged().and(Matches.unitIsBeingTransported().negate()));
final boolean canCreateAirBattle = !enemyTargetsTotal.isEmpty() && Properties.getRaidsMayBePreceededByAirBattles(data) && AirBattle.territoryCouldPossiblyHaveAirBattleDefenders(route.getEnd(), id, data, true);
final Predicate<Unit> allBombingRaid = PredicateBuilder.of(Matches.unitIsStrategicBomber()).orIf(canCreateAirBattle, Matches.unitCanEscort()).build();
final boolean allCanBomb = !arrived.isEmpty() && arrived.stream().allMatch(allBombingRaid);
final Collection<Unit> enemyTargets = CollectionUtils.getMatches(enemyTargetsTotal, Matches.unitIsOfTypes(UnitAttachment.getAllowedBombingTargetsIntersection(CollectionUtils.getMatches(arrived, Matches.unitIsStrategicBomber()), data)));
final boolean targetsOrEscort = !enemyTargets.isEmpty() || (!enemyTargetsTotal.isEmpty() && canCreateAirBattle && !arrived.isEmpty() && arrived.stream().allMatch(Matches.unitCanEscort()));
boolean targetedAttack = false;
// if it's all bombers and there's something to bomb
if (allCanBomb && targetsOrEscort && GameStepPropertiesHelper.isCombatMove(data)) {
bombing = getRemotePlayer().shouldBomberBomb(route.getEnd());
// if bombing and there's something to target- ask what to bomb
if (bombing) {
// CompositeMatchOr<Unit> unitsToBeBombed = new CompositeMatchOr<Unit>(Matches.UnitIsFactory,
// Matches.UnitCanBeDamagedButIsNotFactory);
// determine which unit to bomb
final Unit target;
if (enemyTargets.size() > 1 && Properties.getDamageFromBombingDoneToUnitsInsteadOfTerritories(data) && !canCreateAirBattle) {
target = getRemotePlayer().whatShouldBomberBomb(route.getEnd(), enemyTargets, arrived);
} else if (!enemyTargets.isEmpty()) {
target = enemyTargets.iterator().next();
} else {
// in case we are escorts only
target = enemyTargetsTotal.iterator().next();
}
if (target == null) {
bombing = false;
targetedAttack = false;
} else {
targetedAttack = true;
final HashMap<Unit, HashSet<Unit>> targets = new HashMap<>();
targets.put(target, new HashSet<>(arrived));
// createdBattle = true;
getBattleTracker().addBattle(route, arrivedCopyForBattles, bombing, id, MovePerformer.this.bridge, m_currentMove, dependentOnSomethingTilTheEndOfRoute, targets, false);
}
}
}
// Ignore Trn on Trn forces.
if (isIgnoreTransportInMovement(bridge.getData())) {
final boolean allOwnedTransports = !arrived.isEmpty() && arrived.stream().allMatch(Matches.unitIsTransportButNotCombatTransport());
final boolean allEnemyTransports = !enemyUnits.isEmpty() && enemyUnits.stream().allMatch(Matches.unitIsTransportButNotCombatTransport());
// If everybody is a transport, don't create a battle
if (allOwnedTransports && allEnemyTransports) {
ignoreBattle = true;
}
}
if (!ignoreBattle && GameStepPropertiesHelper.isCombatMove(data) && !targetedAttack) {
// createdBattle = true;
if (bombing) {
getBattleTracker().addBombingBattle(route, arrivedCopyForBattles, id, MovePerformer.this.bridge, m_currentMove, dependentOnSomethingTilTheEndOfRoute);
} else {
getBattleTracker().addBattle(route, arrivedCopyForBattles, id, MovePerformer.this.bridge, m_currentMove, dependentOnSomethingTilTheEndOfRoute);
}
}
if (!ignoreBattle && GameStepPropertiesHelper.isNonCombatMove(data, false) && !targetedAttack) {
// difficult if we want these recorded in battle records).
for (final Territory t : route.getMatches(Matches.territoryIsOwnedByPlayerWhosRelationshipTypeCanTakeOverOwnedTerritoryAndPassableAndNotWater(id).and(Matches.territoryIsBlitzable(id, data)))) {
if (Matches.isTerritoryEnemy(id, data).test(t) || Matches.territoryHasEnemyUnits(id, data).test(t)) {
continue;
}
if ((t.equals(route.getEnd()) && !arrivedCopyForBattles.isEmpty() && arrivedCopyForBattles.stream().allMatch(Matches.unitIsAir())) || (!t.equals(route.getEnd()) && !presentFromStartTilEnd.isEmpty() && presentFromStartTilEnd.stream().allMatch(Matches.unitIsAir()))) {
continue;
}
// createdBattle = true;
getBattleTracker().takeOver(t, id, bridge, m_currentMove, arrivedCopyForBattles);
}
}
}
// mark movement
final Change moveChange = markMovementChange(arrived, route, id);
change.add(moveChange);
// actually move the units
if (route.getStart() != null && route.getEnd() != null) {
// ChangeFactory.addUnits(route.getEnd(), arrived);
final Change remove = ChangeFactory.removeUnits(route.getStart(), units);
final Change add = ChangeFactory.addUnits(route.getEnd(), arrived);
change.add(add, remove);
}
MovePerformer.this.bridge.addChange(change);
m_currentMove.addChange(change);
m_currentMove.setDescription(MyFormatter.unitsToTextNoOwner(arrived) + " moved from " + route.getStart().getName() + " to " + route.getEnd().getName());
moveDelegate.updateUndoableMoves(m_currentMove);
}
};
m_executionStack.push(postAaFire);
m_executionStack.push(fireAa);
m_executionStack.push(preAaFire);
m_executionStack.execute(bridge);
}
use of games.strategy.engine.delegate.IDelegateBridge in project triplea by triplea-game.
the class AAInMoveUtil method populateExecutionStack.
private void populateExecutionStack(final Route route, final Collection<Unit> units, final Comparator<Unit> decreasingMovement, final UndoableMove currentMove) {
final List<Unit> targets = new ArrayList<>(units);
// select units with lowest movement first
targets.sort(decreasingMovement);
final List<IExecutable> executables = new ArrayList<>();
for (final Territory location : getTerritoriesWhereAaWillFire(route, units)) {
executables.add(new IExecutable() {
private static final long serialVersionUID = -1545771595683434276L;
@Override
public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
fireAa(location, targets, currentMove);
}
});
}
Collections.reverse(executables);
m_executionStack.push(executables);
}
use of games.strategy.engine.delegate.IDelegateBridge in project triplea by triplea-game.
the class AAInMoveUtil method fireAa.
/**
* Fire the aa units in the given territory, hits are removed from units.
*/
private void fireAa(final Territory territory, final Collection<Unit> units, final UndoableMove currentMove) {
if (units.isEmpty()) {
return;
}
final PlayerID movingPlayer = movingPlayer(units);
final HashMap<String, HashSet<UnitType>> airborneTechTargetsAllowed = TechAbilityAttachment.getAirborneTargettedByAa(movingPlayer, getData());
final List<Unit> defendingAa = territory.getUnits().getMatches(Matches.unitIsAaThatCanFire(units, airborneTechTargetsAllowed, movingPlayer, Matches.unitIsAaForFlyOverOnly(), 1, true, getData()));
// comes ordered alphabetically already
final List<String> aaTypes = UnitAttachment.getAllOfTypeAas(defendingAa);
// stacks are backwards
Collections.reverse(aaTypes);
for (final String currentTypeAa : aaTypes) {
final Collection<Unit> currentPossibleAa = CollectionUtils.getMatches(defendingAa, Matches.unitIsAaOfTypeAa(currentTypeAa));
final Set<UnitType> targetUnitTypesForThisTypeAa = UnitAttachment.get(currentPossibleAa.iterator().next().getType()).getTargetsAa(getData());
final Set<UnitType> airborneTypesTargettedToo = airborneTechTargetsAllowed.get(currentTypeAa);
final Collection<Unit> validTargetedUnitsForThisRoll = CollectionUtils.getMatches(units, Matches.unitIsOfTypes(targetUnitTypesForThisTypeAa).or(Matches.unitIsAirborne().and(Matches.unitIsOfTypes(airborneTypesTargettedToo))));
// once we fire the AA guns, we can't undo
// otherwise you could keep undoing and redoing
// until you got the roll you wanted
currentMove.setCantUndo("Move cannot be undone after " + currentTypeAa + " has fired.");
final DiceRoll[] dice = new DiceRoll[1];
final IExecutable rollDice = new IExecutable() {
private static final long serialVersionUID = 4714364489659654758L;
@Override
public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
// get rid of units already killed, so we don't target them twice
validTargetedUnitsForThisRoll.removeAll(m_casualties);
if (!validTargetedUnitsForThisRoll.isEmpty()) {
dice[0] = DiceRoll.rollAa(validTargetedUnitsForThisRoll, currentPossibleAa, AAInMoveUtil.this.bridge, territory, true);
}
}
};
final IExecutable selectCasualties = new IExecutable() {
private static final long serialVersionUID = -8633263235214834617L;
@Override
public void execute(final ExecutionStack stack, final IDelegateBridge bridge) {
if (!validTargetedUnitsForThisRoll.isEmpty()) {
final int hitCount = dice[0].getHits();
if (hitCount == 0) {
if (currentTypeAa.equals("AA")) {
AAInMoveUtil.this.bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BATTLE_AA_MISS, findDefender(currentPossibleAa, territory));
} else {
AAInMoveUtil.this.bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BATTLE_X_PREFIX + currentTypeAa.toLowerCase() + SoundPath.CLIP_BATTLE_X_MISS, findDefender(currentPossibleAa, territory));
}
getRemotePlayer().reportMessage("No " + currentTypeAa + " hits in " + territory.getName(), "No " + currentTypeAa + " hits in " + territory.getName());
} else {
if (currentTypeAa.equals("AA")) {
AAInMoveUtil.this.bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BATTLE_AA_HIT, findDefender(currentPossibleAa, territory));
} else {
AAInMoveUtil.this.bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BATTLE_X_PREFIX + currentTypeAa.toLowerCase() + SoundPath.CLIP_BATTLE_X_HIT, findDefender(currentPossibleAa, territory));
}
selectCasualties(dice[0], units, validTargetedUnitsForThisRoll, currentPossibleAa, defendingAa, territory, currentTypeAa);
}
}
}
};
// push in reverse order of execution
m_executionStack.push(selectCasualties);
m_executionStack.push(rollDice);
}
}
use of games.strategy.engine.delegate.IDelegateBridge in project triplea by triplea-game.
the class EndTurnDelegate method findNationalObjectiveAndTriggerResources.
/**
* Find the resources generated by national objectives and triggers that are currently met.
*/
public static IntegerMap<Resource> findNationalObjectiveAndTriggerResources(final PlayerID player, final GameData data) {
final IDelegateBridge bridge = new ObjectiveDummyDelegateBridge(data);
// Find and test all the conditions for triggers and national objectives
final Set<TriggerAttachment> triggers = new HashSet<>();
final List<RulesAttachment> objectives = new ArrayList<>();
final HashMap<ICondition, Boolean> testedConditions = testNationalObjectivesAndTriggers(player, data, bridge, triggers, objectives);
// Find triggers value
final IntegerMap<Resource> resources;
final boolean useTriggers = Properties.getTriggers(data);
if (useTriggers && !triggers.isEmpty()) {
final Set<TriggerAttachment> toFireTestedAndSatisfied = new HashSet<>(CollectionUtils.getMatches(triggers, AbstractTriggerAttachment.isSatisfiedMatch(testedConditions)));
resources = TriggerAttachment.findResourceIncome(toFireTestedAndSatisfied, bridge);
} else {
resources = new IntegerMap<>();
}
// Find national objectives value
int pus = 0;
for (final RulesAttachment rule : objectives) {
final int uses = rule.getUses();
if (uses == 0 || !rule.isSatisfied(testedConditions)) {
continue;
}
pus += (rule.getObjectiveValue() * rule.getEachMultiple() * Properties.getPuMultiplier(data));
}
resources.add(data.getResourceList().getResource(Constants.PUS), pus);
return resources;
}
use of games.strategy.engine.delegate.IDelegateBridge in project triplea by triplea-game.
the class DoesNothingAi method endTurn.
@Override
protected void endTurn(final IAbstractForumPosterDelegate endTurnForumPosterDelegate, final GameData data, final PlayerID player) {
// destroy whatever we have
final ResourceCollection resourceCollection = player.getResources();
final Change removeChange = ChangeFactory.removeResourceCollection(player, resourceCollection);
// shameless cheating... (do NOT do this, normally you are never supposed to access the IDelegateBridge from outside
// of a delegate)
final IDelegateBridge bridge = endTurnForumPosterDelegate.getBridge();
// resourceCollection is not yet a valid renderingObject
bridge.getHistoryWriter().startEvent(player.getName() + " removes resources: " + resourceCollection, null);
bridge.addChange(removeChange);
}
Aggregations