package com.github.jamesnorris.ablockalypse.aspect;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.Chest;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.github.jamesnorris.ablockalypse.Ablockalypse;
import com.github.jamesnorris.ablockalypse.behavior.MapDatable;
import com.github.jamesnorris.ablockalypse.enumerated.Setting;
import com.github.jamesnorris.ablockalypse.enumerated.ZAEffect;
import com.github.jamesnorris.ablockalypse.enumerated.ZASound;
import com.github.jamesnorris.ablockalypse.threading.DelayedTask;
import com.github.jamesnorris.ablockalypse.threading.RepeatingTask;
import com.github.jamesnorris.ablockalypse.utility.AblockalypseUtility;
import com.github.jamesnorris.ablockalypse.utility.BukkitUtility;
import com.github.jamesnorris.ablockalypse.utility.BuyableItemData;
import com.github.jamesnorris.ablockalypse.utility.Region;
import com.github.jamesnorris.ablockalypse.utility.SerialLocation;
public class MysteryBox extends SpecificGameAspect implements MapDatable {
private boolean active = true, showing;
private Object chest;
private Game game;
private Location loc;
private Location[] locs;
private Random rand = new Random();
private int uses, cost = (Integer) Setting.MYSTERY_BOX_COST.getSetting();
private UUID uuid = UUID.randomUUID();
private ItemStack lastShownItem;
private ZAPlayer lastShownZAPlayer;
/**
* Creates a new instance of the MysteryBox.
*
* @param game The game to involve this mystery chest in
* @param loc A location on the chest
*/
public MysteryBox(Game game, Location loc) {
this(game, loc, game.getActiveMysteryChest() == null);
}
/**
* Creates a new instance of the MysteryBox.
*
* @param game The game to involve this mystery chest in
* @param loc A location on the chest
* @param active Whether or not this chest should be active
*/
public MysteryBox(Game game, Location loc, boolean active) {
super(game, loc, !game.hasStarted());
this.loc = loc;
Block b2 = BukkitUtility.getSecondChest(loc.getBlock());
locs = b2 != null ? new Location[] {loc, b2.getLocation()} : new Location[] {loc};
chest = loc.getBlock().getState();
this.game = game;
this.active = active;
uses = rand.nextInt(8) + 2;
load();
}
public MysteryBox(Map<String, Object> savings) {
this(Ablockalypse.getData().getGame((String) savings.get("game_name"), true), SerialLocation.returnLocation((SerialLocation) savings.get("location")), (Boolean) savings.get("is_active"));
uses = (Integer) savings.get("uses_left");
cost = (Integer) savings.get("cost");
uuid = savings.get("uuid") == null ? uuid : (UUID) savings.get("uuid");
}
/**
* Gets the uses that this chest has before the mystery chest moves to another location.
*
* @return The uses before movement
*/
public int getActiveUses() {
return uses;
}
/**
* Gets the chest associated with this instance.
*
* @return The chest associated with this instance
*/
public Chest getChest() {
if (chest instanceof Chest) {
return (Chest) chest;
}
return null;
}
@Override public List<Block> getDefiningBlocks() {
List<Block> blocks = new ArrayList<Block>();
for (Location location : locs) {
blocks.add(location.getBlock());
}
return blocks;
}
public ItemStack getLastShownItem() {
return lastShownItem;
}
public ZAPlayer getLastShownZAPlayer() {
return lastShownZAPlayer;
}
@Override public int getLoadPriority() {
return 2;
}
/**
* Gets the location that the chest is located at.
*
* @return The location of the chest
*/
@Override public Location getLocation() {
return locs[0];
}
@Override public Location getPointClosestToOrigin() {
return loc;
}
@Override public Map<String, Object> getSave() {
Map<String, Object> savings = new HashMap<String, Object>();
savings.put("uuid", getUUID());
savings.put("is_active", active);
savings.put("game_name", game.getName());
savings.put("location", loc == null ? null : new SerialLocation(loc));
savings.put("uses_left", uses);
savings.put("cost", cost);
return savings;
}
@Override public UUID getUUID() {
return uuid;
}
/**
* Checks if the chest is active or not.
*
* @return Whether or not the chest is active and can be used
*/
public boolean isActive() {
return active;
}
public boolean isShowingItem() {
return showing;
}
@Override public void onGameEnd() {
setBlinking(true);
}
@Override public void onGameStart() {
setBlinking(false);
}
/**
* Randomizes the contents of the MysteryChest.
*
* @param zap The zaplayer to give the random item to
*/
@SuppressWarnings("deprecation") public void openToRandomItem(ZAPlayer zap) {
final Player player = zap.getPlayer();
if (!active) {
player.sendMessage(ChatColor.RED + "This box is currently inactive!");
return;
}
Map<Integer, BuyableItemData> maps = Ablockalypse.getExternal().getItemFileManager().getSignItemMap();
ArrayList<Integer> idList = new ArrayList<Integer>();
for (int testId : maps.keySet()) {
idList.add(testId);
}
int id = idList.get(rand.nextInt(idList.size()));// Solution for the lack of integer positions in item maps
BuyableItemData map = maps.get(id);
if (zap.getPoints() < cost) {
zap.getPlayer().sendMessage(ChatColor.RED + "You have " + zap.getPoints() + " / " + cost + " points to buy this.");
return;
}
final Location topView = locs[1] != null ? new Region(locs[0], locs[1]).getCenter().clone().add(0, 1, 0) : locs[0].clone().add(0, 1, 0);
final Item dropped = showItem(new ItemStack(Material.SKULL_ITEM, 1, (short) 4), 140);
lastShownItem = map.toItemStack();
lastShownZAPlayer = zap;
if ((Boolean) Setting.EXTRA_EFFECTS.getSetting()) {
ZASound.ACHIEVEMENT.play(topView);
}
AblockalypseUtility.scheduleNearbyWarning(topView, ChatColor.GRAY + "Press " + ChatColor.AQUA + "SHIFT" + ChatColor.GRAY + " to take your item.", 2, 3.5, 2, 7000);
new RepeatingTask(20, (Boolean) Setting.EXTRA_EFFECTS.getSetting()) {
@Override public void run() {
ZAEffect.FLAMES.play(topView);
}
};
new DelayedTask(140, true) {
@Override public void run() {
dropped.remove();
}
};
--uses;
zap.subtractPoints(cost);
player.updateInventory();
if (uses == 0 && (Boolean) Setting.MOVING_MYSTERY_BOXES.getSetting()) {
setActive(false);
List<MysteryBox> chests = game.getObjectsOfType(MysteryBox.class);
game.setActiveMysteryChest(chests.get(rand.nextInt(chests.size())));
}
}
@Override public void paste(Location pointClosestToOrigin) {
loc = pointClosestToOrigin;
refreshBlinker();
}
/**
* Removes the mystery chest completely.
*/
@Override public void remove() {
setActive(false);
List<MysteryBox> chests = game.getObjectsOfType(MysteryBox.class);
int size = chests.size();
if (size >= 1) {
game.setActiveMysteryChest(chests.get(rand.nextInt(size)));
}
super.remove();
}
/**
* Changes whether or not the chest will be active.
*
* @param tf Whether or not the chest should be active
*/
public void setActive(boolean tf) {
if (tf && uses == 0) {
uses = rand.nextInt(8) + 2;
}
active = tf;
}
/**
* Sets the uses before the mystery chest moves.
*
* @param i The uses before movement
*/
public void setActiveUses(int i) {
uses = i;
}
public Item showItem(ItemStack stack, int duration) {
showing = true;
Location topView = locs[1] != null ? new Region(locs[0], locs[1]).getCenter().clone().add(0, 1, 0) : locs[0].clone().add(0, 1, 0);
BukkitUtility.setChestOpened(Arrays.asList(Bukkit.getOnlinePlayers()), loc.getBlock(), true);
Item item = topView.getWorld().dropItem(topView, stack);
item.setPickupDelay(Integer.MAX_VALUE);
new DelayedTask(duration, true) {
@Override public void run() {
stopShowing();
}
};
return item;
}
public void stopShowing() {
BukkitUtility.setChestOpened(Arrays.asList(Bukkit.getOnlinePlayers()), loc.getBlock(), false);
showing = false;
}
}