mirror of https://github.com/FreeCol/freecol.git
309 lines
11 KiB
Java
309 lines
11 KiB
Java
/**
|
|
* Copyright (C) 2002-2022 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.Comparator;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.Random;
|
|
import java.util.Set;
|
|
|
|
|
|
/**
|
|
* A abstract requirements for a FreeCol combat model.
|
|
*/
|
|
public abstract class CombatModel {
|
|
|
|
public enum CombatEffectType {
|
|
// Special results that set the sense of the result.
|
|
NO_RESULT,
|
|
LOSE,
|
|
WIN,
|
|
// Specific actions
|
|
AUTOEQUIP_UNIT, // Defending unit auto-arms
|
|
BURN_MISSIONS, // Defending natives burn attackers missions
|
|
CAPTURE_AUTOEQUIP, // Winner captures loser auto-equipment
|
|
CAPTURE_COLONY, // Winning Europeans capture a colony
|
|
CAPTURE_CONVERT, // Winning Europeans cause native to convert
|
|
CAPTURE_EQUIP, // Winner captures loser equipment
|
|
CAPTURE_UNIT, // Losing unit is captured
|
|
DAMAGE_COLONY_SHIPS, // Ships in losing colony are damaged
|
|
DAMAGE_SHIP_ATTACK, // Losing ship is damaged by normal attack
|
|
DAMAGE_SHIP_BOMBARD, // Losing ship is damaged by bombardment
|
|
DEMOTE_UNIT, // Losing unit is demoted
|
|
DESTROY_COLONY, // Winning natives burn a colony
|
|
DESTROY_SETTLEMENT, // Winner destroys a native settlement
|
|
EVADE_ATTACK, // Defending ship evades normal attack
|
|
EVADE_BOMBARD, // Defending ship evades bombardment
|
|
LOOT_SHIP, // Losing ship is looted
|
|
LOSE_AUTOEQUIP, // Losing unit auto-arms and loses the arms
|
|
LOSE_EQUIP, // Losing unit loses some equipment
|
|
PILLAGE_COLONY, // Winning natives pillage an undefended colony
|
|
PROMOTE_UNIT, // Winning unit is promoted
|
|
SINK_COLONY_SHIPS, // Ships in losing colony are sunk
|
|
SINK_SHIP_ATTACK, // Losing ship is sunk by normal attack
|
|
SINK_SHIP_BOMBARD, // Losing ship is sunk by bombardment
|
|
SLAUGHTER_UNIT, // Losing unit is slaughtered
|
|
}
|
|
|
|
public static final class CombatResult {
|
|
|
|
private final List<CombatEffectType> effects;
|
|
private final int attackerHitpointsAfter;
|
|
private final int defenderHitpointsAfter;
|
|
|
|
public CombatResult(List<CombatEffectType> effects) {
|
|
this.effects = Objects.requireNonNull(effects);
|
|
this.attackerHitpointsAfter = -1;
|
|
this.defenderHitpointsAfter = -1;
|
|
}
|
|
|
|
public CombatResult(List<CombatEffectType> effects, int attackerHitpointsAfter, int defenderHitpointsAfter) {
|
|
this.effects = Objects.requireNonNull(effects);
|
|
this.attackerHitpointsAfter = attackerHitpointsAfter;
|
|
this.defenderHitpointsAfter = defenderHitpointsAfter;
|
|
}
|
|
|
|
public List<CombatEffectType> getEffects() {
|
|
return effects;
|
|
}
|
|
|
|
public boolean isAttackerHitpointsAffected() {
|
|
return attackerHitpointsAfter >= 0;
|
|
}
|
|
|
|
public boolean isDefenderHitpointsAffected() {
|
|
return defenderHitpointsAfter >= 0;
|
|
}
|
|
|
|
public int getAttackerHitpointsAfter() {
|
|
return attackerHitpointsAfter;
|
|
}
|
|
|
|
public int getDefenderHitpointsAfter() {
|
|
return defenderHitpointsAfter;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Odds a particular outcome will occur in combat.
|
|
*/
|
|
public static class CombatOdds {
|
|
public static final double UNKNOWN_ODDS = -1.0;
|
|
|
|
public final double win;
|
|
|
|
public CombatOdds(double win) {
|
|
this.win = win;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Empty constructor is sufficient.
|
|
*/
|
|
public CombatModel() {}
|
|
|
|
|
|
/**
|
|
* Is this just a measurement of offence power?
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return True if no defender is provided.
|
|
*/
|
|
protected final boolean combatIsAttackMeasurement(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
return attacker instanceof Unit && defender == null;
|
|
}
|
|
|
|
/**
|
|
* Is this just a measurement of defence power?
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return True if no attacker is provided.
|
|
*/
|
|
protected final boolean combatIsDefenceMeasurement(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
return attacker == null && defender instanceof Unit;
|
|
}
|
|
|
|
/**
|
|
* Is this combat a normal attack?
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return True if the combat is a normal attack.
|
|
*/
|
|
public boolean combatIsAttack(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
return attacker instanceof Unit && defender instanceof Unit;
|
|
}
|
|
|
|
/**
|
|
* Is this combat a attack on a settlement? These happen on the client
|
|
* side only, for the purposes of the pre-combat display. In these cases
|
|
* the actual defender unit is hidden from the attacker player, so
|
|
* the defender is shown as the settlement itself.
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return True if the combat is a client-side attack on a settlement.
|
|
*/
|
|
public boolean combatIsSettlementAttack(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
return attacker instanceof Unit && defender instanceof Settlement;
|
|
}
|
|
|
|
/**
|
|
* Is this combat a bombardment?
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return True if the combat is a bombardment.
|
|
*/
|
|
public boolean combatIsBombard(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
return attacker instanceof Settlement && defender instanceof Unit
|
|
&& ((Unit)defender).isNaval();
|
|
}
|
|
|
|
/**
|
|
* Could this attack be an amphibious operation?
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return True if the attack is amphibious.
|
|
*/
|
|
public boolean combatIsAmphibious(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
return attacker instanceof Unit
|
|
&& ((Unit)attacker).hasTile()
|
|
&& !((Unit)attacker).getTile().isLand()
|
|
&& defender instanceof Location
|
|
&& ((Location)defender).getTile() != null
|
|
&& ((Location)defender).getTile().isLand();
|
|
}
|
|
|
|
/**
|
|
* Is this a combat between a rebel player and the REF at a colony?
|
|
*
|
|
* @param attacker The attacker object.
|
|
* @param defender The defender object.
|
|
* @return True if the attack is a war of independence battle for a colony.
|
|
*/
|
|
protected final boolean combatIsWarOfIndependence(FreeColGameObject attacker,
|
|
FreeColGameObject defender) {
|
|
if (attacker instanceof Unit
|
|
&& defender instanceof Ownable) {
|
|
Player aPlayer = ((Unit)attacker).getOwner();
|
|
Player dPlayer = ((Ownable)defender).getOwner();
|
|
return (aPlayer.isRebel() && aPlayer.getREFPlayer() == dPlayer)
|
|
|| (dPlayer.isRebel() && dPlayer.getREFPlayer() == aPlayer);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get a comparator to order units by relative military strength
|
|
* with respect to this combat model.
|
|
*
|
|
* @return A suitable unit {@code Comparator}.
|
|
*/
|
|
public final Comparator<Unit> getMilitaryStrengthComparator() {
|
|
return (u1, u2) -> Double.compare(calculateCombatOdds(u1, u2).win,
|
|
calculateCombatOdds(u2, u1).win);
|
|
}
|
|
|
|
/**
|
|
* Calculates the chance of the outcomes of a combat.
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return The {@code CombatOdds}.
|
|
*/
|
|
public abstract CombatOdds calculateCombatOdds(FreeColGameObject attacker,
|
|
FreeColGameObject defender);
|
|
|
|
/**
|
|
* Get the offensive power of a attacker wrt a defender.
|
|
*
|
|
* Null can be passed for the defender when only the attacker
|
|
* stats are required.
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return The offensive power.
|
|
*/
|
|
public abstract double getOffencePower(FreeColGameObject attacker,
|
|
FreeColGameObject defender);
|
|
|
|
/**
|
|
* Get the defensive power of a defender wrt an attacker.
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return The defensive power.
|
|
*/
|
|
public abstract double getDefencePower(FreeColGameObject attacker,
|
|
FreeColGameObject defender);
|
|
|
|
/**
|
|
* Collect all the offensive modifiers that apply to an attack.
|
|
*
|
|
* Null can be passed as the defender when only the attacker unit
|
|
* stats are required.
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return All the applicable offensive modifiers.
|
|
*/
|
|
public abstract Set<Modifier> getOffensiveModifiers(FreeColGameObject attacker,
|
|
FreeColGameObject defender);
|
|
|
|
/**
|
|
* Collect all defensive modifiers that apply to a unit defending
|
|
* against another.
|
|
*
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return All the applicable defensive modifiers.
|
|
*/
|
|
public abstract Set<Modifier> getDefensiveModifiers(FreeColGameObject attacker,
|
|
FreeColGameObject defender);
|
|
|
|
/**
|
|
* Generates a list of results of an attack. The first must be one
|
|
* of NO_RESULT, LOSE or WIN. The rest can be any other CombatResult
|
|
* suitable to the situation.
|
|
* To be called by the server only.
|
|
*
|
|
* @param random A pseudo-random number source.
|
|
* @param attacker The attacker.
|
|
* @param defender The defender.
|
|
* @return The results of the combat.
|
|
*/
|
|
public abstract CombatResult generateAttackResult(Random random,
|
|
FreeColGameObject attacker,
|
|
FreeColGameObject defender);
|
|
}
|