Search in sources :

Example 26 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class RevisedTest method testSubAdvance.

@Test
public void testSubAdvance() {
    final UnitType sub = submarine(gameData);
    final UnitAttachment attachment = UnitAttachment.get(sub);
    final PlayerID japanese = japanese(gameData);
    // before the advance, subs defend and attack at 2
    assertEquals(2, attachment.getDefense(japanese));
    assertEquals(2, attachment.getAttack(japanese));
    final ITestDelegateBridge bridge = getDelegateBridge(japanese);
    TechTracker.addAdvance(japanese, bridge, TechAdvance.findAdvance(TechAdvance.TECH_PROPERTY_SUPER_SUBS, gameData, japanese));
    // after tech advance, this is now 3
    assertEquals(2, attachment.getDefense(japanese));
    assertEquals(3, attachment.getAttack(japanese));
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) PlayerID(games.strategy.engine.data.PlayerID) UnitType(games.strategy.engine.data.UnitType) ITestDelegateBridge(games.strategy.engine.data.ITestDelegateBridge) Test(org.junit.jupiter.api.Test)

Example 27 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class LhtrTest method testSubDefenseBonus.

@Test
public void testSubDefenseBonus() {
    final UnitType sub = GameDataTestUtil.submarine(gameData);
    final UnitAttachment attachment = UnitAttachment.get(sub);
    final PlayerID japanese = GameDataTestUtil.japanese(gameData);
    // before the advance, subs defend and attack at 2
    assertEquals(2, attachment.getDefense(japanese));
    assertEquals(2, attachment.getAttack(japanese));
    final ITestDelegateBridge bridge = getDelegateBridge(japanese);
    TechTracker.addAdvance(japanese, bridge, TechAdvance.findAdvance(TechAdvance.TECH_PROPERTY_SUPER_SUBS, gameData, japanese));
    // after tech advance, this is now 3
    assertEquals(3, attachment.getDefense(japanese));
    assertEquals(3, attachment.getAttack(japanese));
    // make sure this only changes for the player with the tech
    final PlayerID americans = GameDataTestUtil.americans(gameData);
    assertEquals(2, attachment.getDefense(americans));
    assertEquals(2, attachment.getAttack(americans));
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) PlayerID(games.strategy.engine.data.PlayerID) UnitType(games.strategy.engine.data.UnitType) ITestDelegateBridge(games.strategy.engine.data.ITestDelegateBridge) Test(org.junit.jupiter.api.Test)

Example 28 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class RocketsFireHelper method fireRocket.

