package com.asteria.game.character.combat.weapon;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import com.asteria.game.NodeType;
import com.asteria.game.World;
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.MovementQueue;
import com.asteria.game.character.Projectile;
import com.asteria.game.character.combat.Combat;
import com.asteria.game.character.combat.CombatSessionData;
import com.asteria.game.character.combat.CombatType;
import com.asteria.game.character.player.Player;
import com.asteria.game.character.player.content.WeaponInterface;
import com.asteria.game.character.player.skill.Skills;
import com.asteria.game.item.container.Equipment;
import com.asteria.game.location.Location;
import com.asteria.task.Task;
/**
* The enumerated type whose elements represent the combat special attacks.
*
* @author lare96 <http://github.com/lare96>
*/
public enum CombatSpecial {
DRAGON_DAGGER(new int[] { 1215, 1231, 5680, 5698 }, 25, 1.15, 1.25, CombatType.MELEE, WeaponInterface.DAGGER) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1062, AnimationPriority.HIGH));
player.highGraphic(new Graphic(252));
return new CombatSessionData(player, target, 2, CombatType.MELEE, true);
}
},
GRANITE_MAUL(new int[] { 4153 }, 50, 1.5, 1, CombatType.MELEE, WeaponInterface.WARHAMMER) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1667, AnimationPriority.HIGH));
player.highGraphic(new Graphic(337));
return new CombatSessionData(player, target, 1, CombatType.MELEE, true);
}
},
ABYSSAL_WHIP(new int[] { 4151 }, 50, 1, 1, CombatType.MELEE, WeaponInterface.WHIP) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1658, AnimationPriority.HIGH));
target.highGraphic(new Graphic(341));
return new CombatSessionData(player, target, 1, CombatType.MELEE, false);
}
},
DRAGON_LONGSWORD(new int[] { 1305 }, 25, 1.25, 1.25, CombatType.MELEE, WeaponInterface.LONGSWORD) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1058, AnimationPriority.HIGH));
player.highGraphic(new Graphic(248));
return new CombatSessionData(player, target, 1, CombatType.MELEE, true);
}
},
MAGIC_SHORTBOW(new int[] { 861 }, 50, 1, 1.1, CombatType.RANGED, WeaponInterface.SHORTBOW) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(426, AnimationPriority.HIGH));
player.highGraphic(new Graphic(250));
new Projectile(player, target, 249, 44, 3, 43, 31, 0).sendProjectile();
World.submit(new Task(1, false) {
@Override
public void execute() {
player.animation(new Animation(426, AnimationPriority.HIGH));
player.highGraphic(new Graphic(250));
new Projectile(player, target, 249, 44, 3, 43, 31, 0).sendProjectile();
this.cancel();
}
});
return new CombatSessionData(player, target, 2, CombatType.RANGED, true);
}
},
MAGIC_LONGBOW(new int[] { 859 }, 35, 1, 5, CombatType.RANGED, WeaponInterface.LONGBOW) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(426, AnimationPriority.HIGH));
player.highGraphic(new Graphic(250));
new Projectile(player, target, 249, 44, 3, 43, 31, 0).sendProjectile();
return new CombatSessionData(player, target, 1, CombatType.RANGED, true);
}
},
DRAGON_BATTLEAXE(new int[] { 1377 }, 100, 1, 1, CombatType.MELEE, WeaponInterface.BATTLEAXE) {
@Override
public void onActivation(Player player, CharacterNode target) {
int newStrength = (int) (player.getSkills()[Skills.STRENGTH].getRealLevel() * 0.2);
int newAttack = (int) (player.getSkills()[Skills.ATTACK].getRealLevel() * 0.1);
int newDefence = (int) (player.getSkills()[Skills.DEFENCE].getRealLevel() * 0.1);
int newRanged = (int) (player.getSkills()[Skills.RANGED].getRealLevel() * 0.1);
int newMagic = (int) (player.getSkills()[Skills.MAGIC].getRealLevel() * 0.1);
player.graphic(new Graphic(246));
player.animation(new Animation(1056));
player.forceChat("Raarrrrrgggggghhhhhhh!");
player.getSkills()[Skills.STRENGTH].increaseLevelReal(newStrength);
player.getSkills()[Skills.ATTACK].decreaseLevelReal(newAttack);
player.getSkills()[Skills.DEFENCE].decreaseLevelReal(newDefence);
player.getSkills()[Skills.RANGED].decreaseLevelReal(newRanged);
player.getSkills()[Skills.MAGIC].decreaseLevelReal(newMagic);
Skills.refresh(player, Skills.STRENGTH);
Skills.refresh(player, Skills.ATTACK);
Skills.refresh(player, Skills.DEFENCE);
Skills.refresh(player, Skills.RANGED);
Skills.refresh(player, Skills.MAGIC);
player.getCombatBuilder().cooldown(true);
CombatSpecial.drain(player, DRAGON_BATTLEAXE.amount);
}
@Override
public CombatSessionData container(Player player, CharacterNode target) {
throw new UnsupportedOperationException("Dragon battleaxe does " + "not have a special attack!");
}
},
DRAGON_SPEAR(new int[] { 1249, 1263, 5716, 5730 }, 25, 1, 1, CombatType.MELEE, WeaponInterface.SPEAR) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1064, AnimationPriority.HIGH));
player.graphic(new Graphic(253));
return new CombatSessionData(player, target, 1, CombatType.MELEE, true) {
@Override
public void postAttack(int counter) {
if (target.getType() == NodeType.PLAYER) {
target.getMovementQueue().walk(MovementQueue.DIRECTION_DELTA_X[player.getLastDirection()],
MovementQueue.DIRECTION_DELTA_Y[player.getLastDirection()]);
}
target.graphic(new Graphic(80));
target.getMovementListener().append(() -> target.freeze(6));
}
};
}
},
DRAGON_MACE(new int[] { 1434 }, 25, 1.45, 0.9, CombatType.MELEE, WeaponInterface.MACE) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1060, AnimationPriority.HIGH));
player.highGraphic(new Graphic(251));
return new CombatSessionData(player, target, 1, CombatType.MELEE, true);
}
},
DRAGON_SCIMITAR(new int[] { 4587 }, 55, 1, 1, CombatType.MELEE, WeaponInterface.SCIMITAR) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1872, AnimationPriority.HIGH));
player.highGraphic(new Graphic(347));
return new CombatSessionData(player, target, 1, CombatType.MELEE, true);
}
},
DRAGON_2H_SWORD(new int[] { 7158 }, 60, 1, 1, CombatType.MELEE, WeaponInterface.TWO_HANDED_SWORD) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(3157, AnimationPriority.HIGH));
player.graphic(new Graphic(559));
return new CombatSessionData(player, target, 1, CombatType.MELEE, false) {
@Override
public void postAttack(int counter) {
if (Location.inMultiCombat(player)) {
Set<? extends CharacterNode> local = null;
if (target.getType() == NodeType.PLAYER) {
local = player.getLocalPlayers();
} else if (target.getType() == NodeType.NPC) {
local = player.getLocalNpcs();
}
for (CharacterNode character : local) {
if (character == null) {
continue;
}
if (character.getPosition().withinDistance(target.getPosition(), 1) && !character.equals(target) && !character
.equals(player) && character.getCurrentHealth() > 0 && !character.isDead()) {
Hit hit = Combat.calculateRandomHit(player, target, CombatType.MELEE);
character.damage(hit);
character.getCombatBuilder().getDamageCache().add(player, hit.getDamage());
}
}
}
}
};
}
},
DRAGON_HALBERD(new int[] { 3204 }, 30, 1.1, 1, CombatType.MELEE, WeaponInterface.HALBERD) {
@Override
public CombatSessionData container(Player player, CharacterNode target) {
player.animation(new Animation(1203, AnimationPriority.HIGH));
player.highGraphic(new Graphic(282));
return new CombatSessionData(player, target, 2, CombatType.MELEE, true);
}
};
/**
* The identifiers for the weapons that perform this special.
*/
private final int[] ids;
/**
* The amount of special energy drained by this attack.
*/
private final int amount;
/**
* The strength bonus added when performing this special attack.
*/
private final double strength;
/**
* The accuracy bonus added when performing this special attack.
*/
private final double accuracy;
/**
* The combat type used when performing this special attack.
*/
private final CombatType combat;
/**
* The weapon type used when performing this special attack.
*/
private final WeaponInterface weapon;
/**
* Creates a new {@link CombatSpecial}.
*
* @param ids
* the identifiers for the weapons that perform this special.
* @param amount
* the amount of special energy drained by this attack.
* @param strength
* the strength bonus added when performing this special attack.
* @param accuracy
* the accuracy bonus added when performing this special attack.
* @param combat
* the combat type used when performing this special attack.
* @param weapon
* the weapon type used when performing this special attack.
*/
private CombatSpecial(int[] ids, int amount, double strength, double accuracy, CombatType combat, WeaponInterface weapon) {
this.ids = ids;
this.amount = amount;
this.strength = strength;
this.accuracy = accuracy;
this.combat = combat;
this.weapon = weapon;
}
/**
* Executes exactly when {@code player} activates the special bar.
*
* @param player
* the player who activated the special bar.
* @param target
* the target when activating the special attack bar, will be
* {@code null} if the player is not in combat.
*/
public void onActivation(Player player, CharacterNode target) {
}
/**
* The combat data that will be used to make an attack on {@code target}.
*
* @param player
* the player who is making an attack.
* @param target
* the main target of the attack.
* @return the combat data.
*/
public abstract CombatSessionData container(Player player, CharacterNode target);
/**
* Drains the special bar for {@code player}.
*
* @param player
* the player who's special bar will be drained.
* @param amount
* the amount of energy to drain from the special bar.
*/
public static void drain(Player player, int amount) {
player.getSpecialPercentage().decrementAndGet(amount, 0);
CombatSpecial.updateSpecialAmount(player);
player.getMessages().sendByteState(301, 0);
player.setSpecialActivated(false);
}
/**
* Restores the special bar for {@code player}.
*
* @param player
* the player who's special bar will be restored.
* @param amount
* the amount of energy to restore to the special bar.
*/
public static void restore(Player player, int amount) {
player.getSpecialPercentage().incrementAndGet(amount, 100);
CombatSpecial.updateSpecialAmount(player);
}
/**
* Updates the special bar with the amount of special energy {@code player}
* has.
*
* @param player
* the player who's special bar will be updated.
*/
public static void updateSpecialAmount(Player player) {
if (player.getWeapon().getSpecialBar() == -1 || player.getWeapon().getSpecialMeter() == -1) {
return;
}
int specialCheck = 10;
int specialBar = player.getWeapon().getSpecialMeter();
int specialAmount = player.getSpecialPercentage().get() / 10;
for (int i = 0; i < 10; i++) {
player.getMessages().sendUpdateSpecial(--specialBar, specialAmount >= specialCheck ? 500 : 0);
specialCheck--;
}
}
/**
* Updates the weapon interface with a special bar if needed.
*
* @param player
* the player to update the interface for.
*/
public static void assign(Player player) {
if (player.getWeapon().getSpecialBar() == -1) {
player.setCombatSpecial(null);
return;
}
Optional<CombatSpecial> special = Arrays.stream(CombatSpecial.values()).filter(
c -> Arrays.stream(c.getIds()).anyMatch(id -> player.getEquipment().getId(Equipment.WEAPON_SLOT) == id)).findFirst();
if (special.isPresent()) {
player.getMessages().sendInterfaceLayer(player.getWeapon().getSpecialBar(), false);
player.setCombatSpecial(special.get());
return;
}
player.getMessages().sendInterfaceLayer(player.getWeapon().getSpecialBar(), true);
player.setCombatSpecial(null);
}
/**
* Gets the identifiers for the weapons that perform this special.
*
* @return the identifiers for the weapons.
*/
public final int[] getIds() {
return ids;
}
/**
* Gets the amount of special energy drained by this attack.
*
* @return the amount of special energy drained.
*/
public final int getAmount() {
return amount;
}
/**
* Gets the strength bonus added when performing this special attack.
*
* @return the strength bonus.
*/
public final double getStrength() {
return strength;
}
/**
* Gets the accuracy bonus added when performing this special attack.
*
* @return the accuracy bonus.
*/
public final double getAccuracy() {
return accuracy;
}
/**
* Gets the combat type used when performing this special attack.
*
* @return the combat type.
*/
public final CombatType getCombat() {
return combat;
}
/**
* Gets the weapon type used when performing this special attack.
*
* @return the weapon type.
*/
public final WeaponInterface getWeapon() {
return weapon;
}
}