package org.pokenet.server.battle.mechanics.clauses;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.pokenet.server.battle.BattleField;
import org.pokenet.server.battle.Pokemon;
import org.pokenet.server.battle.mechanics.ModData;
import org.pokenet.server.battle.mechanics.moves.MoveListEntry;
import org.pokenet.server.battle.mechanics.moves.PokemonMove;
import org.pokenet.server.battle.mechanics.moves.StatusMove;
import org.pokenet.server.battle.mechanics.moves.MoveList.OneHitKillMove;
import org.pokenet.server.battle.mechanics.statuses.FreezeEffect;
import org.pokenet.server.battle.mechanics.statuses.SleepEffect;
import org.pokenet.server.battle.mechanics.statuses.StatChangeEffect;
import org.pokenet.server.battle.mechanics.statuses.StatusEffect;
import org.pokenet.server.battle.mechanics.statuses.field.FieldEffect;
import org.pokenet.server.battle.mechanics.statuses.items.HoldItem;
/**
* A rule applied to a battle.
*
* @author Colin
*/
public abstract class Clause extends FieldEffect {
@SuppressWarnings("unchecked")
public static class ClauseChoice implements Serializable, Comparable {
private static final long serialVersionUID = 1L;
private String m_name, m_description;
private boolean m_default, m_disablesSelection;
private transient Clause m_clause;
public ClauseChoice(Clause c) {
m_name = c.getClauseName();
m_description = c.getClauseDescription();
m_default = c.isEnabledByDefault();
m_disablesSelection = c.disablesTeamSelection();
m_clause = c;
}
public Clause getClause() {
return m_clause;
}
public int compareTo(Object o2) {
ClauseChoice c2 = (ClauseChoice)o2;
return m_name.compareToIgnoreCase(c2.m_name);
}
public String getName() {
return m_name;
}
public String getDescription() {
return m_description;
}
public boolean isEnabledByDefault() {
return m_default;
}
public boolean disablesTeamSelection() {
return m_disablesSelection;
}
}
private String m_name;
private static final Map<String, Clause> m_clauses = new HashMap<String, Clause>();
private static ClauseChoice[] m_clauseChoices;
static {
new EffectClause("Sleep Clause", SleepEffect.class) {
public String getClauseDescription() {
return "Only one pokemon on each team may be afflicted "
+ "with enemy-induced sleep at a given time. "
+ "Subsequent enemy attempts to inflict sleep fail.";
}
public boolean isEnabledByDefault() {
return true;
}
};
new EffectClause("Freeze Clause", FreezeEffect.class) {
public String getClauseDescription() {
return "Only one pokemon on each team may be afflicted "
+ "with freeze at a given time. "
+ "Subsequent uses of moves with a chance to freeze "
+ "will not freeze.";
}
};
new PendanticDamageClause();
new Clause("Item Clause") {
public String getClauseDescription() {
return "No two pokemon on a team may begin the battle "
+ "holding the same item.";
}
public boolean isTeamValid(BattleField field, Pokemon[] team, int idx) {
Set<String> set = new HashSet<String>();
for (int i = 0; i < team.length; ++i) {
if (team[i] == null)
continue;
HoldItem item = team[i].getItem();
if (item != null) {
if (!set.add(item.getName())) {
return false;
}
}
}
return true;
}
};
new Clause("Species Clause") {
public String getClauseDescription() {
return "No two pokemon on a team may have the same species.";
}
public boolean isTeamValid(BattleField field, Pokemon[] team, int idx) {
Set<String> set = new HashSet<String>();
for (int i = 0; i < team.length; ++i) {
if (team[i] == null)
continue;
if (!set.add(team[i].getSpeciesName())) {
return false;
}
}
return true;
}
public boolean isEnabledByDefault() {
return true;
}
};
new Clause("Random Battle") {
public String getClauseDescription() {
return "Instead of loading teams, both players use randomly "
+ "generated parties.";
}
public boolean isTeamValid(BattleField field, Pokemon[] team, int idx) {
for (int i = 0; i < team.length; ++i) {
if (team[i] != null) {
team[i].setItem(null);
team[i].setAbility(null, true);
}
team[i] = Pokemon.getRandomPokemon(
ModData.getDefaultData(), field.getMechanics());
}
field.attachField(idx);
return true;
}
public boolean disablesTeamSelection() {
return true;
}
public int getTier() {
return -2;
}
};
new Clause("OHKO Clause") {
public String getClauseDescription() {
return "Moves that kill in one hit (e.g. Fissure) fail.";
}
public boolean isMoveTransformer(boolean enemy) {
return !enemy;
}
protected MoveListEntry getTransformedMove(Pokemon p, MoveListEntry entry) {
if (entry.getMove() instanceof OneHitKillMove) {
BattleField field = p.getField();
field.informUseMove(p, entry.getName());
field.showMessage("But it failed!");
return null;
}
return entry;
}
};
new Clause("Level Balance") {
public String getClauseDescription() {
return "Multiplies 0.074 by a pokemon's base stat total "
+ "and subtracts the result from 113; the pokemon's "
+ "level is set to the integer nearest this value. "
+ "This gives each pokemon a level in the closed "
+ "interval [60, 100] based on its base stats.";
}
public boolean isTeamValid(BattleField field, Pokemon[] team, int idx) {
for (int i = 0; i < team.length; ++i) {
Pokemon p = team[i];
if (p != null) {
p.setLevel(p.getBalancedLevel());
p.calculateStats(true);
}
}
return true;
}
};
new Clause("Evasion Clause") {
public String getClauseDescription() {
return "Moves that specifically raise evasion (e.g. Double "
+ "Team) fail.";
}
public boolean isMoveTransformer(boolean enemy) {
return !enemy;
}
protected MoveListEntry getTransformedMove(Pokemon p, MoveListEntry entry) {
PokemonMove move = entry.getMove();
if (move instanceof StatusMove) {
StatusMove statusMove = (StatusMove)move;
StatusEffect[] effects = statusMove.getEffects();
boolean failure = false;
for (int i = 0; i < effects.length; ++i) {
if (!statusMove.getAttacker(i))
continue;
StatusEffect eff = effects[i];
if (eff instanceof StatChangeEffect) {
StatChangeEffect stat = (StatChangeEffect)eff;
if ((stat.getStat() == Pokemon.S_EVASION)
&& stat.isRaise()) {
failure = true;
break;
}
}
}
if (failure) {
BattleField field = p.getField();
field.informUseMove(p, entry.getName());
field.showMessage("But it failed!");
return null;
}
}
return entry;
}
};
initialiseClauseChoices();
}
@SuppressWarnings("unchecked")
private static void initialiseClauseChoices() {
m_clauseChoices = new ClauseChoice[m_clauses.size()];
int i = 0;
Iterator<Clause> j = m_clauses.values().iterator();
while (j.hasNext()) {
m_clauseChoices[i++] = new ClauseChoice((Clause)j.next());
}
Collections.sort(Arrays.asList(m_clauseChoices));
}
public static class PendanticDamageClause extends Clause {
public PendanticDamageClause() {
super("Strict Damage Clause");
}
public String getClauseDescription() {
return "By default, Shoddy Battle does not limit the display of "
+ "damage done to a pokemon to its remaining health. "
+ "Enabling this clause causes Shoddy Battle never to "
+ "show more damage being done than the target has "
+ "remaining health.";
}
}
public static Clause getInstance(String name) {
return (Clause)m_clauses.get(name);
}
public static ClauseChoice[] getClauses() {
return m_clauseChoices;
}
public Clause(String name) {
m_clauses.put(name, this);
m_name = name;
}
public String getClauseName() {
return m_name;
}
public boolean disablesTeamSelection() {
return false;
}
public boolean isEnabledByDefault() {
return false;
}
public int getTier() {
return -1;
}
public boolean isTeamValid(BattleField field, Pokemon[] team, int idx) {
return true;
}
public abstract String getClauseDescription();
public boolean applyToField(BattleField field) {
return true;
}
public boolean tickField(BattleField field) {
return false;
}
}