private static void fireRocket(final PlayerID player, final Territory attackedTerritory, final IDelegateBridge bridge, final Territory attackFrom) {
    final GameData data = bridge.getData();
    final PlayerID attacked = attackedTerritory.getOwner();
    final Resource pus = data.getResourceList().getResource(Constants.PUS);
    final boolean damageFromBombingDoneToUnits = isDamageFromBombingDoneToUnitsInsteadOfTerritories(data);
    // unit damage vs territory damage
    final Collection<Unit> enemyUnits = attackedTerritory.getUnits().getMatches(Matches.enemyUnit(player, data).and(Matches.unitIsBeingTransported().negate()));
    final Collection<Unit> enemyTargetsTotal = CollectionUtils.getMatches(enemyUnits, Matches.unitIsAtMaxDamageOrNotCanBeDamaged(attackedTerritory).negate());
    final Collection<Unit> rockets;
    // attackFrom could be null if WW2V1
    if (attackFrom == null) {
        rockets = null;
    } else {
        rockets = new ArrayList<>(CollectionUtils.getMatches(attackFrom.getUnits().getUnits(), rocketMatch(player)));
    }
    final int numberOfAttacks = (rockets == null ? 1 : Math.min(TechAbilityAttachment.getRocketNumberPerTerritory(player, data), TechAbilityAttachment.getRocketDiceNumber(rockets, data)));
    if (numberOfAttacks <= 0) {
        return;
    }
    final Collection<Unit> targets = new ArrayList<>();
    if (damageFromBombingDoneToUnits) {
        // TODO: rockets needs to be completely redone to allow for multiple rockets to fire at different targets, etc
        // etc.
        final HashSet<UnitType> legalTargetsForTheseRockets = new HashSet<>();
        if (rockets == null) {
            legalTargetsForTheseRockets.addAll(data.getUnitTypeList().getAllUnitTypes());
        } else {
            // a hack for now, we let the rockets fire at anyone who could be targetted by any rocket
            for (final Unit r : rockets) {
                legalTargetsForTheseRockets.addAll(UnitAttachment.get(r.getType()).getBombingTargets(data));
            }
        }
        final Collection<Unit> enemyTargets = CollectionUtils.getMatches(enemyTargetsTotal, Matches.unitIsOfTypes(legalTargetsForTheseRockets));
        if (enemyTargets.isEmpty()) {
            // TODO: this sucks
            return;
        }
        Unit target = null;
        if (enemyTargets.size() == 1) {
            target = enemyTargets.iterator().next();
        } else {
            while (target == null) {
                final ITripleAPlayer iplayer = (ITripleAPlayer) bridge.getRemotePlayer(player);
                target = iplayer.whatShouldBomberBomb(attackedTerritory, enemyTargets, rockets);
            }
        }
        if (target == null) {
            throw new IllegalStateException("No Targets in " + attackedTerritory.getName());
        }
        targets.add(target);
    }
    final boolean doNotUseBombingBonus = !Properties.getUseBombingMaxDiceSidesAndBonus(data) || rockets == null;
    int cost = 0;
    final String transcript;
    if (!Properties.getLowLuckDamageOnly(data)) {
        if (doNotUseBombingBonus || rockets == null) {
            // no low luck, and no bonus, so just roll based on the map's dice sides
            final int[] rolls = bridge.getRandom(data.getDiceSides(), numberOfAttacks, player, DiceType.BOMBING, "Rocket fired by " + player.getName() + " at " + attacked.getName());
            for (final int r : rolls) {
                // we are zero based
                cost += r + 1;
            }
            transcript = "Rockets " + (attackFrom == null ? "" : "in " + attackFrom.getName()) + " roll: " + MyFormatter.asDice(rolls);
        } else {
            // we must use bombing bonus
            int highestMaxDice = 0;
            int highestBonus = 0;
            final int diceSides = data.getDiceSides();
            for (final Unit u : rockets) {
                final UnitAttachment ua = UnitAttachment.get(u.getType());
                int maxDice = ua.getBombingMaxDieSides();
                final int bonus = ua.getBombingBonus();
                // map, and zero for the bonus.
                if (maxDice < 0) {
                    maxDice = diceSides;
                }
                // we only roll once for rockets, so if there are other rockets here we just roll for the best rocket
                if ((bonus + ((maxDice + 1) / 2)) > (highestBonus + ((highestMaxDice + 1) / 2))) {
                    highestMaxDice = maxDice;
                    highestBonus = bonus;
                }
            }
            // now we roll, or don't if there is nothing to roll.
            if (highestMaxDice > 0) {
                final int[] rolls = bridge.getRandom(highestMaxDice, numberOfAttacks, player, DiceType.BOMBING, "Rocket fired by " + player.getName() + " at " + attacked.getName());
                for (int i = 0; i < rolls.length; i++) {
                    final int r = Math.max(-1, rolls[i] + highestBonus);
                    rolls[i] = r;
                    // we are zero based
                    cost += r + 1;
                }
                transcript = "Rockets " + (attackFrom == null ? "" : "in " + attackFrom.getName()) + " roll: " + MyFormatter.asDice(rolls);
            } else {
                cost = highestBonus * numberOfAttacks;
                transcript = "Rockets " + (attackFrom == null ? "" : "in " + attackFrom.getName()) + " do " + highestBonus + " damage for each rocket";
            }
        }
    } else {
        if (doNotUseBombingBonus || rockets == null) {
            // no bonus, so just roll based on the map's dice sides, but modify for LL
            final int maxDice = (data.getDiceSides() + 1) / 3;
            final int bonus = (data.getDiceSides() + 1) / 3;
            final int[] rolls = bridge.getRandom(maxDice, numberOfAttacks, player, DiceType.BOMBING, "Rocket fired by " + player.getName() + " at " + attacked.getName());
            for (int i = 0; i < rolls.length; i++) {
                final int r = rolls[i] + bonus;
                rolls[i] = r;
                // we are zero based
                cost += r + 1;
            }
            transcript = "Rockets " + (attackFrom == null ? "" : "in " + attackFrom.getName()) + " roll: " + MyFormatter.asDice(rolls);
        } else {
            int highestMaxDice = 0;
            int highestBonus = 0;
            final int diceSides = data.getDiceSides();
            for (final Unit u : rockets) {
                final UnitAttachment ua = UnitAttachment.get(u.getType());
                int maxDice = ua.getBombingMaxDieSides();
                int bonus = ua.getBombingBonus();
                // map, and zero for the bonus.
                if (maxDice < 0 || doNotUseBombingBonus) {
                    maxDice = diceSides;
                }
                if (doNotUseBombingBonus) {
                    bonus = 0;
                }
                // luck by 2/3.
                if (maxDice >= 5) {
                    bonus += (maxDice + 1) / 3;
                    maxDice = (maxDice + 1) / 3;
                }
                // we only roll once for rockets, so if there are other rockets here we just roll for the best rocket
                if ((bonus + ((maxDice + 1) / 2)) > (highestBonus + ((highestMaxDice + 1) / 2))) {
                    highestMaxDice = maxDice;
                    highestBonus = bonus;
                }
            }
            // now we roll, or don't if there is nothing to roll.
            if (highestMaxDice > 0) {
                final int[] rolls = bridge.getRandom(highestMaxDice, numberOfAttacks, player, DiceType.BOMBING, "Rocket fired by " + player.getName() + " at " + attacked.getName());
                for (int i = 0; i < rolls.length; i++) {
                    final int r = Math.max(-1, rolls[i] + highestBonus);
                    rolls[i] = r;
                    // we are zero based
                    cost += r + 1;
                }
                transcript = "Rockets " + (attackFrom == null ? "" : "in " + attackFrom.getName()) + " roll: " + MyFormatter.asDice(rolls);
            } else {
                cost = highestBonus * numberOfAttacks;
                transcript = "Rockets " + (attackFrom == null ? "" : "in " + attackFrom.getName()) + " do " + highestBonus + " damage for each rocket";
            }
        }
    }
    int territoryProduction = TerritoryAttachment.getProduction(attackedTerritory);
    if (damageFromBombingDoneToUnits && !targets.isEmpty()) {
        // we are doing damage to 'target', not to the territory
        final Unit target = targets.iterator().next();
        // UnitAttachment ua = UnitAttachment.get(target.getType());
        final TripleAUnit taUnit = (TripleAUnit) target;
        final int damageLimit = taUnit.getHowMuchMoreDamageCanThisUnitTake(target, attackedTerritory);
        cost = Math.max(0, Math.min(cost, damageLimit));
        final int totalDamage = taUnit.getUnitDamage() + cost;
        // Record production lost
        // DelegateFinder.moveDelegate(data).PUsLost(attackedTerritory, cost);
        // apply the hits to the targets
        final IntegerMap<Unit> damageMap = new IntegerMap<>();
        damageMap.put(target, totalDamage);
        bridge.addChange(ChangeFactory.bombingUnitDamage(damageMap));
    // attackedTerritory.notifyChanged();
    // in WW2V2, limit rocket attack cost to production value of factory.
    } else if (isWW2V2(data) || isLimitRocketDamageToProduction(data)) {
        // If we are limiting total PUs lost then take that into account
        if (isPuCap(data) || isLimitRocketDamagePerTurn(data)) {
            final int alreadyLost = DelegateFinder.moveDelegate(data).pusAlreadyLost(attackedTerritory);
            territoryProduction -= alreadyLost;
            territoryProduction = Math.max(0, territoryProduction);
        }
        if (cost > territoryProduction) {
            cost = territoryProduction;
        }
    }
    // Record the PUs lost
    DelegateFinder.moveDelegate(data).pusLost(attackedTerritory, cost);
    if (damageFromBombingDoneToUnits && !targets.isEmpty()) {
        getRemote(bridge).reportMessage("Rocket attack in " + attackedTerritory.getName() + " does " + cost + " damage to " + targets.iterator().next(), "Rocket attack in " + attackedTerritory.getName() + " does " + cost + " damage to " + targets.iterator().next());
        bridge.getHistoryWriter().startEvent("Rocket attack in " + attackedTerritory.getName() + " does " + cost + " damage to " + targets.iterator().next());
    } else {
        cost *= Properties.getPuMultiplier(data);
        getRemote(bridge).reportMessage("Rocket attack in " + attackedTerritory.getName() + " costs:" + cost, "Rocket attack in " + attackedTerritory.getName() + " costs:" + cost);
        // Trying to remove more PUs than the victim has is A Bad Thing[tm]
        final int availForRemoval = attacked.getResources().getQuantity(pus);
        if (cost > availForRemoval) {
            cost = availForRemoval;
        }
        final String transcriptText = attacked.getName() + " lost " + cost + " PUs to rocket attack by " + player.getName();
        bridge.getHistoryWriter().startEvent(transcriptText);
        final Change rocketCharge = ChangeFactory.changeResourcesChange(attacked, pus, -cost);
        bridge.addChange(rocketCharge);
    }
    bridge.getHistoryWriter().addChildToEvent(transcript, rockets == null ? null : new ArrayList<>(rockets));
    // this is null in WW2V1
    if (attackFrom != null) {
        if (rockets != null && !rockets.isEmpty()) {
            // TODO: only a certain number fired...
            final Change change = ChangeFactory.markNoMovementChange(Collections.singleton(rockets.iterator().next()));
            bridge.addChange(change);
        } else {
            throw new IllegalStateException("No rockets?" + attackFrom.getUnits().getUnits());
        }
    }
    // kill any units that can die if they have reached max damage (veqryn)
    if (targets.stream().anyMatch(Matches.unitCanDieFromReachingMaxDamage())) {
        final List<Unit> unitsCanDie = CollectionUtils.getMatches(targets, Matches.unitCanDieFromReachingMaxDamage());
        unitsCanDie.retainAll(CollectionUtils.getMatches(unitsCanDie, Matches.unitIsAtMaxDamageOrNotCanBeDamaged(attackedTerritory)));
        if (!unitsCanDie.isEmpty()) {
            final Change removeDead = ChangeFactory.removeUnits(attackedTerritory, unitsCanDie);
            final String transcriptText = MyFormatter.unitsToText(unitsCanDie) + " lost in " + attackedTerritory.getName();
            bridge.getHistoryWriter().addChildToEvent(transcriptText, unitsCanDie);
            bridge.addChange(removeDead);
        }
    }
    // play a sound
    if (cost > 0) {
        bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BOMBING_ROCKET, player);
    }
}
Also used : IntegerMap(games.strategy.util.IntegerMap) PlayerID(games.strategy.engine.data.PlayerID) GameData(games.strategy.engine.data.GameData) Resource(games.strategy.engine.data.Resource) ArrayList(java.util.ArrayList) Change(games.strategy.engine.data.Change) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) TripleAUnit(games.strategy.triplea.TripleAUnit) ITripleAPlayer(games.strategy.triplea.player.ITripleAPlayer) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) UnitType(games.strategy.engine.data.UnitType) HashSet(java.util.HashSet)

