package be.isach.ultracosmetics.cosmetics.gadgets;
import be.isach.ultracosmetics.UltraCosmetics;
import be.isach.ultracosmetics.UltraCosmeticsData;
import be.isach.ultracosmetics.config.MessageManager;
import be.isach.ultracosmetics.config.SettingsManager;
import be.isach.ultracosmetics.cosmetics.Category;
import be.isach.ultracosmetics.cosmetics.Cosmetic;
import be.isach.ultracosmetics.cosmetics.Updatable;
import be.isach.ultracosmetics.cosmetics.type.GadgetType;
import be.isach.ultracosmetics.player.UltraPlayer;
import be.isach.ultracosmetics.util.*;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
import java.util.UUID;
/**
* Represents an instance of a Gadget summoned by a player.
*
* @author iSach
* @since 08-03-2015
*/
public abstract class Gadget extends Cosmetic<GadgetType> implements Updatable {
private static final DecimalFormatSymbols OTHER_SYMBOLS = new DecimalFormatSymbols(Locale.US);
private static final DecimalFormat DECIMAL_FORMAT;
static {
OTHER_SYMBOLS.setDecimalSeparator('.');
OTHER_SYMBOLS.setGroupingSeparator('.');
OTHER_SYMBOLS.setPatternSeparator('.');
DECIMAL_FORMAT = new DecimalFormat("0.0", OTHER_SYMBOLS);
}
/**
* Page the user was on when trying to buy ammo.
* Is used when player buys ammo from Gadget Menu.
*/
public int lastPage = 1;
/**
* If it should open Gadget Menu after purchase.
*/
public boolean openGadgetsInvAfterAmmo;
/**
* If true, it will differentiate left and right click.
*/
protected boolean useTwoInteractMethods;
/**
* Gadget ItemStack.
*/
protected ItemStack itemStack;
/**
* If true, will display cooldown left when fail on use
* because cooldown active.
*/
protected boolean displayCooldownMessage = true;
/**
* Last Clicked Block by the player.
*/
protected Block lastClickedBlock;
/**
* If true, it will affect players (velocity).
*/
protected boolean affectPlayers;
/**
* If Gadget interaction should tick asynchronously.
*/
private boolean asynchronous = false;
/**
* The Ammo Purchase inventory.
*/
private Inventory ammoInventory;
public Gadget(UltraPlayer owner, GadgetType type, UltraCosmetics ultraCosmetics) {
super(ultraCosmetics, Category.GADGETS, owner, type);
this.affectPlayers = type.affectPlayers();
this.useTwoInteractMethods = false;
}
@Override
protected void onEquip() {
if (getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).getCurrentGadget() != null) {
getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).removeGadget();
}
runTaskTimerAsynchronously(getUltraCosmetics(), 0, 1);
if (getPlayer().getInventory().getItem(ConfigUtils.getGadgetSlot()) != null) {
getPlayer().getWorld().dropItem(getPlayer().getLocation(),
getPlayer().getInventory().getItem(ConfigUtils.getGadgetSlot()));
getPlayer().getInventory().remove(ConfigUtils.getGadgetSlot());
}
String ammo = "";
if (UltraCosmeticsData.get().isAmmoEnabled() && getType().requiresAmmo()) {
ammo = ChatColor.WHITE + "" + ChatColor.BOLD + getOwner().getAmmo(getType().toString().toLowerCase()) + " ";
}
itemStack = ItemFactory.create(getType().getMaterial(), getType().getData(), ammo + getType().getName(),
MessageManager.getMessage("Gadgets.Lore"));
getPlayer().getInventory().setItem((int) SettingsManager.getConfig().get("Gadget-Slot"), itemStack);
getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).setCurrentGadget(this);
}
@Override
public void run() {
try {
if (getOwner() == null || getPlayer() == null) {
return;
}
if (getOwner().getCurrentGadget() != null && getOwner().getCurrentGadget().getType() == getType()) {
onUpdate();
try {
if (UltraCosmeticsData.get().displaysCooldownInBar()) {
if (getPlayer().getItemInHand() != null && itemStack != null && getPlayer().getItemInHand()
.hasItemMeta() && getPlayer().getItemInHand().getType() == getItemStack().getType()
&& getPlayer().getItemInHand().getData().getData() == getItemStack().getData().getData()
&& getPlayer().getItemInHand().getItemMeta().hasDisplayName() && getPlayer()
.getItemInHand().getItemMeta().getDisplayName().endsWith(getType().getName())
&& getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).canUse(getType())
!= -1) {
sendCooldownBar();
}
}
} catch (NullPointerException ignored) {
// Caused by rapid item switching in inventory.
}
if (getOwner() == null || getPlayer() == null) {
return;
}
double left = getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).canUse(getType());
if (left > -0.1) {
String leftRounded = DECIMAL_FORMAT.format(left);
double decimalRoundedValue = Double.parseDouble(leftRounded);
if (decimalRoundedValue == 0) {
String message = MessageManager.getMessage("Gadgets.Gadget-Ready-ActionBar");
message = message.replace("%gadgetname%",
TextUtil.filterPlaceHolder(getType().getName(), getUltraCosmetics()));
PlayerUtils.sendInActionBar(getPlayer(), message);
SoundUtil.playSound(getPlayer(), Sounds.NOTE_STICKS, 1.4f, 1.5f);
}
}
} else {
clear();
}
} catch (NullPointerException exc) {
clear();
exc.printStackTrace();
}
}
@Override
public void clear() {
removeItem();
super.clear();
}
/**
* Sends the current cooldown in action bar.
*/
private void sendCooldownBar() {
if (getOwner() == null)
return;
if (getPlayer() == null)
return;
StringBuilder stringBuilder = new StringBuilder();
double currentCooldown = getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).canUse(getType());
double maxCooldown = getType().getCountdown();
int res = (int) (currentCooldown / maxCooldown * 50);
ChatColor color;
for (int i = 0; i < 50; i++) {
color = ChatColor.RED;
if (i < 50 - res) {
color = ChatColor.GREEN;
}
stringBuilder.append(color + "┃");
}
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols(Locale.US);
otherSymbols.setDecimalSeparator('.');
otherSymbols.setGroupingSeparator('.');
otherSymbols.setPatternSeparator('.');
final DecimalFormat decimalFormat = new DecimalFormat("0.0", otherSymbols);
String timeLeft = decimalFormat.format(currentCooldown) + "s";
PlayerUtils.sendInActionBar(getPlayer(),
getType().getName() + ChatColor.WHITE + " " + stringBuilder.toString() + ChatColor.WHITE + " "
+ timeLeft);
}
/**
* Removes the item.
*/
public void removeItem() {
itemStack = null;
try {
getPlayer().getInventory().setItem((int) SettingsManager.getConfig().get("Gadget-Slot"), null);
} catch (Exception exc) {
}
}
/**
* Gets the price for each ammo purchase.
*
* @return the price for each ammo purchase.
*/
private int getPrice() {
return SettingsManager.getConfig().getInt("Gadgets." + getType().getConfigName() + ".Ammo.Price");
}
/**
* Gets the ammo it should give after a purchase.
*
* @return the ammo it should give after a purchase.
*/
private int getResultAmmoAmount() {
return SettingsManager.getConfig().getInt("Gadgets." + getType().getConfigName() + ".Ammo.Result-Amount");
}
/**
* Gets the gadget current Item Stack.
*
* @return
*/
public ItemStack getItemStack() {
return itemStack;
}
/**
* Opens Ammo Purchase Menu.
*/
public void openAmmoPurchaseMenu() {
Inventory inventory = Bukkit.createInventory(null, 54, MessageManager.getMessage("Menus.Buy-Ammo"));
inventory.setItem(13, ItemFactory.create(getType().getMaterial(), getType().getData(),
MessageManager.getMessage("Buy-Ammo-Description").replace("%amount%", "" + getResultAmmoAmount())
.replace("%price%", "" + getPrice()).replaceAll("%gadgetname%", getType().getName())));
for (int i = 27; i < 30; i++) {
inventory.setItem(i,
ItemFactory.create(Material.EMERALD_BLOCK, (byte) 0x0, MessageManager.getMessage("Purchase")));
inventory.setItem(i + 9,
ItemFactory.create(Material.EMERALD_BLOCK, (byte) 0x0, MessageManager.getMessage("Purchase")));
inventory.setItem(i + 18,
ItemFactory.create(Material.EMERALD_BLOCK, (byte) 0x0, MessageManager.getMessage("Purchase")));
inventory.setItem(i + 6,
ItemFactory.create(Material.REDSTONE_BLOCK, (byte) 0x0, MessageManager.getMessage("Cancel")));
inventory.setItem(i + 9 + 6,
ItemFactory.create(Material.REDSTONE_BLOCK, (byte) 0x0, MessageManager.getMessage("Cancel")));
inventory.setItem(i + 18 + 6,
ItemFactory.create(Material.REDSTONE_BLOCK, (byte) 0x0, MessageManager.getMessage("Cancel")));
}
ItemFactory.fillInventory(inventory);
getPlayer().openInventory(inventory);
this.ammoInventory = inventory;
}
protected boolean checkRequirements(PlayerInteractEvent event) {
return true;
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
if (event.getPlayer() == getPlayer() && ammoInventory != null && InventoryUtils
.areSame(event.getInventory(), ammoInventory)) {
ammoInventory = null;
openGadgetsInvAfterAmmo = false;
}
}
@EventHandler
public void onInventoryClickAmmo(final InventoryClickEvent event) {
if (getOwner() != null && getPlayer() != null && event.getWhoClicked() == getPlayer() && ammoInventory != null
&& InventoryUtils.areSame(event.getWhoClicked().getOpenInventory().getTopInventory(), ammoInventory)) {
event.setCancelled(true);
if (event.getCurrentItem() != null && event.getCurrentItem().hasItemMeta() && event.getCurrentItem()
.getItemMeta().hasDisplayName()) {
String displayName = event.getCurrentItem().getItemMeta().getDisplayName();
String purchase = MessageManager.getMessage("Purchase");
String cancel = MessageManager.getMessage("Cancel");
if (displayName.equals(purchase)) {
if (getUltraCosmetics().getPlayerManager().getUltraPlayer((Player) event.getWhoClicked())
.getBalance() >= getPrice()) {
getUltraCosmetics().getEconomy().withdrawPlayer((Player) event.getWhoClicked(), getPrice());
getUltraCosmetics().getPlayerManager().getUltraPlayer((Player) event.getWhoClicked())
.addAmmo(getType().toString().toLowerCase(), getResultAmmoAmount());
event.getWhoClicked().sendMessage(MessageManager.getMessage("Successful-Purchase"));
if (openGadgetsInvAfterAmmo)
Bukkit.getScheduler().runTaskLater(getUltraCosmetics(), () -> {
getUltraCosmetics().getMenus().getGadgetsMenu().open(getOwner(), lastPage);
openGadgetsInvAfterAmmo = false;
lastPage = 1;
}, 1);
} else {
getPlayer().sendMessage(MessageManager.getMessage("Not-Enough-Money"));
}
event.getWhoClicked().closeInventory();
} else if (displayName.equals(cancel)) {
event.getWhoClicked().closeInventory();
}
}
}
}
@EventHandler
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
if (getOwner() == null || getPlayer() == null || event.getPlayer() != getPlayer() || !(event
.getRightClicked() instanceof ItemFrame) || getItemStack() == null || itemStack == null || !itemStack
.hasItemMeta() || itemStack.getType() != getItemStack().getType()
|| itemStack.getData().getData() != getItemStack().getData().getData() || !itemStack.getItemMeta()
.getDisplayName().endsWith(getType().getName())) {
return;
}
event.setCancelled(true);
}
@EventHandler
public void onPlayerInteract(final PlayerInteractEvent event) {
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
UltraPlayer ultraPlayer = getUltraCosmetics().getPlayerManager().getUltraPlayer(event.getPlayer());
if (!uuid.equals(getOwnerUniqueId()))
return;
ItemStack itemStack = player.getItemInHand();
if (itemStack.getType() != getType().getMaterial())
return;
if (itemStack.getData().getData() != getType().getData())
return;
if (player.getInventory().getHeldItemSlot() != (int) SettingsManager.getConfig().get("Gadget-Slot"))
return;
if (ultraPlayer != getOwner())
return;
if (event.getAction() == Action.PHYSICAL)
return;
if(UltraCosmeticsData.get().getServerVersion().compareTo(ServerVersion.v1_9_R1) >= 0) {
if(event.getHand() != null && event.getHand() == EquipmentSlot.OFF_HAND) {
return;
}
}
event.setCancelled(true);
player.updateInventory();
if (!ultraPlayer.hasGadgetsEnabled()) {
getPlayer().sendMessage(MessageManager.getMessage("Gadgets-Enabled-Needed"));
return;
}
if (ultraPlayer.getCurrentTreasureChest() != null) {
return;
}
if (UltraCosmeticsData.get().isAmmoEnabled() && getType().requiresAmmo()) {
if (ultraPlayer.getAmmo(getType().toString().toLowerCase()) < 1) {
openAmmoPurchaseMenu();
return;
}
}
if (!checkRequirements(event)) {
return;
}
double coolDown = ultraPlayer.canUse(getType());
if (coolDown != -1) {
String timeLeft = new DecimalFormat("#.#").format(coolDown);
if (getType().getCountdown() > 1)
getPlayer().sendMessage(MessageManager.getMessage("Gadgets.Countdown-Message")
.replace("%gadgetname%", TextUtil.filterPlaceHolder(getType().getName(), getUltraCosmetics()))
.replace("%time%", timeLeft));
return;
} else {
ultraPlayer.setCoolDown(getType(), getType().getCountdown());
}
if (UltraCosmeticsData.get().isAmmoEnabled() && getType().requiresAmmo()) {
ultraPlayer.removeAmmo(getType().toString().toLowerCase());
itemStack = ItemFactory.create(getType().getMaterial(), getType().getData(),
ChatColor.WHITE + "" + ChatColor.BOLD + ultraPlayer.getAmmo(getType().toString().toLowerCase())
+ " " + getType().getName(), MessageManager.getMessage("Gadgets.Lore"));
this.itemStack = itemStack;
getPlayer().getInventory().setItem((int) SettingsManager.getConfig().get("Gadget-Slot"), itemStack);
}
if (event.getClickedBlock() != null && event.getClickedBlock().getType() != Material.AIR)
lastClickedBlock = event.getClickedBlock();
if (asynchronous) {
Bukkit.getScheduler().runTaskAsynchronously(getUltraCosmetics(), new BukkitRunnable() {
@Override
public void run() {
if (useTwoInteractMethods) {
if (event.getAction() == Action.RIGHT_CLICK_AIR
|| event.getAction() == Action.RIGHT_CLICK_BLOCK)
onRightClick();
else if (event.getAction() == Action.LEFT_CLICK_BLOCK
|| event.getAction() == Action.LEFT_CLICK_AIR)
onLeftClick();
} else {
onRightClick();
}
}
});
} else {
if (useTwoInteractMethods) {
if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK)
onRightClick();
else if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_AIR)
onLeftClick();
} else {
onRightClick();
}
}
}
@EventHandler
public void onItemDrop(PlayerDropItemEvent event) {
if (event.getItemDrop().getItemStack().equals(getItemStack())) {
if (SettingsManager.getConfig().getBoolean("Remove-Gadget-With-Drop")) {
getUltraCosmetics().getPlayerManager().getUltraPlayer(getPlayer()).removeGadget();
event.getItemDrop().remove();
} else {
event.setCancelled(true);
}
}
}
/**
* Cancel players from removing, picking the item in their inventory.
*
* @param event
*/
@EventHandler(priority = EventPriority.LOWEST)
public void cancelMove(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked();
if (player == getPlayer() && ((event.getCurrentItem() != null && event.getCurrentItem().equals(getItemStack())))
|| ((event.getCursor() != null && event.getCursor().equals(getItemStack())))) {
if (event.getClick() == ClickType.SHIFT_LEFT || event.getClick() == ClickType.SHIFT_RIGHT
|| event.getClick() == ClickType.NUMBER_KEY || event.getClick() == ClickType.UNKNOWN) {
event.setCancelled(true);
player.updateInventory();
return;
}
if (event.getCurrentItem() != null) {
if (event.getCurrentItem().equals(getItemStack())) {
event.setCancelled(true);
player.updateInventory();
}
}
}
}
/**
* Cancel players from removing, picking the item in their inventory.
*
* @param event
*/
@EventHandler
public void cancelMove(InventoryDragEvent event) {
Player player = (Player) event.getWhoClicked();
for (ItemStack item : event.getNewItems().values()) {
if (item != null && player == getPlayer() && item.equals(itemStack)) {
event.setCancelled(true);
((Player) event.getWhoClicked()).updateInventory();
return;
}
}
}
protected void setAsynchronous(boolean asynchronous) {
this.asynchronous = asynchronous;
}
public boolean isAsynchronous() {
return asynchronous;
}
/**
* If useTwoInteractMethods is true,
* called when only a right click is called.
* <p/>
* Otherwise, called when a right or left click
* is performed.
*/
abstract void onRightClick();
/**
* Called when a left click is done with gadget,
* only called if useTwoInteractMethods is true.
*/
abstract void onLeftClick();
/**
* Called when gadget is cleared.
*/
public abstract void onClear();
}