package com.asteria.game.character.combat;
import java.util.Optional;
import com.asteria.game.NodeType;
import com.asteria.game.World;
import com.asteria.game.character.combat.weapon.CombatSpecial;
import com.asteria.game.character.npc.Npc;
import com.asteria.game.character.player.Player;
import com.asteria.game.character.player.minigame.Minigame;
import com.asteria.game.character.player.minigame.MinigameHandler;
import com.asteria.game.location.Location;
import com.asteria.task.Task;
/**
* The combat session controls the mechanics of when and how the controller of
* the builder will attack.
*
* @author lare96 <http://github.com/lare96>
*/
public final class CombatSession extends Task {
/**
* The builder assigned to this combat session.
*/
private final CombatBuilder builder;
/**
* Create a new {@link CombatSession}.
*
* @param builder
* the builder assigned to this combat session.
*/
public CombatSession(CombatBuilder builder) {
super(1, false);
super.attach(builder.getCharacter().getType() == NodeType.PLAYER ? ((Player) builder.getCharacter()) : ((Npc) builder
.getCharacter()));
this.builder = builder;
}
@Override
public void execute() {
if (builder.isCooldown()) {
builder.decrementCooldown();
builder.decrementAttackTimer();
if (builder.getCooldown() == 0)
builder.reset();
return;
}
if (!sessionCanAttack()) {
return;
}
if (builder.getCharacter().getType() == NodeType.PLAYER) {
builder.determineStrategy();
Player player = (Player) builder.getCharacter();
if (player.isSpecialActivated() && player.getCombatSpecial() == CombatSpecial.GRANITE_MAUL)
builder.clearAttackTimer();
}
builder.decrementAttackTimer();
if (builder.getAttackTimer() < 1) {
if (!Combat.checkAttackDistance(builder)) {
return;
}
if (!builder.getStrategy().canAttack(builder.getCharacter(), builder.getVictim())) {
return;
}
CombatSessionData data = builder.getStrategy().attack(builder.getCharacter(), builder.getVictim());
if (builder.getCharacter().getType() == NodeType.PLAYER) {
Player player = (Player) builder.getCharacter();
player.getMessages().sendCloseWindows();
if (player.isSpecialActivated() && player.getCastSpell() == null) {
data = player.getCombatSpecial().container(player, builder.getVictim());
CombatSpecial.drain(player, player.getCombatSpecial().getAmount());
}
}
if (data.getType() != null) {
builder.getVictim().getCombatBuilder().setLastAttacker(builder.getCharacter());
builder.getVictim().getLastCombat().reset();
if (data.getType() == CombatType.MAGIC && builder.getCharacter().getType() == NodeType.PLAYER) {
Player player = (Player) builder.getCharacter();
if (player.getCastSpell() != null && player.getAutocastSpell() != null || player.getAutocastSpell() == null) {
if (!player.isSpecialActivated())
player.getCombatBuilder().cooldown(false);
player.setCastSpell(null);
player.setFollowing(false);
builder.determineStrategy();
}
}
World.submit(new CombatSessionAttack(builder, data));
}
builder.resetAttackTimer();
builder.getCharacter().faceCharacter(builder.getVictim());
}
}
/**
* Determines if the combat session can continue on, this method is invoked
* before the attack timers are evaluated.
*
* @return {@code true} if this combat session can continue on,
* {@code false} otherwise.
*/
private boolean sessionCanAttack() {
if (!builder.getVictim().isRegistered() || !builder.getCharacter().isRegistered() || builder.getCharacter().isDead() || builder
.getVictim().isDead()) {
builder.reset();
return false;
}
if (builder.getVictim().getType() == NodeType.PLAYER) {
if (((Player) builder.getVictim()).getTeleportStage() > 0) {
builder.cooldown(false);
return false;
}
}
if (!Location.inMultiCombat(builder.getCharacter()) && builder.isBeingAttacked() && !builder.getVictim().equals(
builder.getLastAttacker())) {
if (builder.getCharacter().getType() == NodeType.PLAYER)
((Player) builder.getCharacter()).getMessages().sendMessage("You are already under attack!");
builder.reset();
return false;
}
if (!Location.inMultiCombat(builder.getCharacter()) && builder.getVictim().getCombatBuilder().isBeingAttacked() && !builder
.getVictim().getCombatBuilder().getLastAttacker().equals(builder.getCharacter())) {
if (builder.getCharacter().getType() == NodeType.PLAYER)
((Player) builder.getCharacter()).getMessages().sendMessage("They are already under attack!");
builder.reset();
return false;
}
if (builder.getCharacter().getType() == NodeType.PLAYER) {
Player player = (Player) builder.getCharacter();
Optional<Minigame> optional = MinigameHandler.search(player);
if (optional.isPresent()) {
if (!optional.get().canHit(player, builder.getVictim())) {
return false;
}
} else if (Location.inWilderness(builder.getCharacter()) && !Location.inWilderness(builder.getVictim())) {
player.getMessages().sendMessage("They are not in the wilderness!");
builder.reset();
return false;
}
}
if (builder.getCharacter().getType() == NodeType.NPC) {
Npc npc = (Npc) builder.getCharacter();
if (builder.getVictim().getCombatBuilder().isCooldown() && !npc.getPosition().isViewableFrom(npc.getOriginalPosition()) || !builder
.getVictim().getCombatBuilder().isBeingAttacked() && !npc.getPosition().isViewableFrom(npc.getOriginalPosition())) {
builder.reset();
return false;
}
}
return true;
}
}