package ch.fusun.baron.basic.command;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import ch.fusun.baron.city.City;
import ch.fusun.baron.city.api.CityService;
import ch.fusun.baron.core.injection.Configure;
import ch.fusun.baron.core.injection.Inject;
import ch.fusun.baron.core.service.UserService;
import ch.fusun.baron.map.Tile;
import ch.fusun.baron.map.api.GameMapService;
import ch.fusun.baron.player.Dynasty;
import ch.fusun.baron.printing.MessagingService;
import ch.fusun.baron.property.api.PropertyService;
import ch.fusun.baron.unit.Unit;
import ch.fusun.baron.unit.service.UnitService;
/**
* Moves a unit from one tile to the next
*/
public class MoveUnitCommand extends MoneyTurnCommand {
private Dynasty dynasty;
private Unit unit;
private Tile destination;
@Inject
private transient PropertyService propertyService;
@Inject
private transient UnitService unitService;
@Inject
private transient CityService cityService;
@Inject
private transient GameMapService mapService;
@Inject
private transient MessagingService messagingService;
@Inject
private transient UserService userService;
@Configure(value = "10")
private transient int MONEY_COST;
/**
* Injection constructor
*/
public MoveUnitCommand() {
}
/**
* @param dynasty
* The player
* @param unit
* the unit
* @param destination
* THe destination tile
*/
public MoveUnitCommand(Dynasty dynasty, Unit unit, Tile destination) {
this.dynasty = dynasty;
this.unit = unit;
this.destination = destination;
}
@Override
public boolean isAllowedImpl() {
Collection<Unit> units = unitService.getUnits(destination);
boolean destinationOccupied = false;
if (!units.isEmpty()) {
Unit otherUnit = units.iterator().next();
destinationOccupied = dynasty.equals(propertyService
.getOwnership(otherUnit));
}
return dynasty.equals(propertyService.getOwnership(unit))
&& tileIsReachable() && unitService.unitExists(unit)
&& !destinationOccupied;
}
private boolean tileIsReachable() {
return !(unitService.getLocation(unit).absoluteDistanceTo(destination) > 1f);
}
@Override
public void executeImpl() {
Unit movingUnit = unitService.getUnits(unitService.getLocation(unit))
.iterator().next();
Collection<Unit> units = unitService.getUnits(destination);
if (units.isEmpty()) {
unitService.moveUnit(movingUnit, destination);
if (calculateAnnectionFrom()) {
messagingService
.addMessage(
userService.getUser(),
"City of " //$NON-NLS-1$
+ ((Dynasty) propertyService
.getOwnership(unit)).getName()
+ " is lost because no one defended it."); //$NON-NLS-1$
}
} else {
Unit otherUnit = units.iterator().next();
if (!dynasty.equals(propertyService.getOwnership(otherUnit))) {
int numberOfUnits = movingUnit.getNumberOfUnits();
int otherNumberOfUnits = otherUnit.getNumberOfUnits();
int casualties = 0;
int otherCasualties = 0;
for (int i = 1; i <= Math
.max(numberOfUnits, otherNumberOfUnits); i++) {
if (i > numberOfUnits) {
casualties += (Math.random() < 0.5f) ? 1 : 0;
} else if (i > otherNumberOfUnits) {
otherCasualties += (Math.random() < 0.5f) ? 1 : 0;
} else if (Math.random() < 0.5f) {
casualties += 1;
} else {
otherCasualties += 1;
}
}
messagingService
.addMessage(
userService.getUser(),
"Battle between " //$NON-NLS-1$
+ ((Dynasty) propertyService
.getOwnership(unit)).getName()
+ "(" + casualties + " casualties) and " //$NON-NLS-1$ //$NON-NLS-2$
+ ((Dynasty) propertyService
.getOwnership(otherUnit))
.getName() + "(" //$NON-NLS-1$
+ otherCasualties + " casualties)"); //$NON-NLS-1$
movingUnit.kill(casualties);
if (movingUnit.isDead()) {
unitService.removeUnit(movingUnit);
messagingService.addMessage(
userService.getUser(),
"Attacking unit of " //$NON-NLS-1$
+ ((Dynasty) propertyService
.getOwnership(unit)).getName()
+ " exploded in a fireball"); //$NON-NLS-1$
}
otherUnit.kill(otherCasualties);
if (otherUnit.isDead()) {
messagingService.addMessage(
userService.getUser(),
"Defending unit of " //$NON-NLS-1$
+ ((Dynasty) propertyService
.getOwnership(unit)).getName()
+ " was trampled"); //$NON-NLS-1$
unitService.removeUnit(otherUnit);
unitService.moveUnit(movingUnit, destination);
if (calculateAnnectionFrom()) {
messagingService
.addMessage(
userService.getUser(),
"City of " //$NON-NLS-1$
+ ((Dynasty) propertyService
.getOwnership(unit))
.getName()
+ " is lost because defenders were to weak."); //$NON-NLS-1$
}
}
}
}
}
private boolean calculateAnnectionFrom() {
boolean newLand = false;
Object o = propertyService.getOwnership(destination);
if (o instanceof Dynasty) {
Dynasty ownership = (Dynasty) o;
if (!dynasty.equals(ownership)) {
City city = cityService.getCity(destination);
if (city != null) {
Collection<City> citiesOfPlayer = getCitiesForDynasty(ownership);
for (Tile tile : mapService.getTiles()) {
if (ownership
.equals(propertyService.getOwnership(tile))) {
if (getNearestCityLocation(tile, citiesOfPlayer)
.equals(destination)) {
propertyService.setOwnership(dynasty, tile);
newLand = true;
}
}
}
}
}
}
return newLand;
}
private Tile getNearestCityLocation(Tile tile, Collection<City> cities) {
Tile nearestLocation = new Tile(Integer.MAX_VALUE, Integer.MAX_VALUE);
double nearestDistance = Double.MAX_VALUE;
for (City city : cities) {
Tile cityLocation = cityService.getLocation(city);
if (cityLocation.absoluteDistanceTo(tile) < nearestDistance) {
nearestDistance = cityLocation.absoluteDistanceTo(tile);
nearestLocation = cityLocation;
}
}
return nearestLocation;
}
private Collection<City> getCitiesForDynasty(Dynasty dynasty) {
List<City> cities = new LinkedList<City>();
for (Tile tile : mapService.getTiles()) {
City city = cityService.getCity(tile);
if (city != null) {
if (dynasty.equals(propertyService.getOwnership(tile))) {
cities.add(city);
}
}
}
return cities;
}
@Override
protected int getTurnCost() {
return unit.getNumberOfUnits();
}
@Override
protected Dynasty getDynasty() {
return dynasty;
}
@Override
protected int getMoneyCost() {
return MONEY_COST;
}
}