use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class BattleCalculator method getTotalHitpointsLeft.
public static int getTotalHitpointsLeft(final Collection<Unit> units) {
if (units == null || units.isEmpty()) {
return 0;
}
int totalHitPoints = 0;
for (final Unit u : units) {
final UnitAttachment ua = UnitAttachment.get(u.getType());
totalHitPoints += ua.getHitPoints();
totalHitPoints -= u.getHits();
}
return totalHitPoints;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class BattleCalculator method selectCasualties.
/**
* @param battleId
* may be null if we are not in a battle (eg, if this is an aa fire due to moving).
*/
public static CasualtyDetails selectCasualties(final String step, final PlayerID player, final Collection<Unit> targetsToPickFrom, final Collection<Unit> friendlyUnits, final PlayerID enemyPlayer, final Collection<Unit> enemyUnits, final boolean amphibious, final Collection<Unit> amphibiousLandAttackers, final Territory battlesite, final Collection<TerritoryEffect> territoryEffects, final IDelegateBridge bridge, final String text, final DiceRoll dice, final boolean defending, final GUID battleId, final boolean headLess, final int extraHits, final boolean allowMultipleHitsPerUnit) {
if (targetsToPickFrom.isEmpty()) {
return new CasualtyDetails();
}
if (!friendlyUnits.containsAll(targetsToPickFrom)) {
throw new IllegalStateException("friendlyUnits should but does not contain all units from targetsToPickFrom");
}
final GameData data = bridge.getData();
final boolean isEditMode = BaseEditDelegate.getEditMode(data);
final ITripleAPlayer tripleaPlayer = player.isNull() ? new WeakAi(player.getName(), TripleA.WEAK_COMPUTER_PLAYER_TYPE) : (ITripleAPlayer) bridge.getRemotePlayer(player);
final Map<Unit, Collection<Unit>> dependents = headLess ? Collections.emptyMap() : getDependents(targetsToPickFrom);
if (isEditMode && !headLess) {
final CasualtyDetails editSelection = tripleaPlayer.selectCasualties(targetsToPickFrom, dependents, 0, text, dice, player, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, new CasualtyList(), battleId, battlesite, allowMultipleHitsPerUnit);
final List<Unit> killed = editSelection.getKilled();
// if partial retreat is possible, kill amphibious units first
if (isPartialAmphibiousRetreat(data)) {
killAmphibiousFirst(killed, targetsToPickFrom);
}
return editSelection;
}
if (dice.getHits() == 0) {
return new CasualtyDetails(Collections.emptyList(), Collections.emptyList(), true);
}
int hitsRemaining = dice.getHits();
if (isTransportCasualtiesRestricted(data)) {
hitsRemaining = extraHits;
}
if (!isEditMode && allTargetsOneTypeOneHitPoint(targetsToPickFrom, dependents)) {
final List<Unit> killed = new ArrayList<>();
final Iterator<Unit> iter = targetsToPickFrom.iterator();
for (int i = 0; i < hitsRemaining; i++) {
if (i >= targetsToPickFrom.size()) {
break;
}
killed.add(iter.next());
}
return new CasualtyDetails(killed, Collections.emptyList(), true);
}
// Create production cost map, Maybe should do this elsewhere, but in case prices change, we do it here.
final IntegerMap<UnitType> costs = TuvUtils.getCostsForTuv(player, data);
final Tuple<CasualtyList, List<Unit>> defaultCasualtiesAndSortedTargets = getDefaultCasualties(targetsToPickFrom, hitsRemaining, defending, player, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, costs, territoryEffects, data, allowMultipleHitsPerUnit, true);
final CasualtyList defaultCasualties = defaultCasualtiesAndSortedTargets.getFirst();
final List<Unit> sortedTargetsToPickFrom = defaultCasualtiesAndSortedTargets.getSecond();
if (sortedTargetsToPickFrom.size() != targetsToPickFrom.size() || !targetsToPickFrom.containsAll(sortedTargetsToPickFrom) || !sortedTargetsToPickFrom.containsAll(targetsToPickFrom)) {
throw new IllegalStateException("sortedTargetsToPickFrom must contain the same units as targetsToPickFrom list");
}
final int totalHitpoints = (allowMultipleHitsPerUnit ? getTotalHitpointsLeft(sortedTargetsToPickFrom) : sortedTargetsToPickFrom.size());
final CasualtyDetails casualtySelection;
if (hitsRemaining >= totalHitpoints) {
casualtySelection = new CasualtyDetails(defaultCasualties, true);
} else {
casualtySelection = tripleaPlayer.selectCasualties(sortedTargetsToPickFrom, dependents, hitsRemaining, text, dice, player, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, defaultCasualties, battleId, battlesite, allowMultipleHitsPerUnit);
}
List<Unit> killed = casualtySelection.getKilled();
// if partial retreat is possible, kill amphibious units first
if (isPartialAmphibiousRetreat(data)) {
killed = killAmphibiousFirst(killed, sortedTargetsToPickFrom);
}
final List<Unit> damaged = casualtySelection.getDamaged();
int numhits = killed.size();
if (!allowMultipleHitsPerUnit) {
damaged.clear();
} else {
for (final Unit unit : killed) {
final UnitAttachment ua = UnitAttachment.get(unit.getType());
final int damageToUnit = Collections.frequency(damaged, unit);
// allowed damage
numhits += Math.max(0, Math.min(damageToUnit, (ua.getHitPoints() - (1 + unit.getHits()))));
// remove from damaged list, since they will die
damaged.removeIf(unit::equals);
}
}
// check right number
if (!isEditMode && !(numhits + damaged.size() == (hitsRemaining > totalHitpoints ? totalHitpoints : hitsRemaining))) {
tripleaPlayer.reportError("Wrong number of casualties selected");
if (headLess) {
System.err.println("Possible Infinite Loop: Wrong number of casualties selected: number of hits on units " + (numhits + damaged.size()) + " != number of hits to take " + (hitsRemaining > totalHitpoints ? totalHitpoints : hitsRemaining) + ", for " + casualtySelection.toString());
}
return selectCasualties(step, player, sortedTargetsToPickFrom, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, territoryEffects, bridge, text, dice, defending, battleId, headLess, extraHits, allowMultipleHitsPerUnit);
}
// check we have enough of each type
if (!sortedTargetsToPickFrom.containsAll(killed) || !sortedTargetsToPickFrom.containsAll(damaged)) {
tripleaPlayer.reportError("Cannot remove enough units of those types");
if (headLess) {
System.err.println("Possible Infinite Loop: Cannot remove enough units of those types: targets " + MyFormatter.unitsToTextNoOwner(sortedTargetsToPickFrom) + ", for " + casualtySelection.toString());
}
return selectCasualties(step, player, sortedTargetsToPickFrom, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, territoryEffects, bridge, text, dice, defending, battleId, headLess, extraHits, allowMultipleHitsPerUnit);
}
return casualtySelection;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class BattleCalculator method getUnitPowerForSorting.
/**
* This returns the exact Power that a unit has according to what DiceRoll.rollDiceLowLuck() would give it.
* As such, it needs to exactly match DiceRoll, otherwise this method will become useless.
* It does NOT take into account SUPPORT.
* It DOES take into account ROLLS.
* It needs to be updated to take into account isMarine.
*/
public static int getUnitPowerForSorting(final Unit current, final boolean defending, final GameData data, final Collection<TerritoryEffect> territoryEffects) {
final boolean lhtrBombers = Properties.getLhtrHeavyBombers(data);
final UnitAttachment ua = UnitAttachment.get(current.getType());
final int rolls = (defending) ? ua.getDefenseRolls(current.getOwner()) : ua.getAttackRolls(current.getOwner());
int strengthWithoutSupport = 0;
// lhtr heavy bombers take best of n dice for both attack and defense
if (rolls > 1 && (lhtrBombers || ua.getChooseBestRoll())) {
strengthWithoutSupport = (defending) ? ua.getDefense(current.getOwner()) : ua.getAttack(current.getOwner());
strengthWithoutSupport += TerritoryEffectHelper.getTerritoryCombatBonus(current.getType(), territoryEffects, defending);
// just add one like LL if we are LHTR bombers
strengthWithoutSupport = Math.min(Math.max(strengthWithoutSupport + 1, 0), data.getDiceSides());
} else {
for (int i = 0; i < rolls; i++) {
final int tempStrength = (defending) ? ua.getDefense(current.getOwner()) : ua.getAttack(current.getOwner());
strengthWithoutSupport += TerritoryEffectHelper.getTerritoryCombatBonus(current.getType(), territoryEffects, defending);
strengthWithoutSupport += Math.min(Math.max(tempStrength, 0), data.getDiceSides());
}
}
return strengthWithoutSupport;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class BattleCalculator method getRolls.
private static int getRolls(final Unit unit, final PlayerID id, final boolean defend, final boolean bombing, final Set<List<UnitSupportAttachment>> supportRulesFriendly, final IntegerMap<UnitSupportAttachment> supportLeftFriendlyCopy, final Set<List<UnitSupportAttachment>> supportRulesEnemy, final IntegerMap<UnitSupportAttachment> supportLeftEnemyCopy, final Collection<TerritoryEffect> territoryEffects) {
final UnitAttachment unitAttachment = UnitAttachment.get(unit.getType());
int rolls;
if (defend) {
rolls = unitAttachment.getDefenseRolls(id);
} else {
rolls = unitAttachment.getAttackRolls(id);
}
final Map<UnitSupportAttachment, LinkedIntegerMap<Unit>> dummyEmptyMap = new HashMap<>();
rolls += DiceRoll.getSupport(unit, supportRulesFriendly, supportLeftFriendlyCopy, dummyEmptyMap, null, false, true);
rolls += DiceRoll.getSupport(unit, supportRulesEnemy, supportLeftEnemyCopy, dummyEmptyMap, null, false, true);
rolls = Math.max(0, rolls);
// if we are strategic bombing, we do not care what the strength of the unit is...
if (bombing) {
return rolls;
}
int strength;
if (defend) {
strength = unitAttachment.getDefense(unit.getOwner());
} else {
strength = unitAttachment.getAttack(unit.getOwner());
}
// TODO: we should add in isMarine bonus too...
strength += DiceRoll.getSupport(unit, supportRulesFriendly, supportLeftFriendlyCopy, dummyEmptyMap, null, true, false);
strength += DiceRoll.getSupport(unit, supportRulesEnemy, supportLeftEnemyCopy, dummyEmptyMap, null, true, false);
strength += TerritoryEffectHelper.getTerritoryCombatBonus(unit.getType(), territoryEffects, defend);
if (strength <= 0) {
rolls = 0;
}
return rolls;
}
use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.
the class BattleCalculator method getDefaultCasualties.
/**
* A unit with two hitpoints will be listed twice if they will die. The first time they are listed it is as damaged.
* The second time they
* are listed, it is dead.
*/
private static Tuple<CasualtyList, List<Unit>> getDefaultCasualties(final Collection<Unit> targetsToPickFrom, final int hits, final boolean defending, final PlayerID player, final Collection<Unit> enemyUnits, final boolean amphibious, final Collection<Unit> amphibiousLandAttackers, final Territory battlesite, final IntegerMap<UnitType> costs, final Collection<TerritoryEffect> territoryEffects, final GameData data, final boolean allowMultipleHitsPerUnit, final boolean bonus) {
final CasualtyList defaultCasualtySelection = new CasualtyList();
// Sort units by power and cost in ascending order
final List<Unit> sorted = sortUnitsForCasualtiesWithSupport(targetsToPickFrom, defending, player, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, costs, territoryEffects, data, bonus);
// Remove two hit bb's selecting them first for default casualties
int numSelectedCasualties = 0;
if (allowMultipleHitsPerUnit) {
for (final Unit unit : sorted) {
// Stop if we have already selected as many hits as there are targets
if (numSelectedCasualties >= hits) {
return Tuple.of(defaultCasualtySelection, sorted);
}
final UnitAttachment ua = UnitAttachment.get(unit.getType());
final int extraHitPoints = Math.min((hits - numSelectedCasualties), (ua.getHitPoints() - (1 + unit.getHits())));
for (int i = 0; i < extraHitPoints; i++) {
numSelectedCasualties++;
defaultCasualtySelection.addToDamaged(unit);
}
}
}
// Select units
for (final Unit unit : sorted) {
// Stop if we have already selected as many hits as there are targets
if (numSelectedCasualties >= hits) {
return Tuple.of(defaultCasualtySelection, sorted);
}
defaultCasualtySelection.addToKilled(unit);
numSelectedCasualties++;
}
return Tuple.of(defaultCasualtySelection, sorted);
}
Aggregations