/*
* StatusMove.java
*
* Created on December 16, 2006, 1:25 PM
*
* This file is a part of Shoddy Battle.
* Copyright (C) 2006 Colin Fitzpatrick
*
* This program 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.
*
* This program 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 this program; if not, visit the Free Software Foundation, Inc.
* online at http://gnu.org.
*/
package org.pokenet.server.battle.mechanics.moves;
import java.util.Random;
import org.pokenet.server.battle.Pokemon;
import org.pokenet.server.battle.mechanics.BattleMechanics;
import org.pokenet.server.battle.mechanics.PokemonType;
import org.pokenet.server.battle.mechanics.statuses.SleepEffect;
import org.pokenet.server.battle.mechanics.statuses.StatusEffect;
/**
*
* @author Colin
*/
public class StatusMove extends PokemonMove {
private StatusEffect[] m_statuses;
private double[] m_chances;
private boolean[] m_attacker; // Does this status affect the attacker?
@SuppressWarnings("unused")
private boolean m_bug = false;
// Is this is a personal enhancement move?
private boolean m_personal = true;
/**
* Creates a new instance of StatusMove
*/
public StatusMove(PokemonType type,
int power,
double accuracy,
int pp,
StatusEffect[] statuses,
boolean[] attacker,
double[] chances) {
super(type, power, accuracy, pp);
m_statuses = statuses;
m_chances = chances;
m_attacker = attacker;
for (int i = 0; i < attacker.length; ++i) {
if (!attacker[i]) {
m_personal = false;
break;
}
}
if (power != 0) {
m_personal = false;
}
}
/**
* Attempt a hit. Personal enhancement moves never miss, but other status
* moves can.
*/
public boolean attemptHit(BattleMechanics mech, Pokemon user, Pokemon target) {
if (m_personal)
return true;
return super.attemptHit(mech, user, target);
}
public Object clone() {
StatusMove ret = (StatusMove)super.clone();
ret.m_statuses = (StatusEffect[])ret.m_statuses.clone();
ret.m_chances = (double[])ret.m_chances.clone();
ret.m_attacker = (boolean[])ret.m_attacker.clone();
for (int i = 0; i < m_statuses.length; ++i) {
ret.m_statuses[i] = (StatusEffect)ret.m_statuses[i].clone();
}
return ret;
}
public StatusEffect[] getEffects() {
return m_statuses;
}
public boolean isAttack() {
return !m_personal;
}
public boolean isDamaging() {
return (m_power != 0);
}
public boolean isBuggy() {
return ((m_statuses.length != m_chances.length)
|| (m_chances.length != m_attacker.length));
}
public boolean getAttacker(int i) {
return m_attacker[i];
}
/**
* Sets if a an effect affects the attacker.
*/
public void setAttacker(int idx, boolean attacker) {
if ((idx < 0) || (idx >= m_attacker.length)) return;
m_attacker[idx] = attacker;
}
/**
* Return whether this status effect can be successfully applied. This is
* very random and not logical at all.
*/
public boolean isEffective(Pokemon target) {
for (int i = 0; i < m_statuses.length; ++i) {
StatusEffect status = m_statuses[i];
// Exception 1: Non-special effects ignore type immunities.
if (status.getLock() != StatusEffect.SPECIAL_EFFECT_LOCK)
continue;
// Exception 2: Sleep ignores type immunities.
if (status instanceof SleepEffect)
continue;
// Exception 3: Wonder Guard pokemon ignore type immunities.
if (target.hasAbility("Wonder Guard"))
continue;
return false;
}
return true;
}
/**
* The rules for whether this move can hit are elaborate. If the move does
* damage then the normal type rules apply; if the move has no effect then
* it will not inflict statuses either. However, if the move does not
* do damage and does not inflict one of the SPECIAL_EFFECT_LOCK statuses
* then it can hit even types normally immune to the move's type.
* <br /><br />
* Two intrinsic abilities also affect this method. If the user has
* Serene Grace then the chance of each effect being applied is double. If
* the target has Shield Dust then none of the effects can be applied to it
* so long as the move does damage.
*/
public int use(BattleMechanics mech, Pokemon user, Pokemon target) {
int damage = 0;
boolean hasSubstitute = target.hasSubstitute();
final boolean ineffective = (getEffectiveness(user, target) == 0.0);
if (m_power != 0) {
damage = mech.calculateDamage(this, user, target);
target.changeHealth(-damage);
if (ineffective) {
return 0;
}
} else if (!m_personal && ineffective && !isEffective(target)) {
user.getField().showMessage("It doesn't affect "
+ target.getName() + "...");
return 0;
}
final boolean serene = user.hasAbility("Serene Grace");
final boolean immune = (target.hasAbility("Shield Dust") && (m_power != 0));
Random random = mech.getRandom();
for (int i = 0; i < m_statuses.length; ++i) {
if (!m_attacker[i] && immune) {
continue;
}
double chance = m_chances[i];
if (serene) {
chance *= 2.0;
}
if (random.nextDouble() <= chance) {
Pokemon affected = (m_attacker[i] ? user : target);
if ((user != affected) && hasSubstitute && !m_statuses[i].hitsThroughSubstitute()) {
if (m_power == 0) {
user.getField().showMessage("But it failed!");
}
continue;
}
if (affected.addStatus(user, m_statuses[i]) == null) {
if (m_power == 0) {
// Only show the message if it is a primary effect.
m_statuses[i].informDuplicateEffect(affected);
}
}
}
}
return damage;
}
}