Basic battle royale game

This commit is contained in:
Sam 2017-06-23 22:31:08 +01:00
parent 2facabbe2d
commit c6a3001bae
8 changed files with 1028 additions and 0 deletions

View File

@ -107,6 +107,8 @@ public enum GameDisplay
MOBA("Heroes of GWEN", Material.PRISMARINE, (byte)0, GameCategory.CLASSICS, 70, true), MOBA("Heroes of GWEN", Material.PRISMARINE, (byte)0, GameCategory.CLASSICS, 70, true),
MOBATraining("Heroes of GWEN Training", Material.PRISMARINE, (byte)0, GameCategory.CLASSICS, 70, false), MOBATraining("Heroes of GWEN Training", Material.PRISMARINE, (byte)0, GameCategory.CLASSICS, 70, false),
BattleRoyale("Battle Royale", Material.DIAMOND_SWORD, (byte)0, GameCategory.EVENT, 72, false),
GemHunters("Gem Hunters", Material.EMERALD, (byte) 0, GameCategory.SURVIVAL, 71, false), GemHunters("Gem Hunters", Material.EMERALD, (byte) 0, GameCategory.SURVIVAL, 71, false),
Event("Mineplex Event", Material.CAKE, (byte)0, GameCategory.EVENT, 999, false), Event("Mineplex Event", Material.CAKE, (byte)0, GameCategory.EVENT, 999, false),

View File

