package com.asteria.game.character.combat;
import com.asteria.game.NodeType;
import com.asteria.game.character.CharacterNode;
import com.asteria.game.character.Hit;
import com.asteria.game.character.player.Player;
import com.google.common.base.Preconditions;
/**
* The container that holds data for an entire combat session attack.
*
* @author lare96 <http://github.com/lare96>
*/
public class CombatSessionData {
/**
* The attacker in this combat session.
*/
private final CharacterNode attacker;
/**
* The victim in this combat session.
*/
private final CharacterNode victim;
/**
* The hits that will be sent when the attacker attacks.
*/
private final CombatHit[] hits;
/**
* The skills that experience will be given to.
*/
private final int[] experience;
/**
* The combat type the attacker is using.
*/
private final CombatType type;
/**
* The flag that determines if accuracy should be taken into account.
*/
private final boolean checkAccuracy;
/**
* The flag that determines if at least one hit is accurate.
*/
private boolean accurate;
/**
* Creates a new {@link CombatSessionData}.
*
* @param attacker
* the attacker in this combat session.
* @param victim
* the victim in this combat session.
* @param amount
* the amount of hits to calculate.
* @param type
* the combat type the attacker is using.
* @param checkAccuracy
* determines if accuracy should be calculated for hits.
*/
public CombatSessionData(CharacterNode attacker, CharacterNode victim, int amount, CombatType type, boolean checkAccuracy) {
this.attacker = attacker;
this.victim = victim;
this.type = type;
this.checkAccuracy = checkAccuracy;
this.hits = calculateHits(amount);
this.experience = determineExperience();
}
/**
* Creates a new {@link CombatSessionData} with an {@code amount} of
* {@code 0}.
*
* @param attacker
* the attacker in this combat session.
* @param victim
* the victim in this combat session.
* @param type
* the combat type the attacker is using.
* @param checkAccuracy
* determines if accuracy should be calculated for hits.
*/
public CombatSessionData(CharacterNode attacker, CharacterNode victim, CombatType type, boolean checkAccuracy) {
this(attacker, victim, 0, type, checkAccuracy);
}
/**
* Calculates all of the hits that will be dealt before the attack is
* launched.
*
* @param amount
* the amount of hits to calculate, with minimum of {@code 0} and
* a maximum of {@code 1}.
* @return an array of the calculated hits.
*/
private final CombatHit[] calculateHits(int amount) {
Preconditions.checkArgument(amount >= 0 && amount <= 4);
if (amount == 0) {
accurate = calculateAccuracy();
return new CombatHit[] {};
}
CombatHit[] array = new CombatHit[amount];
for (int i = 0; i < array.length; i++) {
array[i] = new CombatHit(Combat.calculateRandomHit(attacker, victim, type), calculateAccuracy());
if (array[i].isAccurate())
accurate = true;
}
return array;
}
/**
* Determines if a hit is accurate or not. This method may return different
* values if called multiple times.
*
* @return {@code true} if the hit is accurate, {@code false} otherwise.
*/
private final boolean calculateAccuracy() {
return checkAccuracy ? Combat.isAccurate(attacker, victim, type) : true;
}
/**
* Launches all of the damage concealed within this container.
*
* @return the amount of damage that was dealt.
*/
public final int attack() {
Combat.applyPrayerEffects(this);
int counter = 0;
int index = 0;
Hit[] container = new Hit[hits.length];
for (CombatHit hit : hits) {
if (!hit.isAccurate())
hit.setHit(new Hit(0));
counter += hit.getHit().getDamage();
container[index++] = hit.getHit();
}
if (hits.length > 0) {
victim.damage(container);
}
Combat.handleExperience(attacker.getCombatBuilder(), this, counter);
return counter;
}
/**
* Determines which skills will be given experience based on the combat
* type.
*
* @return an array of skills that will be given experience for this attack.
*/
private final int[] determineExperience() {
return attacker.getType() == NodeType.NPC ? new int[] {} : ((Player) attacker).getFightType().getStyle().skills(type);
}
/**
* The method that can be overridden to do any last second modifications to
* the container before hits are dealt to the victim.
*
* @return the modified combat session data container.
*/
public CombatSessionData preAttack() {
return this;
}
/**
* The method that can be overridden to do any post-attack effects to the
* victim. Do <b>not</b> reset the combat builder here!
*
* @param counter
* the amount of damage this attack inflicted, always {@code 0}
* if the attack was inaccurate.
*/
public void postAttack(int counter) {
}
/**
* Gets the attacker in this combat session.
*
* @return the attacker.
*/
public final CharacterNode getAttacker() {
return attacker;
}
/**
* Gets the victim in this combat session.
*
* @return the victim.
*/
public final CharacterNode getVictim() {
return victim;
}
/**
* Determines if at least one hit in this container is accurate.
*
* @return {@code true} if one hit is accurate, {@code false} otherwise.
*/
public final boolean isAccurate() {
return accurate;
}
/**
* Sets the value for {@link CombatSessionData#accurate}.
*
* @param accurate
* the new value to set.
*/
public final void setAccurate(boolean accurate) {
this.accurate = accurate;
}
/**
* Gets the hits that will be sent when the attacker attacks.
*
* @return the hits that will be sent.
*/
public final CombatHit[] getHits() {
return hits;
}
/**
* Gets the skills that experience will be given to.
*
* @return the skills for experience.
*/
public final int[] getExperience() {
return experience;
}
/**
* Gets the combat type the attacker is using.
*
* @return the combat type.
*/
public final CombatType getType() {
return type;
}
/**
* Determines if accuracy should be taken into account.
*
* @return {@code true} if accuracy should be calculated, {@code false}
* otherwise.
*/
public final boolean isCheckAccuracy() {
return checkAccuracy;
}
}