Search in sources :

Example 1 with UnitAttachment

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;
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Unit(games.strategy.engine.data.Unit)

Example 2 with UnitAttachment

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;
}
Also used : GameData(games.strategy.engine.data.GameData) ArrayList(java.util.ArrayList) Unit(games.strategy.engine.data.Unit) ITripleAPlayer(games.strategy.triplea.player.ITripleAPlayer) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) WeakAi(games.strategy.triplea.ai.weak.WeakAi) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) UnitType(games.strategy.engine.data.UnitType) Collection(java.util.Collection) CasualtyDetails(games.strategy.triplea.delegate.dataObjects.CasualtyDetails) ArrayList(java.util.ArrayList) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) List(java.util.List)

Example 3 with UnitAttachment

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;
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment)

Example 4 with UnitAttachment

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;
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) LinkedIntegerMap(games.strategy.util.LinkedIntegerMap) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) UnitSupportAttachment(games.strategy.triplea.attachments.UnitSupportAttachment)

Example 5 with UnitAttachment

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);
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) Unit(games.strategy.engine.data.Unit)

Aggregations

UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)60 Unit (games.strategy.engine.data.Unit)45 ArrayList (java.util.ArrayList)25 TripleAUnit (games.strategy.triplea.TripleAUnit)23 UnitType (games.strategy.engine.data.UnitType)20 GameData (games.strategy.engine.data.GameData)19 Territory (games.strategy.engine.data.Territory)19 PlayerID (games.strategy.engine.data.PlayerID)12 CompositeChange (games.strategy.engine.data.CompositeChange)8 TerritoryAttachment (games.strategy.triplea.attachments.TerritoryAttachment)7 IntegerMap (games.strategy.util.IntegerMap)6 Collection (java.util.Collection)6 Set (java.util.Set)6 Change (games.strategy.engine.data.Change)5 Resource (games.strategy.engine.data.Resource)5 Tuple (games.strategy.util.Tuple)5 HashSet (java.util.HashSet)5 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)4 Route (games.strategy.engine.data.Route)4 List (java.util.List)4