@ -9,6 +9,7 @@ import nautilus.game.arcade.game.games.alieninvasion.AlienInvasion;
import nautilus.game.arcade.game.games.baconbrawl.BaconBrawl; import nautilus.game.arcade.game.games.baconbrawl.BaconBrawl;
import nautilus.game.arcade.game.games.barbarians.Barbarians; import nautilus.game.arcade.game.games.barbarians.Barbarians;
import nautilus.game.arcade.game.games.basketball.Basketball; import nautilus.game.arcade.game.games.basketball.Basketball;
import nautilus.game.arcade.game.games.battleroyale.BattleRoyaleSolo;
import nautilus.game.arcade.game.games.bossbattles.BossBattles; import nautilus.game.arcade.game.games.bossbattles.BossBattles;
import nautilus.game.arcade.game.games.bouncyballs.BouncyBalls; import nautilus.game.arcade.game.games.bouncyballs.BouncyBalls;
import nautilus.game.arcade.game.games.bridge.Bridge; import nautilus.game.arcade.game.games.bridge.Bridge;
@ -237,6 +238,8 @@ public enum GameType
MOBA(MobaClassic.class, GameDisplay.MOBA), MOBA(MobaClassic.class, GameDisplay.MOBA),
MOBATraining(MobaTraining.class, GameDisplay.MOBATraining), MOBATraining(MobaTraining.class, GameDisplay.MOBATraining),
BattleRoyale(BattleRoyaleSolo.class, GameDisplay.BattleRoyale),
Event(EventGame.class, GameDisplay.Event, new GameType[]{ Event(EventGame.class, GameDisplay.Event, new GameType[]{
GameType.BaconBrawl, GameType.Barbarians, GameType.Bridge, GameType.Build, GameType.Build, GameType.BaconBrawl, GameType.Barbarians, GameType.Bridge, GameType.Build, GameType.Build,
GameType.Cards, GameType.CastleSiege, GameType.ChampionsDominate, GameType.ChampionsTDM, GameType.Christmas, GameType.Cards, GameType.CastleSiege, GameType.ChampionsDominate, GameType.ChampionsTDM, GameType.Christmas,

View File

@ -0,0 +1,347 @@
package nautilus.game.arcade.game.games.battleroyale;
import mineplex.core.common.util.C;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilAlg;
import mineplex.core.common.util.UtilBlock;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilParticle;
import mineplex.core.common.util.UtilParticle.ParticleType;
import mineplex.core.common.util.UtilParticle.ViewDist;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.common.util.UtilTextBottom;
import mineplex.core.common.util.UtilTime;
import mineplex.core.common.util.UtilWorld;
import mineplex.core.recharge.Recharge;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import mineplex.minecraft.game.core.damage.CustomDamageEvent;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.GameType;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.Game;
import nautilus.game.arcade.game.modules.chest.ChestLootModule;
import nautilus.game.arcade.game.modules.chest.ChestLootPool;
import nautilus.game.arcade.game.modules.compass.CompassModule;
import nautilus.game.arcade.kit.Kit;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.WorldBorder;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class BattleRoyale extends Game
{
private static final long PREPARE_TIME = TimeUnit.SECONDS.toMillis(20);
private static final int MAX_CORD = 1000;
private static final int SPAWN_Y = 130;
private static final int WORLD_SIZE_BUFFER = 300;
private static final int MIN_DISTANCE_APART_FOR_SPAWNS_SQUARED = 100;
private static final long MAX_DRAGON_TIME = TimeUnit.SECONDS.toMillis(60);
private static final long BORDER_TIME = TimeUnit.MINUTES.toSeconds(20);
private final Map<Player, BattleRoyalePlayer> _playerData = new HashMap<>(70);
protected WorldBorder _border;
public BattleRoyale(ArcadeManager manager, GameType gameType, Kit[] kits, String[] gameDesc)
{
super(manager, gameType, kits, gameDesc);
PrepareTime = PREPARE_TIME;
PrepareFreeze = false;
Damage = false;
DamageTeamSelf = true;
DeathDropItems = true;
QuitDropItems = true;
HungerSet = 20;
DeathTeleport = false;
WorldChunkUnload = true;
ItemDrop = true;
ItemPickup = true;
StrictAntiHack = true;
InventoryClick = true;
InventoryOpenBlock = true;
InventoryOpenChest = true;
new CompassModule()
.register(this);
new ChestLootModule()
.registerChestType("Standard",
// Swords
new ChestLootPool()
.addItem(new ItemStack(Material.WOOD_SWORD))
.addItem(new ItemStack(Material.STONE_SWORD))
,
// Armour
new ChestLootPool()
.addItem(new ItemStack(Material.LEATHER_HELMET))
.addItem(new ItemStack(Material.LEATHER_CHESTPLATE))
.addItem(new ItemStack(Material.LEATHER_LEGGINGS))
.addItem(new ItemStack(Material.LEATHER_BOOTS))
)
.register(this);
}
@Override
public void ParseData()
{
ChestLootModule chestModule = getModule(ChestLootModule.class);
chestModule.setSpawnsForType("Standard", WorldData.GetDataLocs("ORANGE"));
WorldData.MinX = -MAX_CORD;
WorldData.MinZ = -MAX_CORD;
WorldData.MaxX = MAX_CORD;
WorldData.MaxZ = MAX_CORD;
_border = WorldData.World.getWorldBorder();
}
@EventHandler
public void prepare(GameStateChangeEvent event)
{
if (event.GetState() != GameState.Prepare)
{
return;
}
_border.setCenter(getRandomCenter());
_border.setSize(MAX_CORD * 2);
List<Player> toTeleport = GetPlayers(true);
AtomicInteger index = new AtomicInteger();
Manager.runSyncTimer(new BukkitRunnable()
{
@Override
public void run()
{
if (index.get() >= toTeleport.size())
{
cancel();
return;
}
Player player = toTeleport.get(index.get());
if (player == null || !player.isOnline() || UtilPlayer.isSpectator(player))
{
return;
}
Location spawn = null;
int attempts = 0;
int initialXZ = 0;
while (spawn == null && attempts++ < 20)
{
if (attempts > 10)
{
initialXZ += 20;
}
spawn = getPlayerSpawn(initialXZ);
}
// Couldn't create a spawn, this should never happen and is pretty much impossible
if (spawn == null)
{
cancel();
SetState(GameState.Dead);
return;
}
Location goal = spawn.clone();
goal.setX(-spawn.getX());
goal.setZ(-spawn.getZ());
Bukkit.broadcastMessage(player.getName() + " -> " + UtilWorld.locToStrClean(spawn) + " after " + attempts + " attempts");
BattleRoyalePlayer royalePlayer = new BattleRoyalePlayer(Manager, player, spawn, goal);
_playerData.put(player, royalePlayer);
index.getAndIncrement();
}
}, 100, 2);
}
private Location getPlayerSpawn(int initialXZ)
{
// Calculate where a player should spawn
int max = MAX_CORD - WORLD_SIZE_BUFFER;
int x = initialXZ;
int z = initialXZ;
boolean varyX = UtilMath.random.nextBoolean();
boolean sign = UtilMath.random.nextBoolean();
if (varyX)
{
x += UtilMath.rRange(-max, max);
z += sign ? max : -max;
}
else
{
x += sign ? max : -max;
z += UtilMath.rRange(-max, max);
}
Location location = new Location(WorldData.World, x, SPAWN_Y, z);
// Check to make sure no players are nearby
for (BattleRoyalePlayer other : _playerData.values())
{
if (UtilMath.offsetSquared(location, other.getLocation()) < MIN_DISTANCE_APART_FOR_SPAWNS_SQUARED)
{
return null;
}
}
location.setYaw(UtilAlg.GetYaw(UtilAlg.getTrajectory(location, GetSpectatorLocation())));
return location;
}
private Location getRandomCenter()
{
int attempts = 0;
while (attempts++ < 20)
{
Location location = UtilAlg.getRandomLocation(GetSpectatorLocation(), 200, 0, 200);
if (UtilBlock.airFoliage(UtilBlock.getHighest(location.getWorld(), location.getBlock())))
{
return location;
}
}
return SpectatorSpawn;
}
@EventHandler
public void live(GameStateChangeEvent event)
{
if (event.GetState() != GameState.Live)
{
return;
}
CreatureAllowOverride = true;
_playerData.forEach((player, battleRoyalePlayer) ->
{
battleRoyalePlayer.removeCage();
battleRoyalePlayer.spawnDragon();
});
CreatureAllowOverride = false;
}
@EventHandler
public void updateDragons(UpdateEvent event)
{
if (event.getType() != UpdateType.FAST || !IsLive())
{
return;
}
Iterator<Player> iterator = _playerData.keySet().iterator();
while (iterator.hasNext())
{
Player player = iterator.next();
BattleRoyalePlayer royalePlayer = _playerData.get(player);
if (royalePlayer == null || !player.isOnline())
{
iterator.remove();
continue;
}
EnderDragon dragon = royalePlayer.getDragon();
Chicken chicken = royalePlayer.getChicken();
if (dragon == null || chicken == null)
{
continue;
}
UtilTextBottom.display((player.getTicksLived() % 5 == 0 ? C.cGreenB : C.cWhiteB) + "PRESS YOUR SNEAK KEY TO DISMOUNT YOUR DRAGON", player);
if (dragon.getPassenger() == null || chicken.getPassenger() == null)
{
Recharge.Instance.useForce(player, "Fall Damage", TimeUnit.SECONDS.toMillis(10));
UtilParticle.PlayParticleToAll(ParticleType.WITCH_MAGIC, player.getLocation(), 5, 5, 5, 0.01F, 100, ViewDist.NORMAL);
player.playSound(player.getLocation(), Sound.BLAZE_DEATH, 1, 0.6F);
dragon.remove();
chicken.remove();
iterator.remove();
}
}
if (!Damage && UtilTime.elapsed(GetStateTime(), MAX_DRAGON_TIME))
{
_playerData.forEach((player, battleRoyalePlayer) ->
{
Recharge.Instance.useForce(player, "Fall Damage", TimeUnit.SECONDS.toMillis(10));
player.sendMessage(F.main("Game", "You were too slow!"));
battleRoyalePlayer.getDragon().remove();
battleRoyalePlayer.getChicken().remove();
});
_playerData.clear();
Announce(C.cRedB + "Grace Period Over!", false);
for (Player player : Bukkit.getOnlinePlayers())
{
player.playSound(player.getLocation(), Sound.ENDERDRAGON_GROWL, 1, 1);
}
Damage = true;
HungerSet = -1;
_border.setSize(100, BORDER_TIME);
}
}
@EventHandler
public void fallDamage(CustomDamageEvent event)
{
Player player = event.GetDamageePlayer();
if (player == null || event.GetCause() != DamageCause.FALL || Recharge.Instance.usable(player, "Fall Damage"))
{
return;
}
event.SetCancelled("Dragon Fall");
}
@EventHandler(priority = EventPriority.LOWEST)
public void preventDragonExplosion(EntityExplodeEvent event)
{
if (event.getEntity() instanceof EnderDragon)
{
event.blockList().clear();
}
}
}

View File

@ -0,0 +1,132 @@
package nautilus.game.arcade.game.games.battleroyale;
import mineplex.core.common.Rank;
import mineplex.core.common.util.MapUtil;
import mineplex.core.common.util.UtilColor;
import mineplex.core.common.util.UtilEnt;
import nautilus.game.arcade.ArcadeManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEnderDragon;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.util.HashSet;
import java.util.Set;
class BattleRoyalePlayer
{
private final Player _player;
private final Location _location;
private final Location _goal;
private final Set<Location> _cageBlocks;
private EnderDragon _dragon;
private Chicken _chicken;
public BattleRoyalePlayer(ArcadeManager manager, Player player, Location location, Location goal)
{
_player = player;
_location = location;
_goal = goal;
_cageBlocks = new HashSet<>();
// Colour the cage based on the player's rank
Rank rank = manager.GetClients().Get(player).GetRank();
byte data = UtilColor.chatColorToWoolData(rank.getColor());
// Build the cage
buildCage(data);
// Teleport the player to the cage
player.teleport(_location.add(0, 1, 0));
}
private void buildCage(byte colourData)
{
// Floor
for (int x = -2; x <= 2; x++)
{
for (int z = -2; z <= 2; z++)
{
_location.add(x, -1, z);
MapUtil.QuickChangeBlockAt(_location, Material.STAINED_GLASS, colourData);
_cageBlocks.add(_location);
_location.subtract(x, -1, z);
}
}
// Roof
for (int x = -2; x <= 2; x++)
{
for (int z = -2; z <= 2; z++)
{
_location.add(x, 4, z);
MapUtil.QuickChangeBlockAt(_location, Material.STAINED_GLASS, colourData);
_cageBlocks.add(_location);
_location.subtract(x, 4, z);
}
}
// Walls
for (int y = 0; y < 4; y++)
{
for (int x = -2; x <= 2; x++)
{
for (int z = -2; z <= 2; z++)
{
if (x != -2 && x != 2 && z != -2 && z != 2)
{
continue;
}
_location.add(x, y, z);
MapUtil.QuickChangeBlockAt(_location, Material.STAINED_GLASS, colourData);
_cageBlocks.add(_location);
_location.subtract(x, y, z);
}
}
}
}
public void removeCage()
{
for (Location location : _cageBlocks)
{
MapUtil.QuickChangeBlockAt(location, Material.AIR);
}
}
public void spawnDragon()
{
_dragon = _location.getWorld().spawn(_location, EnderDragon.class);
UtilEnt.vegetate(_dragon);
UtilEnt.ghost(_dragon, true, false);
_chicken = _location.getWorld().spawn(_location, Chicken.class);
_chicken.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0));
_dragon.setPassenger(_chicken);
_chicken.setPassenger(_player);
((CraftEnderDragon) _dragon).getHandle().setTargetBlock(_goal.getBlockX(), _goal.getBlockY(), _goal.getBlockZ());
}
public Location getLocation()
{
return _location;
}
public EnderDragon getDragon()
{
return _dragon;
}
public Chicken getChicken()
{
return _chicken;
}
}

View File

@ -0,0 +1,151 @@
package nautilus.game.arcade.game.games.battleroyale;
import mineplex.core.common.util.C;
import mineplex.core.common.util.UtilWorld;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import nautilus.game.arcade.ArcadeManager;
import nautilus.game.arcade.GameType;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.GameTeam;
import nautilus.game.arcade.game.games.moba.kit.KitPlayer;
import nautilus.game.arcade.kit.Kit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BattleRoyaleSolo extends BattleRoyale
{
private static final String[] DESCRIPTION = {
"Battle Royale!"
};
private GameTeam _players;
public BattleRoyaleSolo(ArcadeManager manager)
{
super(manager, GameType.BattleRoyale, new Kit[] {new KitPlayer(manager)}, DESCRIPTION);
}
@EventHandler
public void customTeamGeneration(GameStateChangeEvent event)
{
if (event.GetState() != GameState.Recruit)
return;
_players = GetTeamList().get(0);
_players.SetColor(ChatColor.YELLOW);
_players.SetName("Players");
}
@Override
@EventHandler
public void ScoreboardUpdate(UpdateEvent event)
{
if (event.getType() != UpdateType.FAST || !InProgress())
{
return;
}
Scoreboard.writeNewLine();
Scoreboard.write(C.cYellow + C.Bold + "Players");
if (_players.GetPlayers(true).size() > 10)
{
Scoreboard.write(String.valueOf( _players.GetPlayers(true).size()));
}
else
{
for (Player player : _players.GetPlayers(true))
{
Scoreboard.write(player.getName());
}
}
Scoreboard.writeNewLine();
int size = (int) _border.getSize();
Scoreboard.write(C.cRedB + "World Border");
Scoreboard.write(UtilWorld.locToStrClean(_border.getCenter()));
Scoreboard.write(size + " Blocks Wide");
Scoreboard.draw();
}
@Override
public void EndCheck()
{
if (!IsLive())
{
return;
}
if (GetPlayers(true).size() <= 1)
{
List<Player> places = _players.GetPlacements(true);
AnnounceEnd(places);
if (places.size() >= 1)
{
AddGems(places.get(0), 20, "1st Place", false, false);
}
if (places.size() >= 2)
{
AddGems(places.get(1), 15, "2nd Place", false, false);
}
if (places.size() >= 3)
{
AddGems(places.get(2), 10, "3rd Place", false, false);
}
for (Player player : GetPlayers(false))
{
if (player.isOnline())
{
AddGems(player, 10, "Participation", false, false);
}
}
_border.setSize(10000);
SetState(GameState.End);
}
}
@Override
public List<Player> getWinners()
{
if (GetState().ordinal() >= GameState.End.ordinal())
{
List<Player> places = _players.GetPlacements(true);
if (places.isEmpty() || !places.get(0).isOnline())
return new ArrayList<>(0);
else
return Collections.singletonList(places.get(0));
}
else
return null;
}
@Override
public List<Player> getLosers()
{
List<Player> winners = getWinners();
if (winners == null)
{
return null;
}
List<Player> losers = _players.GetPlayers(false);
losers.removeAll(winners);
return losers;
}
}

View File

@ -0,0 +1,37 @@
package nautilus.game.arcade.game.modules.chest;
import mineplex.core.common.util.UtilMath;
import org.bukkit.inventory.ItemStack;
public class ChestLootItem
{
private ItemStack _item;
private int _lowestAmount, _highestAmount;
private double _rarity;
public ChestLootItem(ItemStack item, int lowestAmount, int highestAmount, double rarity)
{
_item = item;
_lowestAmount = lowestAmount;
_highestAmount = highestAmount;
_rarity = rarity;
}
public ItemStack getItem()
{
ItemStack itemStack = _item.clone();
if (_lowestAmount != _highestAmount)
{
itemStack.setAmount(UtilMath.rRange(_lowestAmount, _highestAmount));
}
return itemStack;
}
public double getProbability()
{
return _rarity;
}
}

View File

@ -0,0 +1,262 @@
package nautilus.game.arcade.game.modules.chest;
import mineplex.core.common.util.UtilBlock;
import mineplex.core.common.util.UtilEvent;
import mineplex.core.common.util.UtilEvent.ActionType;
import mineplex.core.common.util.UtilMath;
import mineplex.core.common.util.UtilTime;
import mineplex.core.updater.UpdateType;
import mineplex.core.updater.event.UpdateEvent;
import nautilus.game.arcade.events.GameStateChangeEvent;
import nautilus.game.arcade.game.Game.GameState;
import nautilus.game.arcade.game.modules.Module;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.Chest;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerInteractEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class ChestLootModule extends Module
{
private static final BlockFace[] FACES = {
BlockFace.NORTH,
BlockFace.SOUTH,
BlockFace.WEST,
BlockFace.EAST
};
private final List<ChestType> _chestTypes;
private final Map<ChestType, Set<ChestMetadata>> _chests;
private long _destroyAfterOpened;
private boolean _autoRotateChests = true;
public ChestLootModule()
{
_chestTypes = new ArrayList<>();
_chests = new HashMap<>();
}
public ChestLootModule registerChestType(String name, ChestLootPool... pools)
{
return registerChestType(name, 1, pools);
}
public ChestLootModule registerChestType(String name, double spawnChance, ChestLootPool... pools)
{
_chestTypes.add(new ChestType(name, spawnChance, pools));
return this;
}
public ChestLootModule setSpawnsForType(String typeName, List<Location> locations)
{
for (ChestType type : _chestTypes)
{
if (type.Name.equals(typeName))
{
type.ChestSpawns = locations;
}
}
return this;
}
public ChestLootModule destoryAfterOpened(int seconds)
{
_destroyAfterOpened = TimeUnit.SECONDS.toMillis(seconds);
return this;
}
public ChestLootModule autoRotateChests(boolean autoRotate)
{
_autoRotateChests = autoRotate;
return this;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void populateChests(GameStateChangeEvent event)
{
if (event.GetState() != GameState.Prepare)
{
return;
}
for (ChestType chestType : _chestTypes)
{
if (chestType.ChestSpawns == null)
{
continue;
}
Set<ChestMetadata> metadataSet = new HashSet<>();
for (Location location : chestType.ChestSpawns)
{
if (chestType.SpawnChance == 1 || Math.random() < chestType.SpawnChance)
{
Block block = location.getBlock();
block.setType(Material.CHEST);
if (_autoRotateChests)
{
for (BlockFace face : FACES)
{
if (UtilBlock.airFoliage(block.getRelative(face)))
{
block.setData(getData(face));
break;
}
}
}
ChestMetadata metadata = new ChestMetadata(block, chestType);
metadataSet.add(metadata);
}
}
_chests.put(chestType, metadataSet);
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void openChest(PlayerInteractEvent event)
{
Block block = event.getClickedBlock();
if (event.isCancelled() || !UtilEvent.isAction(event, ActionType.R_BLOCK) || block == null || !(block.getState() instanceof Chest))
{
return;
}
ChestMetadata metadata = getFromBlock(block);
if (metadata == null)
{
return;
}
if (metadata.Opened)
{
return;
}
metadata.Opened = true;
metadata.OpenedAt = System.currentTimeMillis();
metadata.populateChest((Chest) block.getState());
}
@EventHandler
public void destroyOpenedChests(UpdateEvent event)
{
if (event.getType() != UpdateType.SEC || _destroyAfterOpened == 0)
{
return;
}
for (Set<ChestMetadata> metadataSet : _chests.values())
{
metadataSet.removeIf(metadata ->
{
if (metadata.Opened && UtilTime.elapsed(metadata.OpenedAt, _destroyAfterOpened))
{
Block block = metadata.Chest;
Location location = block.getLocation();
location.getWorld().playEffect(location.add(0.5, 0.5, 0.5), Effect.STEP_SOUND, block.getType(), block.getData());
block.setType(Material.AIR);
return true;
}
return false;
});
}
}
private ChestMetadata getFromBlock(Block block)
{
Location blockLocation = block.getLocation();
for (Set<ChestMetadata> metadataSet : _chests.values())
{
for (ChestMetadata metadata : metadataSet)
{
if (UtilMath.offsetSquared(blockLocation, metadata.Chest.getLocation()) < 4)
{
return metadata;
}
}
}
return null;
}
private byte getData(BlockFace face)
{
switch (face)
{
case NORTH:
return 0;
case SOUTH:
return 3;
case WEST:
return 4;
case EAST:
return 5;
}
return 0;
}
private class ChestMetadata
{
Block Chest;
ChestType Type;
long OpenedAt;
boolean Opened;
ChestMetadata(Block chest, ChestType type)
{
Chest = chest;
Type = type;
}
void populateChest(Chest chest)
{
for (ChestLootPool pool : Type.Pool)
{
pool.populateChest(chest);
}
}
}
public class ChestType
{
String Name;
double SpawnChance;
List<ChestLootPool> Pool;
List<Location> ChestSpawns;
public ChestType(String name, double spawnChance, ChestLootPool... pools)
{
Name = name;
SpawnChance = spawnChance;
Pool = Arrays.asList(pools);
}
}
}

View File

@ -0,0 +1,94 @@
package nautilus.game.arcade.game.modules.chest;
import mineplex.core.common.util.UtilMath;
import org.bukkit.block.Chest;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class ChestLootPool
{
private List<ChestLootItem> _items;
private int _minimumPerChest;
private int _maximumPerChest;
public ChestLootPool()
{
_items = new ArrayList<>();
_minimumPerChest = 1;
_maximumPerChest = 1;
}
public ChestLootPool addItem(ItemStack itemStack)
{
return addItem(itemStack, itemStack.getAmount(), itemStack.getAmount(), 1);
}
public ChestLootPool addItem(ItemStack itemStack, double rarity)
{
return addItem(itemStack, itemStack.getAmount(), itemStack.getAmount(), rarity);
}
public ChestLootPool addItem(ItemStack itemStack, int lowestAmount, int highestAmount)
{
return addItem(itemStack, lowestAmount, highestAmount, 1);
}
public ChestLootPool addItem(ItemStack itemStack, int lowestAmount, int highestAmount, double rarity)
{
_items.add(new ChestLootItem(itemStack, lowestAmount, highestAmount, rarity));
return this;
}
public ChestLootPool setAmountsPerChest(int minimumPerChest, int maximumPerChest)
{
_minimumPerChest = minimumPerChest;
_maximumPerChest = maximumPerChest;
return this;
}
public void populateChest(Chest chest)
{
Inventory inventory = chest.getBlockInventory();
for (int i = 0; i < UtilMath.rRange(_minimumPerChest, _maximumPerChest); i++)
{
int slot = UtilMath.r(inventory.getSize());
ChestLootItem item = getRandomItem();
if (item == null)
{
continue;
}
inventory.setItem(slot, item.getItem());
}
chest.update();
}
private ChestLootItem getRandomItem()
{
double totalWeight = 0;
for (ChestLootItem item : _items)
{
totalWeight += item.getProbability();
}
double select = Math.random() * totalWeight;
for (ChestLootItem item : _items)
{
if ((select -= item.getProbability()) <= 0)
{
return item;
}
}
return null;
}
}