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),
|
||||
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),
|
||||
|
@ -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,
|
||||
|
@ -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