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),
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),
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.barbarians.Barbarians;
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.bouncyballs.BouncyBalls;
import nautilus.game.arcade.game.games.bridge.Bridge;
@ -237,6 +238,8 @@ public enum GameType
MOBA(MobaClassic.class, GameDisplay.MOBA),
MOBATraining(MobaTraining.class, GameDisplay.MOBATraining),
BattleRoyale(BattleRoyaleSolo.class, GameDisplay.BattleRoyale),
Event(EventGame.class, GameDisplay.Event, new GameType[]{
GameType.BaconBrawl, GameType.Barbarians, GameType.Bridge, GameType.Build, GameType.Build,
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;
}
}