Example 29 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class PlayerUnitsPanel method init.

/**
 * Sets up components to an initial state.
 */
public void init(final PlayerID id, final List<Unit> units, final boolean land) {
    isLand = land;
    categories = new ArrayList<>(categorize(id, units));
    categories.sort(Comparator.comparing(UnitCategory::getType, (ut1, ut2) -> {
        final UnitAttachment u1 = UnitAttachment.get(ut1);
        final UnitAttachment u2 = UnitAttachment.get(ut2);
        // For land battles, sort by land, air, can't combat move (AA), bombarding
        if (land) {
            if (u1.getIsSea() != u2.getIsSea()) {
                return u1.getIsSea() ? 1 : -1;
            }
            final boolean u1CanNotCombatMove = Matches.unitTypeCanNotMoveDuringCombatMove().test(ut1) || !Matches.unitTypeCanMove(id).test(ut1);
            final boolean u2CanNotCombatMove = Matches.unitTypeCanNotMoveDuringCombatMove().test(ut2) || !Matches.unitTypeCanMove(id).test(ut2);
            if (u1CanNotCombatMove != u2CanNotCombatMove) {
                return u1CanNotCombatMove ? 1 : -1;
            }
            if (u1.getIsAir() != u2.getIsAir()) {
                return u1.getIsAir() ? 1 : -1;
            }
        } else {
            if (u1.getIsSea() != u2.getIsSea()) {
                return u1.getIsSea() ? -1 : 1;
            }
        }
        return u1.getName().compareTo(u2.getName());
    }));
    removeAll();
    final Predicate<UnitType> predicate;
    if (land) {
        if (defender) {
            predicate = Matches.unitTypeIsNotSea();
        } else {
            predicate = Matches.unitTypeIsNotSea().or(Matches.unitTypeCanBombard(id));
        }
    } else {
        predicate = Matches.unitTypeIsSeaOrAir();
    }
    final IntegerMap<UnitType> costs;
    try {
        data.acquireReadLock();
        costs = TuvUtils.getCostsForTuv(id, data);
    } finally {
        data.releaseReadLock();
    }
    for (final UnitCategory category : categories) {
        if (predicate.test(category.getType())) {
            final UnitPanel upanel = new UnitPanel(uiContext, category, costs);
            upanel.addChangeListener(this::notifyListeners);
            add(upanel);
        }
    }
    // TODO: probably do not need to do this much revalidation.
    invalidate();
    validate();
    revalidate();
    getParent().invalidate();
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) NamedAttachable(games.strategy.engine.data.NamedAttachable) TuvUtils(games.strategy.triplea.util.TuvUtils) UnitSeperator(games.strategy.triplea.util.UnitSeperator) ArrayList(java.util.ArrayList) UnitCategory(games.strategy.triplea.util.UnitCategory) UiContext(games.strategy.triplea.ui.UiContext) UnitType(games.strategy.engine.data.UnitType) LinkedHashSet(java.util.LinkedHashSet) BoxLayout(javax.swing.BoxLayout) CollectionUtils(games.strategy.util.CollectionUtils) IntegerMap(games.strategy.util.IntegerMap) Unit(games.strategy.engine.data.Unit) Predicate(java.util.function.Predicate) Collection(java.util.Collection) Set(java.util.Set) Territory(games.strategy.engine.data.Territory) Component(java.awt.Component) GameData(games.strategy.engine.data.GameData) List(java.util.List) PlayerID(games.strategy.engine.data.PlayerID) ProductionFrontier(games.strategy.engine.data.ProductionFrontier) Matches(games.strategy.triplea.delegate.Matches) ProductionRule(games.strategy.engine.data.ProductionRule) Comparator(java.util.Comparator) JPanel(javax.swing.JPanel) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) UnitType(games.strategy.engine.data.UnitType) UnitCategory(games.strategy.triplea.util.UnitCategory)

Example 30 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class TransportTracker method getAvailableCapacity.

public static int getAvailableCapacity(final Unit unit) {
    final UnitAttachment ua = UnitAttachment.get(unit.getType());
    // Check if there are transports available, also check for destroyer capacity (Tokyo Express)
    if (ua.getTransportCapacity() == -1 || (unit.getData().getProperties().get(Constants.PACIFIC_THEATER, false) && ua.getIsDestroyer() && !unit.getOwner().getName().equals(Constants.PLAYER_NAME_JAPANESE))) {
        return 0;
    }
    final int capacity = ua.getTransportCapacity();
    final int used = getCost(transporting(unit));
    final int unloaded = getCost(unloaded(unit));
    return capacity - used - unloaded;
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment)

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