package com.asteria.game.character.combat;
import com.asteria.game.NodeType;
import com.asteria.game.character.Animation;
import com.asteria.game.character.AnimationPriority;
import com.asteria.game.character.CharacterNode;
import com.asteria.game.character.Graphic;
import com.asteria.game.character.Hit;
import com.asteria.game.character.combat.prayer.CombatPrayer;
import com.asteria.game.character.npc.Npc;
import com.asteria.game.character.player.Player;
import com.asteria.game.character.player.minigame.MinigameHandler;
import com.asteria.game.character.player.skill.Skills;
import com.asteria.game.item.Item;
import com.asteria.game.item.ItemNode;
import com.asteria.game.item.ItemNodeManager;
import com.asteria.game.location.Location;
import com.asteria.task.Task;
import com.asteria.utility.RandomGen;
/**
* An attack on the builder's victim that is sent completely separate from the
* main combat session.
*
* @author lare96 <http://github.com/lare96>
*/
public final class CombatSessionAttack extends Task {
/**
* The random generator instance that will generate random numbers.
*/
private final RandomGen random = new RandomGen();
/**
* The builder this attack is executed for.
*/
private final CombatBuilder builder;
/**
* The combat data from the combat session.
*/
private CombatSessionData data;
/**
* The total amount of damage dealt during this attack.
*/
private int counter;
/**
* Creates a new {@link CombatSessionAttack}.
*
* @param builder
* the builder this attack is executed for.
* @param data
* the combat data from the combat session.
*/
public CombatSessionAttack(CombatBuilder builder, CombatSessionData data) {
super(Combat.getDelay(data.getType()), data.getType() == CombatType.MELEE);
this.builder = builder;
this.data = data;
}
@Override
public void execute() {
CharacterNode attacker = builder.getCharacter();
CharacterNode victim = builder.getVictim();
if (attacker == null || victim == null || attacker.isDead() || !attacker.isRegistered() || victim.isDead() || !victim
.isRegistered()) {
this.cancel();
return;
}
data = data.preAttack();
if (data.getHits().length != 0 && data.getType() != CombatType.MAGIC || data.isAccurate()) {
victim.getCombatBuilder().getDamageCache().add(attacker, (counter = data.attack()));
}
if (!data.isAccurate()) {
if (data.getType() == CombatType.MAGIC) {
victim.graphic(new Graphic(85));
attacker.getCurrentlyCasting().executeOnHit(attacker, victim, false, 0);
attacker.setCurrentlyCasting(null);
}
} else if (data.isAccurate()) {
handleArmorEffects();
handlePrayerEffects();
attacker.onSuccessfulHit(victim, data.getType());
if (data.getType() == CombatType.MAGIC) {
attacker.getCurrentlyCasting().endGraphic().ifPresent(victim::graphic);
attacker.getCurrentlyCasting().executeOnHit(attacker, victim, true, counter);
attacker.setCurrentlyCasting(null);
} else if (data.getType() == CombatType.RANGED && attacker.getType() == NodeType.PLAYER && random.inclusive(2) == 0) {
Player player = (Player) attacker;
if (player.getFireAmmo() > 0) {
ItemNodeManager.register(new ItemNode(new Item(player.getFireAmmo()), victim.getPosition(), player), true);
player.setFireAmmo(0);
}
}
}
if (victim.getType() == NodeType.PLAYER) {
victim.animation(new Animation(404, AnimationPriority.LOW));
} else if (victim.getType() == NodeType.NPC) {
victim.animation(new Animation(((Npc) victim).getDefinition().getDefenceAnimation(), AnimationPriority.LOW));
}
data.postAttack(counter);
if (victim.isAutoRetaliate() && !victim.getCombatBuilder().isAttacking()) {
victim.getCombatBuilder().attack(attacker);
}
this.cancel();
}
/**
* Handles all armor effects that take place upon a successful attack.
*/
private void handleArmorEffects() {
if (random.get().nextInt(4) == 0) {
if (Combat.isFullGuthans(builder.getCharacter())) {
builder.getVictim().graphic(new Graphic(398));
builder.getCharacter().healCharacter(counter);
return;
}
if (builder.getVictim().getType() == NodeType.PLAYER) {
Player victim = (Player) builder.getVictim();
if (Combat.isFullTorags(builder.getCharacter())) {
victim.getRunEnergy().decrementAndGet(random.inclusive(1, 100));
victim.graphic(new Graphic(399));
} else if (Combat.isFullAhrims(builder.getCharacter()) && victim.getSkills()[Skills.STRENGTH].getLevel() >= victim
.getSkills()[Skills.STRENGTH].getRealLevel()) {
victim.getSkills()[Skills.STRENGTH].decreaseLevel(random.inclusive(1, 10));
Skills.refresh(victim, Skills.STRENGTH);
victim.graphic(new Graphic(400));
} else if (Combat.isFullKarils(builder.getCharacter()) && victim.getSkills()[Skills.AGILITY].getLevel() >= victim
.getSkills()[Skills.AGILITY].getRealLevel()) {
victim.graphic(new Graphic(401));
victim.getSkills()[Skills.AGILITY].decreaseLevel(random.inclusive(1, 10));
Skills.refresh(victim, Skills.AGILITY);
}
}
}
}
/**
* Handles all prayer effects that take place upon a successful attack.
*/
private void handlePrayerEffects() {
if (builder.getVictim().getType() == NodeType.PLAYER && data.getHits().length != 0) {
Player victim = (Player) builder.getVictim();
if (CombatPrayer.isActivated(victim, CombatPrayer.REDEMPTION) && victim.getSkills()[Skills.HITPOINTS].getLevel() <= (victim
.getSkills()[Skills.HITPOINTS].getRealLevel() / 10)) {
int heal = (int) (victim.getSkills()[Skills.HITPOINTS].getRealLevel() * CombatConstants.REDEMPTION_PRAYER_HEAL);
victim.getSkills()[Skills.HITPOINTS].increaseLevel(random.inclusive(1, heal));
victim.graphic(new Graphic(436));
victim.getSkills()[Skills.PRAYER].setLevel(0, true);
victim.getMessages().sendMessage("You've run out of prayer " + "points!");
CombatPrayer.deactivateAll(victim);
Skills.refresh(victim, Skills.PRAYER);
Skills.refresh(victim, Skills.HITPOINTS);
return;
}
if (builder.getCharacter().getType() == NodeType.PLAYER) {
if (CombatPrayer.isActivated(victim, CombatPrayer.RETRIBUTION) && victim.getSkills()[Skills.HITPOINTS].getLevel() < 1) {
victim.graphic(new Graphic(437));
if (Location.inWilderness(victim) || MinigameHandler.contains(victim) && !Location.inMultiCombat(victim)) {
if (builder.getCharacter().getPosition().withinDistance(victim.getPosition(), CombatConstants.RETRIBUTION_RADIUS)) {
builder.getCharacter().damage(new Hit(random.inclusive(CombatConstants.MAXIMUM_RETRIBUTION_DAMAGE)));
}
} else if (Location.inWilderness(victim) || MinigameHandler.contains(victim) && Location.inMultiCombat(victim)) {
for (Player player : victim.getLocalPlayers()) {
if (player == null) {
continue;
}
if (!player.equals(victim) && player.getPosition().withinDistance(victim.getPosition(),
CombatConstants.RETRIBUTION_RADIUS)) {
player.damage(new Hit(random.inclusive(CombatConstants.MAXIMUM_RETRIBUTION_DAMAGE)));
}
}
}
}
if (CombatPrayer.isActivated((Player) builder.getCharacter(), CombatPrayer.SMITE)) {
victim.getSkills()[Skills.PRAYER].decreaseLevel(counter / 4);
Skills.refresh(victim, Skills.PRAYER);
}
}
}
}
}