use of games.strategy.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class BattleDelegate method doKamikazeSuicideAttacks.
/**
* KamikazeSuicideAttacks are attacks that are made during an Opponent's turn, using Resources that you own that have
* been designated.
* The resources are designated in PlayerAttachment, and hold information like the attack power of the resource.
* KamikazeSuicideAttacks are done in any territory that is a kamikazeZone, and the attacks are done by the original
* owner of that
* territory.
* The user has the option not to do any attacks, and they make target any number of units with any number of resource
* tokens.
* The units are then attacked individually by each resource token (meaning that casualties do not get selected
* because the attacks are
* targeted).
* The enemies of current player should decide all their attacks before the attacks are rolled.
*/
private void doKamikazeSuicideAttacks() {
final GameData data = getData();
if (!Properties.getUseKamikazeSuicideAttacks(data)) {
return;
}
// the current player is not the one who is doing these attacks, it is the all the enemies of this player who will
// do attacks
final Collection<PlayerID> enemies = CollectionUtils.getMatches(data.getPlayerList().getPlayers(), Matches.isAtWar(player, data));
if (enemies.isEmpty()) {
return;
}
final Predicate<Unit> canBeAttackedDefault = Matches.unitIsOwnedBy(player).and(Matches.unitIsSea()).and(Matches.unitIsNotTransportButCouldBeCombatTransport()).and(Matches.unitIsNotSub());
final boolean onlyWhereThereAreBattlesOrAmphibious = Properties.getKamikazeSuicideAttacksOnlyWhereBattlesAre(data);
final Collection<Territory> pendingBattles = battleTracker.getPendingBattleSites(false);
// create a list of all kamikaze zones, listed by enemy
final Map<PlayerID, Collection<Territory>> kamikazeZonesByEnemy = new HashMap<>();
for (final Territory t : data.getMap().getTerritories()) {
final TerritoryAttachment ta = TerritoryAttachment.get(t);
if (ta == null || !ta.getKamikazeZone()) {
continue;
}
final PlayerID owner = !Properties.getKamikazeSuicideAttacksDoneByCurrentTerritoryOwner(data) ? ta.getOriginalOwner() : t.getOwner();
if (owner == null) {
continue;
}
if (enemies.contains(owner)) {
if (t.getUnits().getUnits().stream().noneMatch(Matches.unitIsOwnedBy(player))) {
continue;
}
if (onlyWhereThereAreBattlesOrAmphibious) {
// if no battle or amphibious from here, ignore it
if (!pendingBattles.contains(t)) {
if (!Matches.territoryIsWater().test(t)) {
continue;
}
boolean amphib = false;
final Collection<Territory> landNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsLand());
for (final Territory neighbor : landNeighbors) {
final IBattle battle = battleTracker.getPendingBattle(neighbor, false, BattleType.NORMAL);
if (battle == null) {
final Map<Territory, Collection<Unit>> whereFrom = battleTracker.getFinishedBattlesUnitAttackFromMap().get(neighbor);
if (whereFrom != null && whereFrom.containsKey(t)) {
amphib = true;
break;
}
continue;
}
if (battle.isAmphibious() && ((battle instanceof MustFightBattle && ((MustFightBattle) battle).getAmphibiousAttackTerritories().contains(t)) || (battle instanceof NonFightingBattle && ((NonFightingBattle) battle).getAmphibiousAttackTerritories().contains(t)))) {
amphib = true;
break;
}
}
if (!amphib) {
continue;
}
}
}
final Collection<Territory> currentTerrs = kamikazeZonesByEnemy.getOrDefault(owner, new ArrayList<>());
currentTerrs.add(t);
kamikazeZonesByEnemy.put(owner, currentTerrs);
}
}
if (kamikazeZonesByEnemy.isEmpty()) {
return;
}
for (final Entry<PlayerID, Collection<Territory>> entry : kamikazeZonesByEnemy.entrySet()) {
final PlayerID currentEnemy = entry.getKey();
final PlayerAttachment pa = PlayerAttachment.get(currentEnemy);
if (pa == null) {
continue;
}
Predicate<Unit> canBeAttacked = canBeAttackedDefault;
final Set<UnitType> suicideAttackTargets = pa.getSuicideAttackTargets();
if (suicideAttackTargets != null) {
canBeAttacked = Matches.unitIsOwnedBy(player).and(Matches.unitIsOfTypes(suicideAttackTargets));
}
// See if the player has any attack tokens
final IntegerMap<Resource> resourcesAndAttackValues = pa.getSuicideAttackResources();
if (resourcesAndAttackValues.size() <= 0) {
continue;
}
final IntegerMap<Resource> playerResourceCollection = currentEnemy.getResources().getResourcesCopy();
final IntegerMap<Resource> attackTokens = new IntegerMap<>();
for (final Resource possible : resourcesAndAttackValues.keySet()) {
final int amount = playerResourceCollection.getInt(possible);
if (amount > 0) {
attackTokens.put(possible, amount);
}
}
if (attackTokens.size() <= 0) {
continue;
}
// now let the enemy decide if they will do attacks
final Collection<Territory> kamikazeZones = entry.getValue();
final HashMap<Territory, Collection<Unit>> possibleUnitsToAttack = new HashMap<>();
for (final Territory t : kamikazeZones) {
final List<Unit> validTargets = t.getUnits().getMatches(canBeAttacked);
if (!validTargets.isEmpty()) {
possibleUnitsToAttack.put(t, validTargets);
}
}
final Map<Territory, HashMap<Unit, IntegerMap<Resource>>> attacks = getRemotePlayer(currentEnemy).selectKamikazeSuicideAttacks(possibleUnitsToAttack);
if (attacks == null || attacks.isEmpty()) {
continue;
}
// now validate that we have the resources and those units are valid targets
for (final Entry<Territory, HashMap<Unit, IntegerMap<Resource>>> territoryEntry : attacks.entrySet()) {
final Territory t = territoryEntry.getKey();
final Collection<Unit> possibleUnits = possibleUnitsToAttack.get(t);
if (possibleUnits == null || !possibleUnits.containsAll(territoryEntry.getValue().keySet())) {
throw new IllegalStateException("Player has chosen illegal units during Kamikaze Suicide Attacks");
}
for (final IntegerMap<Resource> resourceMap : territoryEntry.getValue().values()) {
attackTokens.subtract(resourceMap);
}
}
if (!attackTokens.isPositive()) {
throw new IllegalStateException("Player has chosen illegal resource during Kamikaze Suicide Attacks");
}
for (final Entry<Territory, HashMap<Unit, IntegerMap<Resource>>> territoryEntry : attacks.entrySet()) {
final Territory location = territoryEntry.getKey();
for (final Entry<Unit, IntegerMap<Resource>> unitEntry : territoryEntry.getValue().entrySet()) {
final Unit unitUnderFire = unitEntry.getKey();
final IntegerMap<Resource> numberOfAttacks = unitEntry.getValue();
if (numberOfAttacks != null && numberOfAttacks.size() > 0 && numberOfAttacks.totalValues() > 0) {
fireKamikazeSuicideAttacks(unitUnderFire, numberOfAttacks, resourcesAndAttackValues, currentEnemy, location);
}
}
}
}
}
use of games.strategy.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class AbstractPlaceDelegate method canUnitsBePlaced.
public String canUnitsBePlaced(final Territory to, final Collection<Unit> units, final PlayerID player) {
final Collection<Unit> allowedUnits = getUnitsToBePlaced(to, units, player);
if (allowedUnits == null || !allowedUnits.containsAll(units)) {
return "Cannot place these units in " + to.getName();
}
final IntegerMap<String> constructionMap = howManyOfEachConstructionCanPlace(to, to, units, player);
for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
/*
* if (ua.getIsFactory() && !ua.getIsConstruction())
* constructionMap.add("factory", -1);
* else
*/
constructionMap.add(ua.getConstructionType(), -1);
}
if (!constructionMap.isPositive()) {
return "Too many constructions in " + to.getName();
}
final List<Territory> capitalsListOwned = new ArrayList<>(TerritoryAttachment.getAllCurrentlyOwnedCapitals(player, getData()));
if (!capitalsListOwned.contains(to) && isPlacementInCapitalRestricted(player)) {
return "Cannot place these units outside of the capital";
}
if (to.isWater()) {
final String canLand = validateNewAirCanLandOnCarriers(to, units);
if (canLand != null) {
return canLand;
}
} else {
// make sure we own the territory
if (!to.getOwner().equals(player)) {
if (GameStepPropertiesHelper.isBid(getData())) {
final PlayerAttachment pa = PlayerAttachment.get(to.getOwner());
if ((pa == null || pa.getGiveUnitControl() == null || !pa.getGiveUnitControl().contains(player)) && !to.getUnits().anyMatch(Matches.unitIsOwnedBy(player))) {
return "You don't own " + to.getName();
}
} else {
return "You don't own " + to.getName();
}
}
// make sure all units are land
if (units.isEmpty() || !units.stream().allMatch(Matches.unitIsNotSea())) {
return "Cant place sea units on land";
}
}
// make sure we can place consuming units
if (!canWeConsumeUnits(units, to, false, null)) {
return "Not Enough Units To Upgrade or Be Consumed";
}
// now check for stacking limits
final Collection<UnitType> typesAlreadyChecked = new ArrayList<>();
for (final Unit currentUnit : units) {
final UnitType ut = currentUnit.getType();
if (typesAlreadyChecked.contains(ut)) {
continue;
}
typesAlreadyChecked.add(ut);
final int maxForThisType = UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("placementLimit", ut, to, player, getData());
if (CollectionUtils.countMatches(units, Matches.unitIsOfType(ut)) > maxForThisType) {
return "UnitType " + ut.getName() + " is over stacking limit of " + maxForThisType;
}
}
if (!PlayerAttachment.getCanTheseUnitsMoveWithoutViolatingStackingLimit("placementLimit", units, to, player, getData())) {
return "Units Cannot Go Over Stacking Limit";
}
// now return null (valid placement) if we have placement restrictions disabled in game options
if (!isUnitPlacementRestrictions()) {
return null;
}
// account for any unit placement restrictions by territory
for (final Unit currentUnit : units) {
final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
// Can be null!
final TerritoryAttachment ta = TerritoryAttachment.get(to);
if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > (ta == null ? 0 : ta.getProduction())) {
return "Cannot place these units in " + to.getName() + " due to Unit Placement Restrictions on Territory Value";
}
final String[] terrs = ua.getUnitPlacementRestrictions();
final Collection<Territory> listedTerrs = getListedTerritories(terrs);
if (listedTerrs.contains(to)) {
return "Cannot place these units in " + to.getName() + " due to Unit Placement Restrictions";
}
if (Matches.unitCanOnlyPlaceInOriginalTerritories().test(currentUnit) && !Matches.territoryIsOriginallyOwnedBy(player).test(to)) {
return "Cannot place these units in " + to.getName() + " as territory is not originally owned";
}
}
return null;
}
use of games.strategy.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class AbstractEndTurnDelegate method rollWarBondsForFriends.
private String rollWarBondsForFriends(final IDelegateBridge delegateBridge, final PlayerID player, final GameData data) {
final int count = TechAbilityAttachment.getWarBondDiceNumber(player, data);
final int sides = TechAbilityAttachment.getWarBondDiceSides(player, data);
if (sides <= 0 || count <= 0) {
return "";
}
// basically, if we are sharing our technology with someone, and we have warbonds but they do not, then we roll our
// warbonds and give
// them the proceeds (Global 1940)
final PlayerAttachment playerattachment = PlayerAttachment.get(player);
if (playerattachment == null) {
return "";
}
final Collection<PlayerID> shareWith = playerattachment.getShareTechnology();
if (shareWith == null || shareWith.isEmpty()) {
return "";
}
// take first one
PlayerID giveWarBondsTo = null;
for (final PlayerID p : shareWith) {
final int diceCount = TechAbilityAttachment.getWarBondDiceNumber(p, data);
final int diceSides = TechAbilityAttachment.getWarBondDiceSides(p, data);
if (diceSides <= 0 && diceCount <= 0) {
// they cannot have this tech)
if (canPlayerCollectIncome(p, data)) {
giveWarBondsTo = p;
break;
}
}
}
if (giveWarBondsTo == null) {
return "";
}
final String annotation = player.getName() + " rolling to resolve War Bonds, and giving results to " + giveWarBondsTo.getName() + ": ";
final DiceRoll dice = DiceRoll.rollNDice(delegateBridge, count, sides, player, DiceType.NONCOMBAT, annotation);
int totalWarBonds = 0;
for (int i = 0; i < dice.size(); i++) {
totalWarBonds += dice.getDie(i).getValue() + 1;
}
final Resource pus = data.getResourceList().getResource(Constants.PUS);
final int currentPUs = giveWarBondsTo.getResources().getQuantity(pus);
final String transcriptText = player.getName() + " rolls " + totalWarBonds + MyFormatter.pluralize(" PU", totalWarBonds) + " from War Bonds, giving the total to " + giveWarBondsTo.getName() + ", who ends with " + (currentPUs + totalWarBonds) + MyFormatter.pluralize(" PU", (currentPUs + totalWarBonds)) + " total";
delegateBridge.getHistoryWriter().startEvent(transcriptText);
final Change change = ChangeFactory.changeResourcesChange(giveWarBondsTo, pus, totalWarBonds);
delegateBridge.addChange(change);
getRemotePlayer(player).reportMessage(annotation + MyFormatter.asDice(dice), annotation + MyFormatter.asDice(dice));
return transcriptText + "<br />";
}
use of games.strategy.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class AbstractEndTurnDelegate method start.
@Override
public void start() {
// figure out our current PUs before we do anything else, including super methods
final GameData data = bridge.getData();
final Resource pus = data.getResourceList().getResource(Constants.PUS);
final int leftOverPUs = bridge.getPlayerId().getResources().getQuantity(pus);
final IntegerMap<Resource> leftOverResources = bridge.getPlayerId().getResources().getResourcesCopy();
super.start();
if (!needToInitialize) {
return;
}
final StringBuilder endTurnReport = new StringBuilder();
hasPostedTurnSummary = false;
final PlayerAttachment pa = PlayerAttachment.get(player);
// can't collect unless you own your own capital
if (!canPlayerCollectIncome(player, data)) {
endTurnReport.append(rollWarBondsForFriends(bridge, player, data));
// we do not collect any income this turn
} else {
// just collect resources
final Collection<Territory> territories = data.getMap().getTerritoriesOwnedBy(player);
int toAdd = getProduction(territories);
final int blockadeLoss = getBlockadeProductionLoss(player, data, bridge, endTurnReport);
toAdd -= blockadeLoss;
toAdd *= Properties.getPuMultiplier(data);
int total = player.getResources().getQuantity(pus) + toAdd;
final String transcriptText;
if (blockadeLoss == 0) {
transcriptText = player.getName() + " collect " + toAdd + MyFormatter.pluralize(" PU", toAdd) + "; end with " + total + MyFormatter.pluralize(" PU", total);
} else {
transcriptText = player.getName() + " collect " + toAdd + MyFormatter.pluralize(" PU", toAdd) + " (" + blockadeLoss + " lost to blockades)" + "; end with " + total + MyFormatter.pluralize(" PU", total);
}
bridge.getHistoryWriter().startEvent(transcriptText);
endTurnReport.append(transcriptText).append("<br />");
// do war bonds
final int bonds = rollWarBonds(bridge, player, data);
if (bonds > 0) {
total += bonds;
toAdd += bonds;
final String bondText = player.getName() + " collect " + bonds + MyFormatter.pluralize(" PU", bonds) + " from War Bonds; end with " + total + MyFormatter.pluralize(" PU", total);
bridge.getHistoryWriter().startEvent(bondText);
endTurnReport.append("<br />").append(bondText).append("<br />");
}
if (total < 0) {
toAdd -= total;
}
final Change change = ChangeFactory.changeResourcesChange(player, pus, toAdd);
bridge.addChange(change);
if (data.getProperties().get(Constants.PACIFIC_THEATER, false) && pa != null) {
final Change changeVp = (ChangeFactory.attachmentPropertyChange(pa, (pa.getVps() + (toAdd / 10) + (pa.getCaptureVps() / 10)), "vps"));
final Change changeCaptureVp = ChangeFactory.attachmentPropertyChange(pa, "0", "captureVps");
final CompositeChange ccVp = new CompositeChange(changeVp, changeCaptureVp);
bridge.addChange(ccVp);
}
endTurnReport.append("<br />").append(addOtherResources(bridge));
endTurnReport.append("<br />").append(doNationalObjectivesAndOtherEndTurnEffects(bridge));
final IntegerMap<Resource> income = player.getResources().getResourcesCopy();
income.subtract(leftOverResources);
endTurnReport.append("<br />").append(BonusIncomeUtils.addBonusIncome(income, bridge, player));
// now we do upkeep costs, including upkeep cost as a percentage of our entire income for this turn (including
// NOs)
final int currentPUs = player.getResources().getQuantity(pus);
int relationshipUpkeepCostFlat = 0;
int relationshipUpkeepCostPercentage = 0;
for (final Relationship r : data.getRelationshipTracker().getRelationships(player)) {
final String[] upkeep = r.getRelationshipType().getRelationshipTypeAttachment().getUpkeepCost().split(":");
if (upkeep.length == 1 || upkeep[1].equals(RelationshipTypeAttachment.UPKEEP_FLAT)) {
relationshipUpkeepCostFlat += Integer.parseInt(upkeep[0]);
} else if (upkeep[1].equals(RelationshipTypeAttachment.UPKEEP_PERCENTAGE)) {
relationshipUpkeepCostPercentage += Integer.parseInt(upkeep[0]);
}
}
relationshipUpkeepCostPercentage = Math.min(100, relationshipUpkeepCostPercentage);
int relationshipUpkeepTotalCost = 0;
if (relationshipUpkeepCostPercentage != 0) {
final float gainedPus = Math.max(0, currentPUs - leftOverPUs);
relationshipUpkeepTotalCost += Math.round(gainedPus * (relationshipUpkeepCostPercentage) / 100f);
}
if (relationshipUpkeepCostFlat != 0) {
relationshipUpkeepTotalCost += relationshipUpkeepCostFlat;
}
// we can't remove more than we have, and we also must flip the sign
relationshipUpkeepTotalCost = Math.min(currentPUs, relationshipUpkeepTotalCost);
relationshipUpkeepTotalCost = -1 * relationshipUpkeepTotalCost;
if (relationshipUpkeepTotalCost != 0) {
final int newTotal = currentPUs + relationshipUpkeepTotalCost;
final String transcriptText2 = player.getName() + (relationshipUpkeepTotalCost < 0 ? " pays " : " taxes ") + (-1 * relationshipUpkeepTotalCost) + MyFormatter.pluralize(" PU", relationshipUpkeepTotalCost) + " in order to maintain current relationships with other players, and ends the turn with " + newTotal + MyFormatter.pluralize(" PU", newTotal);
bridge.getHistoryWriter().startEvent(transcriptText2);
endTurnReport.append("<br />").append(transcriptText2).append("<br />");
final Change upkeep = ChangeFactory.changeResourcesChange(player, pus, relationshipUpkeepTotalCost);
bridge.addChange(upkeep);
}
}
if (GameStepPropertiesHelper.isRepairUnits(data)) {
MoveDelegate.repairMultipleHitPointUnits(bridge, bridge.getPlayerId());
}
if (isGiveUnitsByTerritory() && pa != null && pa.getGiveUnitControl() != null && !pa.getGiveUnitControl().isEmpty()) {
changeUnitOwnership(bridge);
}
needToInitialize = false;
showEndTurnReport(endTurnReport.toString());
}
use of games.strategy.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class PlacePanel method getUnitsToPlace.
private Collection<Unit> getUnitsToPlace(final Territory territory, final int[] maxUnits) {
getData().acquireReadLock();
try {
// not our territory
if (!territory.isWater() && !territory.getOwner().equals(getCurrentPlayer())) {
if (GameStepPropertiesHelper.isBid(getData())) {
final PlayerAttachment pa = PlayerAttachment.get(territory.getOwner());
if ((pa == null || pa.getGiveUnitControl() == null || !pa.getGiveUnitControl().contains(getCurrentPlayer())) && !territory.getUnits().anyMatch(Matches.unitIsOwnedBy(getCurrentPlayer()))) {
return Collections.emptyList();
}
} else {
return Collections.emptyList();
}
}
// get the units that can be placed on this territory.
Collection<Unit> units = getCurrentPlayer().getUnits().getUnits();
if (territory.isWater()) {
if (!(canProduceFightersOnCarriers() || canProduceNewFightersOnOldCarriers() || isLhtrCarrierProductionRules() || GameStepPropertiesHelper.isBid(getData()))) {
units = CollectionUtils.getMatches(units, Matches.unitIsSea());
} else {
final Predicate<Unit> unitIsSeaOrCanLandOnCarrier = Matches.unitIsSea().or(Matches.unitCanLandOnCarrier());
units = CollectionUtils.getMatches(units, unitIsSeaOrCanLandOnCarrier);
}
} else {
units = CollectionUtils.getMatches(units, Matches.unitIsNotSea());
}
if (units.isEmpty()) {
return Collections.emptyList();
}
final IAbstractPlaceDelegate placeDel = (IAbstractPlaceDelegate) getPlayerBridge().getRemoteDelegate();
final PlaceableUnits production = placeDel.getPlaceableUnits(units, territory);
if (production.isError()) {
JOptionPane.showMessageDialog(getTopLevelAncestor(), production.getErrorMessage(), "No units", JOptionPane.INFORMATION_MESSAGE);
return Collections.emptyList();
}
maxUnits[0] = production.getMaxUnits();
return production.getUnits();
} finally {
getData().releaseReadLock();
}
}
Aggregations