/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.common.model;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import net.sf.freecol.common.model.CombatModel.CombatResult;
import net.sf.freecol.common.model.Unit.MoveType;
import net.sf.freecol.server.ServerTestHelper;
import net.sf.freecol.server.control.ChangeSet;
import net.sf.freecol.server.control.InGameController;
import net.sf.freecol.server.model.ServerPlayer;
import net.sf.freecol.server.model.ServerUnit;
import net.sf.freecol.util.test.FreeColTestCase;
public class CombatTest extends FreeColTestCase {
private static final EquipmentType muskets
= spec().getEquipmentType("model.equipment.muskets");
private static final EquipmentType horses
= spec().getEquipmentType("model.equipment.horses");
private static final EquipmentType tools
= spec().getEquipmentType("model.equipment.tools");
private static final EquipmentType indianMuskets
= spec().getEquipmentType("model.equipment.indian.muskets");
private static final EquipmentType indianHorses
= spec().getEquipmentType("model.equipment.indian.horses");
private static final TileType plains
= spec().getTileType("model.tile.plains");
private static final TileType hills
= spec().getTileType("model.tile.hills");
private static final TileType ocean
= spec().getTileType("model.tile.ocean");
private static final UnitType galleonType
= spec().getUnitType("model.unit.galleon");
private static final UnitType privateerType
= spec().getUnitType("model.unit.privateer");
private static final UnitType braveType
= spec().getUnitType("model.unit.brave");
private static final UnitType colonistType
= spec().getUnitType("model.unit.freeColonist");
private static final UnitType veteranType
= spec().getUnitType("model.unit.veteranSoldier");
private static final UnitType artilleryType
= spec().getUnitType("model.unit.artillery");
private static final UnitType damagedArtilleryType
= spec().getUnitType("model.unit.damagedArtillery");
private static final UnitType colonialRegularType
= spec().getUnitType("model.unit.colonialRegular");
private static final UnitType kingsRegularType
= spec().getUnitType("model.unit.kingsRegular");
private static final UnitType indianConvertType
= spec().getUnitType("model.unit.indianConvert");
private static final UnitType pettyCriminalType
= spec().getUnitType("model.unit.pettyCriminal");
private static final UnitType indenturedServantType
= spec().getUnitType("model.unit.indenturedServant");
EquipmentType[] dragoonEquipment = new EquipmentType[] { horses, muskets };
public void testColonistAttackedByVeteran() throws Exception {
Game game = getStandardGame();
CombatModel combatModel = game.getCombatModel();
Player dutch = game.getPlayer("model.nation.dutch");
Player french = game.getPlayer("model.nation.french");
Map map = getTestMap(plains);
game.setMap(map);
FreeColTestCase.spec();
Tile tile1 = map.getTile(5, 8);
tile1.setType(hills);
assertEquals(hills, tile1.getType());
tile1.setExploredBy(dutch, true);
tile1.setExploredBy(french, true);
Tile tile2 = map.getTile(4, 8);
tile2.setExploredBy(dutch, true);
tile2.setExploredBy(french, true);
Unit colonist = new ServerUnit(game, tile1, dutch, colonistType);
colonist.setStateUnchecked(Unit.UnitState.FORTIFIED);
Unit soldier = new ServerUnit(game, tile2, french, veteranType, muskets, horses);
soldier.setMovesLeft(1);
Modifier bigMovementPenalty = spec().getModifiers(SimpleCombatModel.BIG_MOVEMENT_PENALTY)
.get(0);
Modifier attackBonus = spec().getModifiers(SimpleCombatModel.ATTACK_BONUS).get(0);
Modifier fortified = spec().getModifiers(SimpleCombatModel.FORTIFIED).get(0);
Set<Modifier> veteranModifierSet = veteranType.getModifierSet("model.modifier.offence");
assertEquals(1, veteranModifierSet.size());
Modifier veteranModifier = veteranModifierSet.iterator().next();
Set<Modifier> musketModifierSet = muskets.getModifierSet("model.modifier.offence");
assertEquals(1, musketModifierSet.size());
Modifier musketModifier = musketModifierSet.iterator().next();
Set<Modifier> horsesModifierSet = horses.getModifierSet("model.modifier.offence");
assertEquals(1, horsesModifierSet.size());
Modifier horsesModifier = horsesModifierSet.iterator().next();
Set<Modifier> offenceModifiers = combatModel.getOffensiveModifiers(soldier, colonist);
assertEquals(6, offenceModifiers.size());
assertTrue(offenceModifiers.contains(bigMovementPenalty));
offenceModifiers.remove(bigMovementPenalty);
assertTrue(offenceModifiers.contains(veteranModifier));
offenceModifiers.remove(veteranModifier);
assertTrue(offenceModifiers.contains(musketModifier));
offenceModifiers.remove(musketModifier);
assertTrue(offenceModifiers.contains(horsesModifier));
offenceModifiers.remove(horsesModifier);
assertTrue(offenceModifiers.contains(attackBonus));
offenceModifiers.remove(attackBonus);
// this was also added by the combat model
assertEquals(Specification.BASE_OFFENCE_SOURCE, offenceModifiers.iterator().next().getSource());
Set<Modifier> hillsModifierSet = hills.getDefenceBonus();
assertFalse(soldier.hasAbility("model.ability.ambushBonus"));
assertFalse(colonist.hasAbility("model.ability.ambushPenalty"));
assertEquals(1, hillsModifierSet.size());
Modifier hillsModifier = hillsModifierSet.iterator().next();
Set<Modifier> defenceModifiers = combatModel.getDefensiveModifiers(soldier, colonist);
assertEquals(3, defenceModifiers.size());
assertTrue(defenceModifiers.contains(hillsModifier));
defenceModifiers.remove(hillsModifier);
assertTrue(defenceModifiers.contains(fortified));
defenceModifiers.remove(fortified);
// this was also added by the combat model
assertEquals(Specification.BASE_DEFENCE_SOURCE, defenceModifiers.iterator().next().getSource());
}
public void testGalleonAttackedByPrivateer() throws Exception {
Game game = getStandardGame();
CombatModel combatModel = game.getCombatModel();
Player dutch = game.getPlayer("model.nation.dutch");
Player french = game.getPlayer("model.nation.french");
Map map = getTestMap(ocean);
game.setMap(map);
FreeColTestCase.spec();
Tile tile1 = map.getTile(5, 8);
tile1.setExploredBy(dutch, true);
tile1.setExploredBy(french, true);
Tile tile2 = map.getTile(4, 8);
tile2.setExploredBy(dutch, true);
tile2.setExploredBy(french, true);
Unit galleon = new ServerUnit(game, tile1, dutch, galleonType);
Unit privateer = new ServerUnit(game, tile2, french, privateerType);
/**
* Only base modifiers should apply.
*/
Set<Modifier> offenceModifiers = combatModel.getOffensiveModifiers(privateer, galleon);
assertEquals(1, offenceModifiers.size());
assertEquals(Specification.BASE_OFFENCE_SOURCE, offenceModifiers.iterator().next().getSource());
Set<Modifier> defenceModifiers = combatModel.getDefensiveModifiers(privateer, galleon);
assertEquals(1, defenceModifiers.size());
assertEquals(Specification.BASE_DEFENCE_SOURCE, defenceModifiers.iterator().next().getSource());
/**
* Fortification should have no effect.
*/
galleon.setStateUnchecked(Unit.UnitState.FORTIFIED);
defenceModifiers = combatModel.getDefensiveModifiers(privateer, galleon);
assertEquals(1, defenceModifiers.size());
assertEquals(Specification.BASE_DEFENCE_SOURCE, defenceModifiers.iterator().next().getSource());
/**
* Penalties due to cargo.
*/
GoodsType lumberType = spec().getGoodsType("model.goods.lumber");
Goods goods1 = new Goods(game, null, lumberType, 50);
privateer.add(goods1);
offenceModifiers = combatModel.getOffensiveModifiers(privateer, galleon);
Iterator<Modifier> privIt = offenceModifiers.iterator();
assertEquals(2, offenceModifiers.size());
assertEquals(Specification.BASE_OFFENCE_SOURCE, privIt.next().getSource());
Modifier goodsPenalty1 = privIt.next();
assertEquals(Specification.CARGO_PENALTY_SOURCE, goodsPenalty1.getSource());
assertEquals(-12.5f, goodsPenalty1.getValue());
Goods goods2 = new Goods(game, null, lumberType, 150);
galleon.add(goods2);
assertEquals(2, galleon.getVisibleGoodsCount());
defenceModifiers = combatModel.getDefensiveModifiers(privateer, galleon);
Iterator<Modifier> gallIt = defenceModifiers.iterator();
assertEquals(2, defenceModifiers.size());
assertEquals(Specification.BASE_DEFENCE_SOURCE, gallIt.next().getSource());
Modifier goodsPenalty2 = gallIt.next();
assertEquals(Specification.CARGO_PENALTY_SOURCE, goodsPenalty2.getSource());
assertEquals(-25f, goodsPenalty2.getValue());
/**
* Francis Drake
*/
FoundingFather drake = spec().getFoundingFather("model.foundingFather.francisDrake");
Set<Modifier> drakeModifiers = drake.getModifierSet("model.modifier.offence", privateerType);
assertEquals(1, drakeModifiers.size());
Modifier drakeModifier = drakeModifiers.iterator().next();
french.addFather(drake);
drakeModifiers = french.getModifierSet("model.modifier.offence", privateerType);
assertEquals(1, drakeModifiers.size());
assertEquals(drakeModifier, drakeModifiers.iterator().next());
offenceModifiers = combatModel.getOffensiveModifiers(privateer, galleon);
privIt = offenceModifiers.iterator();
assertEquals(3, offenceModifiers.size());
assertEquals(Specification.BASE_OFFENCE_SOURCE, privIt.next().getSource());
Modifier newDrakeModifier = privIt.next();
assertEquals(drakeModifier, newDrakeModifier);
goodsPenalty1 = privIt.next();
assertEquals(Specification.CARGO_PENALTY_SOURCE, goodsPenalty1.getSource());
assertEquals(-12.5f, goodsPenalty1.getValue());
// Verify that the move is correctly interpreted
assertEquals("Wrong move type", MoveType.ATTACK_UNIT,
privateer.getMoveType(tile1));
}
public void testDefendColonyWithUnarmedColonist() {
Game game = getGame();
Map map = getTestMap(true);
game.setMap(map);
Colony colony = getStandardColony();
@SuppressWarnings("unused")
SimpleCombatModel combatModel = new SimpleCombatModel();
Player dutch = game.getPlayer("model.nation.dutch");
Player inca = game.getPlayer("model.nation.inca");
Tile tile2 = map.getTile(4, 8);
tile2.setExploredBy(dutch, true);
tile2.setExploredBy(inca, true);
Unit colonist = colony.getUnitIterator().next();
Unit attacker = new ServerUnit(getGame(), tile2, inca, braveType,
indianHorses, indianMuskets);
assertEquals(colonist, colony.getDefendingUnit(attacker));
assertEquals(colonist, colony.getTile().getDefendingUnit(attacker));
Unit defender = new ServerUnit(getGame(), colony.getTile(), dutch,
colonistType);
assertFalse("Colonist should not be defensive unit",defender.isDefensiveUnit());
assertEquals(defender, colony.getTile().getDefendingUnit(attacker));
}
public void testDefendColonyWithRevere() {
Game game = getGame();
Map map = getTestMap(true);
game.setMap(map);
Colony colony = getStandardColony();
SimpleCombatModel combatModel = new SimpleCombatModel();
Player dutch = game.getPlayer("model.nation.dutch");
Player inca = game.getPlayer("model.nation.inca");
Tile tile2 = map.getTile(4, 8);
tile2.setExploredBy(dutch, true);
tile2.setExploredBy(inca, true);
Unit colonist = colony.getUnitIterator().next();
Unit attacker = new ServerUnit(getGame(), tile2, inca, braveType, indianHorses, indianMuskets);
assertEquals(colonist, colony.getDefendingUnit(attacker));
dutch.addFather(spec().getFoundingFather("model.foundingFather.paulRevere"));
for (EquipmentType equipment : dragoonEquipment) {
for (AbstractGoods goods : equipment.getGoodsRequired()) {
colony.addGoods(goods);
}
}
Set<Modifier> defenceModifiers = combatModel.getDefensiveModifiers(attacker, colonist);
for (Modifier defenceModifier : muskets.getModifierSet("model.modifier.defence")) {
assertTrue(defenceModifiers.contains(defenceModifier));
}
for (Modifier defenceModifier : horses.getModifierSet("model.modifier.defence")) {
assertFalse(defenceModifiers.contains(defenceModifier));
}
}
public void testDefendSettlement() {
Game game = getStandardGame();
Map map = getTestMap();
game.setMap(map);
SimpleCombatModel combatModel = new SimpleCombatModel();
Player dutch = game.getPlayer("model.nation.dutch");
Player inca = game.getPlayer("model.nation.inca");
Tile tile1 = map.getTile(5, 8);
tile1.setExploredBy(dutch, true);
tile1.setExploredBy(inca, true);
Tile tile2 = map.getTile(4, 8);
tile2.setExploredBy(dutch, true);
tile2.setExploredBy(inca, true);
FreeColTestCase.IndianSettlementBuilder builder = new FreeColTestCase.IndianSettlementBuilder(game);
IndianSettlement settlement = builder.player(inca).settlementTile(tile1).skillToTeach(null).capital(true).build();
//IndianSettlement settlement = new IndianSettlement(game, inca, tile1, true, null, false, null);
Unit defender = new ServerUnit(game, settlement, inca, braveType);
Unit attacker = new ServerUnit(game, tile2, dutch, colonistType, horses, muskets);
for (EquipmentType equipment : dragoonEquipment) {
for (AbstractGoods goods : equipment.getGoodsRequired()) {
settlement.addGoods(goods);
}
}
Set<Modifier> defenceModifiers = combatModel.getDefensiveModifiers(attacker, defender);
for (Modifier defenceModifier : indianMuskets.getModifierSet("model.modifier.defence")) {
assertTrue(defenceModifiers.contains(defenceModifier));
}
for (Modifier defenceModifier : indianHorses.getModifierSet("model.modifier.defence")) {
assertTrue(defenceModifiers.contains(defenceModifier));
}
}
public void testAttackIgnoresMovementPoints() throws Exception {
Game game = getStandardGame();
Player dutch = game.getPlayer("model.nation.dutch");
Player french = game.getPlayer("model.nation.french");
Map map = getTestMap(plains, true);
game.setMap(map);
Tile tile1 = map.getTile(5, 8);
Tile tile2 = map.getTile(4, 8);
tile1.setType(hills);
assertEquals(hills, tile1.getType());
dutch.setStance(french, Player.Stance.WAR);
french.setStance(dutch, Player.Stance.WAR);
Unit colonist = new ServerUnit(game, tile1, dutch, colonistType);
colonist.setStateUnchecked(Unit.UnitState.FORTIFIED);
Unit soldier = new ServerUnit(game, tile2, french, veteranType,
muskets, horses);
soldier.setStateUnchecked(Unit.UnitState.FORTIFIED);
assertEquals(tile1, colonist.getLocation());
assertEquals(tile2, soldier.getLocation());
assertEquals(Unit.MoveType.ATTACK_UNIT,
soldier.getMoveType(tile2, tile1, 9));
assertEquals(Unit.MoveType.ATTACK_UNIT,
soldier.getMoveType(tile2, tile1, 1));
assertEquals(Unit.MoveType.MOVE_NO_MOVES,
soldier.getMoveType(tile2, tile1, 0));
}
public void testSpanishAgainstNatives() throws Exception {
Game game = getStandardGame();
Player spanish = game.getPlayer("model.nation.spanish");
Player tupi = game.getPlayer("model.nation.tupi");
Map map = getTestMap(plains, true);
game.setMap(map);
SimpleCombatModel combatModel = new SimpleCombatModel();
Tile tile1 = map.getTile(5, 8);
Tile tile2 = map.getTile(4, 8);
tile1.setType(hills);
assertEquals(hills, tile1.getType());
spanish.setStance(tupi, Player.Stance.WAR);
tupi.setStance(spanish, Player.Stance.WAR);
Unit soldier = new ServerUnit(game, tile1, spanish, colonistType,
muskets);
Unit brave = new ServerUnit(game, tile2, tupi, braveType);
assertEquals(tile1, soldier.getLocation());
assertEquals(tile2, brave.getLocation());
Set<Modifier> offenceModifiers = combatModel.getOffensiveModifiers(soldier, brave);
Modifier offenceAgainst = null;
for (Modifier modifier : offenceModifiers) {
if (Modifier.OFFENCE_AGAINST.equals(modifier.getId())) {
offenceAgainst = modifier;
break;
}
}
assertNotNull(offenceAgainst);
assertEquals(50, (int) offenceAgainst.getValue());
}
public void testAttackShipWithLandUnit() {
Game game = getStandardGame();
Player spanish = game.getPlayer("model.nation.spanish");
Player tupi = game.getPlayer("model.nation.tupi");
Map map = getTestMap(plains, true);
game.setMap(map);
SimpleCombatModel combatModel = new SimpleCombatModel();
Tile tile1 = map.getTile(5, 8);
Tile tile2 = map.getTile(4, 8);
tile1.setType(hills);
assertEquals(hills, tile1.getType());
tile2.setType(ocean);
assertEquals(ocean, tile2.getType());
spanish.setStance(tupi, Player.Stance.WAR);
tupi.setStance(spanish, Player.Stance.WAR);
Unit galleon = new ServerUnit(game, tile2, spanish, galleonType);
Unit brave = new ServerUnit(game, tile1, tupi, braveType);
assertEquals(tile1, brave.getLocation());
assertEquals(tile2, galleon.getLocation());
assertEquals(Unit.MoveType.MOVE_NO_ACCESS_LAND,
galleon.getMoveType(tile2, tile1, 3));
assertEquals(Unit.MoveType.MOVE_NO_ACCESS_EMBARK,
brave.getMoveType(tile1, tile2, 3));
}
public void testRegulars() {
Random random = new Random(1);
// these are the first ten values the RNG will produce
float[] values = new float[] {
0.7308782f,
0.100473166f,
0.4100808f,
0.40743977f,
0.2077148f,
0.036235332f,
0.332717f,
0.6588672f,
0.96775585f,
0.7107396f
};
Map map = getTestMap(plains, true);
Game game = ServerTestHelper.startServerGame(map);
InGameController igc = ServerTestHelper.getInGameController();
ServerPlayer french = (ServerPlayer) game.getPlayer("model.nation.french");
french.addAbility(new Ability("model.ability.independenceDeclared"));
ServerPlayer refPlayer = igc.createREFPlayer(french);
SimpleCombatModel combatModel = new SimpleCombatModel();
Tile tile1 = map.getTile(5, 8);
Tile tile2 = map.getTile(4, 8);
Unit colonial = new ServerUnit(game, tile1, french, colonialRegularType, muskets, horses);
Unit regular = new ServerUnit(game, tile1, french, kingsRegularType, muskets, horses);
// (regular + muskets + horses) * attack bonus
float offence = (4 + 2 + 1) * 1.5f;
assertEquals(offence, combatModel.getOffencePower(regular, colonial));
// colonial + muskets + horses + defence bonus
float defence = 3 + 1 + 1 + 1;
assertEquals(defence, combatModel.getDefencePower(regular, colonial));
List<CombatResult> result = combatModel.generateAttackResult(random, regular, colonial);
assertEquals(CombatResult.LOSE, result.get(0));
assertEquals(CombatResult.LOSE_EQUIP, result.get(1));
refPlayer.csCombat(regular, colonial, result, random, new ChangeSet());
// (regular + muskets) * attack bonus
offence = (4 + 2) * 1.5f;
assertEquals(offence, combatModel.getOffencePower(regular, colonial));
// slaughter King's Regular
result = combatModel.generateAttackResult(random, colonial, regular);
assertEquals(CombatResult.WIN, result.get(0));
assertEquals("King's Regular should be slaughtered upon losing all equipment.",
CombatResult.SLAUGHTER_UNIT, result.get(1));
regular = new ServerUnit(game, tile1, french, kingsRegularType, muskets, horses);
result = combatModel.generateAttackResult(random, regular, colonial);
assertEquals(CombatResult.WIN, result.get(0));
assertEquals(CombatResult.LOSE_EQUIP, result.get(1));
refPlayer.csCombat(regular, colonial, result, random, new ChangeSet());
result = combatModel.generateAttackResult(random, regular, colonial);
assertEquals(CombatResult.WIN, result.get(0));
assertEquals(CombatResult.LOSE_EQUIP, result.get(1));
assertEquals(CombatResult.DEMOTE_UNIT, result.get(2));
refPlayer.csCombat(regular, colonial, result, random, new ChangeSet());
assertFalse(colonial.isArmed());
assertEquals(veteranType, colonial.getType());
result = combatModel.generateAttackResult(random, regular, colonial);
assertEquals(CombatResult.WIN, result.get(0));
assertEquals(CombatResult.CAPTURE_UNIT, result.get(1));
refPlayer.csCombat(regular, colonial, result, random, new ChangeSet());
}
}