Basic battle royale game
This commit is contained in:
parent
2facabbe2d
commit
c6a3001bae
@ -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),
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user