package net.scapeemulator.game.model.mob.combat;
import net.scapeemulator.game.model.mob.Animation;
import net.scapeemulator.game.model.mob.Mob;
import net.scapeemulator.game.model.player.skills.magic.CombatSpell;
import net.scapeemulator.game.model.player.skills.magic.DamageSpell;
public abstract class CombatHandler<T extends Mob> {
protected final T mob;
protected Mob target;
protected DamageSpell autoCast;
protected CombatSpell nextSpell;
protected AttackStyle attackStyle;
private AttackType attackType;
protected int noRetaliate;
/**
* The delay (in ticks) until the next attack can be administered.
*/
protected int combatDelay;
public CombatHandler(T mob) {
this.mob = mob;
}
public void tick() {
if (combatDelay > 0) {
combatDelay--;
}
if (noRetaliate > 0) {
noRetaliate--;
}
}
public void initiate(Mob target) {
if (nextSpell == null && autoCast != null) {
nextSpell = autoCast;
}
mob.turnToTarget(target);
this.target = target;
}
public void hitTarget(int damage) {
hit(target, damage);
}
public void hit(Mob other, int damage) {
other.processHit(mob, damage);
}
public void reset() {
target = null;
nextSpell = autoCast;
}
/**
* Gets the attack type (SLASH, STAB, CRUSH, RANGE, MAGIC) of the next
* attack.
*/
public AttackType getNextAttackType() {
if (nextSpell != null) {
return AttackType.MAGIC;
}
return attackType;
}
/**
* Sets the attack type (SLASH, STAB, CRUSH, RANGE) currently selected in
* the attack tab, not taking into account potential spellcasting.
*/
public void setRawAttackType(AttackType attackType) {
if (attackType == AttackType.MAGIC) {
throw new IllegalArgumentException("Cannot set attackType to magic, use nextSpell and autoCast instead");
}
this.attackType = attackType;
}
/**
* Gets the attack type (SLASH, STAB, CRUSH, RANGE) currently selected in
* the attack tab, not taking into account potential spellcasting.
*/
public AttackType getRawAttackType() {
return attackType;
}
public void setNoRetaliate(int delay) {
noRetaliate = delay;
}
public int getNoRetaliate() {
return noRetaliate;
}
public void setNextSpell(CombatSpell nextSpell) {
this.nextSpell = nextSpell;
}
public DamageSpell getAutoCast() {
return autoCast;
}
public void setAutoCast(DamageSpell autoCast) {
this.autoCast = autoCast;
nextSpell = autoCast;
}
public abstract boolean canAttack(Mob target);
public abstract boolean attack();
public abstract int attackRoll();
public abstract int defenceRoll(AttackType other);
protected boolean shouldHit() {
double attackRoll = attackRoll();
double defRoll = target.getCombatHandler().defenceRoll(attackType);
double accuracy;
if (attackRoll > defRoll) {
accuracy = 1.0 - ((defRoll + 2.0) / (2.0 * (attackRoll + 1.0)));
} else {
accuracy = attackRoll / (2 * (defRoll + 1));
}
return accuracy > Math.random();
}
/**
* The attack range this mob has, taking into account active spells and
* range weapons.
*
* @return this mobs attack range
*/
public abstract int getAttackRange();
/**
* Whether or not a mob should retaliate an attack at the given time, taking
* into account current combat status and things like retaliation cooldown
* timers for retreat.
*
* @return if this mob should retaliate
*/
public abstract boolean shouldRetaliate();
public abstract Animation getDefendAnimation();
}