-
-
Save aikar/903589f3843e82c2444cddd690d18b96 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016. Starlis LLC / dba Empire Minecraft | |
* | |
* This source code is proprietary software and must not be redistributed without Starlis LLC's approval | |
* | |
*/ | |
package com.empireminecraft.features.specialevents; | |
import co.aikar.timings.Timing; | |
import com.destroystokyo.paper.event.entity.EntityPathfindEvent; | |
import com.empireminecraft.Empire; | |
import com.empireminecraft.Identifier; | |
import com.empireminecraft.Worlds; | |
import com.empireminecraft.commands.EmpireCommand; | |
import com.empireminecraft.commands.annotation.CommandAlias; | |
import com.empireminecraft.commands.annotation.Default; | |
import com.empireminecraft.commands.annotation.Subcommand; | |
import com.empireminecraft.config.EmpireServer; | |
import com.empireminecraft.config.meta.EmpireMetaKey; | |
import com.empireminecraft.config.meta.PersistentMetaKey; | |
import com.empireminecraft.config.typemap.RupeeTransType; | |
import com.empireminecraft.entityai.EntityAIApi; | |
import com.empireminecraft.features.items.CustomItems; | |
import com.empireminecraft.features.items.UsableItem; | |
import com.empireminecraft.features.survival.LootPool; | |
import com.empireminecraft.features.survival.SurvivalItemDrops; | |
import com.empireminecraft.items.PromoItems; | |
import com.empireminecraft.metaapi.MetaApi; | |
import com.empireminecraft.systems.EmpireChat; | |
import com.empireminecraft.systems.Formatting; | |
import com.empireminecraft.systems.chat.Chat; | |
import com.empireminecraft.systems.chat.ChatChannel; | |
import com.empireminecraft.systems.currency.Rupees; | |
import com.empireminecraft.systems.db.DbRow; | |
import com.empireminecraft.systems.db.EmpireDb; | |
import com.empireminecraft.systems.residence.protection.CuboidArea; | |
import com.empireminecraft.systems.residence.protection.Residence; | |
import com.empireminecraft.systems.residence.protection.ResidenceManager; | |
import com.empireminecraft.user.EmpireGroup; | |
import com.empireminecraft.user.EmpireUser; | |
import com.empireminecraft.user.meta.EmpireCustomMeta; | |
import com.empireminecraft.user.meta.EmpireCustomMetaKey; | |
import com.empireminecraft.user.meta.EmpireMetaNumberSerializer; | |
import com.empireminecraft.user.meta.LongSetMetaSerializer; | |
import com.empireminecraft.util.BlockUtil; | |
import com.empireminecraft.util.BukkitUtil; | |
import com.empireminecraft.util.BukkitUtil.Listener; | |
import com.empireminecraft.util.NumUtil; | |
import com.empireminecraft.util.TimeUtil; | |
import com.empireminecraft.util.UserUtil; | |
import com.empireminecraft.util.Util; | |
import com.google.common.collect.ArrayListMultimap; | |
import com.google.common.collect.ListMultimap; | |
import com.google.common.collect.Lists; | |
import org.bukkit.Bukkit; | |
import org.bukkit.Chunk; | |
import org.bukkit.Color; | |
import org.bukkit.FireworkEffect; | |
import org.bukkit.FireworkEffect.Type; | |
import org.bukkit.Location; | |
import org.bukkit.Material; | |
import org.bukkit.World; | |
import org.bukkit.block.Block; | |
import org.bukkit.entity.Bat; | |
import org.bukkit.entity.Creature; | |
import org.bukkit.entity.Entity; | |
import org.bukkit.entity.EntityType; | |
import org.bukkit.entity.Fireball; | |
import org.bukkit.entity.Firework; | |
import org.bukkit.entity.Ghast; | |
import org.bukkit.entity.Item; | |
import org.bukkit.entity.LivingEntity; | |
import org.bukkit.entity.Player; | |
import org.bukkit.entity.Villager; | |
import org.bukkit.event.EventHandler; | |
import org.bukkit.event.EventPriority; | |
import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; | |
import org.bukkit.event.entity.EntityDamageEvent; | |
import org.bukkit.event.entity.EntityDeathEvent; | |
import org.bukkit.event.entity.ItemMergeEvent; | |
import org.bukkit.event.entity.ProjectileLaunchEvent; | |
import org.bukkit.event.player.PlayerDropItemEvent; | |
import org.bukkit.event.player.PlayerPickupItemEvent; | |
import org.bukkit.event.weather.WeatherChangeEvent; | |
import org.bukkit.event.world.ChunkLoadEvent; | |
import org.bukkit.event.world.ChunkUnloadEvent; | |
import org.bukkit.event.world.WorldLoadEvent; | |
import org.bukkit.event.world.WorldUnloadEvent; | |
import org.bukkit.inventory.EntityEquipment; | |
import org.bukkit.inventory.ItemStack; | |
import org.bukkit.inventory.meta.FireworkMeta; | |
import java.sql.SQLException; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Set; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
import static com.empireminecraft.features.survival.LootPool.LootItem; | |
final class Halloween extends Listener { | |
private static World world; | |
private static final ListMultimap<Identifier, Location> jackCache = ArrayListMultimap.create(); | |
private static final EmpireCustomMetaKey<Integer> SMP_SCORE_KEY; | |
private static final EmpireCustomMetaKey<Integer> GLOBAL_SCORE_KEY; | |
private static final EmpireCustomMetaKey<Set<Long>> PICKUP_LOG_KEY; | |
private static final UsableItem[] CANDIES = { | |
PromoItems.CREEPER_CANDY, | |
PromoItems.ZOMBIE_CANDY, | |
PromoItems.SPIDER_CANDY, | |
PromoItems.SKELETON_CANDY, | |
PromoItems.ENDER_CANDY | |
}; | |
private static final Timing jackTiming = Util.timings("Jack block update"); | |
static { | |
final String server = EmpireServer.getServer().label; | |
PICKUP_LOG_KEY = new EmpireCustomMetaKey("htown.pickups", LongSetMetaSerializer.SERIALIZER); | |
GLOBAL_SCORE_KEY = new EmpireCustomMetaKey("htown.score", EmpireMetaNumberSerializer.INTEGER); | |
SMP_SCORE_KEY = new EmpireCustomMetaKey("htown." + server+ ".score", EmpireMetaNumberSerializer.INTEGER); | |
final List<EmpireMetaKey> auto = EmpireMetaKey.getAutoloadKeys(); | |
auto.add(PICKUP_LOG_KEY); | |
auto.add(GLOBAL_SCORE_KEY); | |
auto.add(SMP_SCORE_KEY); | |
} | |
private Halloween() {} | |
public static void initialize() { | |
world = Bukkit.getWorld("event"); | |
if (world != null) { | |
for (Chunk chunk : world.getLoadedChunks()) { | |
cacheChunk(chunk); | |
} | |
} | |
final LootPool.LootTable loot = SurvivalItemDrops.mobDrops; | |
loot.put(EntityType.CREEPER, LootPool.LootPool(LootItem(25, PromoItems.CREEPER_CANDY))); | |
loot.put(EntityType.ZOMBIE, LootPool.LootPool(LootItem(25, PromoItems.ZOMBIE_CANDY))); | |
loot.put(EntityType.SPIDER, LootPool.LootPool(LootItem(25, PromoItems.SPIDER_CANDY))); | |
loot.put(EntityType.SKELETON, LootPool.LootPool(LootItem(25, PromoItems.SKELETON_CANDY))); | |
loot.put(EntityType.ENDERMAN, LootPool.LootPool(LootItem(25, PromoItems.ENDER_CANDY))); | |
new Halloween(); | |
new HalloweenCommand(); | |
BukkitUtil.runTaskTimer(Halloween::worldEvent, TimeUtil.SECOND.inTicks(30)); | |
BukkitUtil.runTaskTimer(Halloween::cycleMobs, TimeUtil.SECOND.inTicks(15)); | |
BukkitUtil.runTaskTimer(Halloween::toggleJacks, TimeUtil.SECOND.inTicks(10)); | |
BukkitUtil.runTaskTimer(Halloween::scoreBroadcast, TimeUtil.MINUTE.inTicks(15)); | |
} | |
public static void initializeCommand() { | |
new HalloweenCommand(); | |
} | |
@CommandAlias("halloween|hallo|htown") | |
private static class HalloweenCommand extends EmpireCommand { | |
@Default | |
public void onEnter(Player player) { | |
if (world != null) { | |
SpecialEvents.teleportToEventWorld(player, p -> { | |
EmpireChat.setActiveChannel(p, ChatChannel.RESIDENCE); | |
Util.sendMsg(p, "&aChat focus set to channel " + ChatChannel.RESIDENCE); | |
}); | |
} else { | |
Util.sendMsg(player, "&cSorry, it appears Halloween Town is closed!"); | |
} | |
} | |
@Subcommand("score|s|p|points") | |
@CommandAlias("hscore|hpoints|gscore") | |
public void onScore(Player player) { | |
sendScore(player, "Global Score", GLOBAL_SCORE_KEY); | |
} | |
@Subcommand("smpscore|smp|smppoints") | |
@CommandAlias("smpscore|smppoints") | |
public void onSMPScore(Player player) { | |
sendScore(player, EmpireServer.getServer().label.toUpperCase() + " Score", SMP_SCORE_KEY); | |
} | |
private void sendScore(Player player, String header, EmpireCustomMetaKey<Integer> key) { | |
Empire.newChain() | |
.async(() -> { | |
try { | |
EmpireUser user = player.getUser(); | |
List<DbRow> results = getTopPlayers(key, 10); | |
Util.sendMsg(player, Formatting.heading("Halloween Score - " + header)); | |
int globalPoints = user.getMeta(GLOBAL_SCORE_KEY).getOrDefault(); | |
int smpPoints = user.getMeta(SMP_SCORE_KEY).getOrDefault(); | |
final String server = EmpireServer.getServer().label.toUpperCase(); | |
user.sendMsg("&a - Your scores: &b" + smpPoints + " &a/&b " + globalPoints + " &e(" + server + "/GLOBAL)"); | |
for (int i = 0; i < results.size(); i++) { | |
DbRow res = results.get(i); | |
Util.sendMsg(player, " &b" + (i+1) + ": " + EmpireGroup.colorUserName(res.get("name"), (Integer) res.get("user_group_id")) | |
+ "&f (" + res.get("score") + ")"); | |
} | |
Util.sendMsg(player, " &bUse &f/smpscore&b for per-SMP score, &f/hscore &bfor global"); | |
} catch (SQLException e) { | |
Util.sendMsg(player, "&cSomething went wrong. Hopefully Aikar can fix it."); | |
Util.printException(e); | |
} | |
}).execute(); | |
} | |
} | |
private static List<DbRow> getTopPlayers(EmpireCustomMetaKey<Integer> key, int number) throws SQLException { | |
return EmpireDb.getResults( | |
"SELECT m.value as score, u.name, u.user_group_id " + | |
" FROM user u JOIN user_meta m ON m.user_id = u.user_id " + | |
" WHERE m.meta_key = ? " + | |
" ORDER BY CAST(value as UNSIGNED) DESC LIMIT " + number, | |
key.key | |
); | |
} | |
@EventHandler | |
public static void onChunkLoad(ChunkLoadEvent event) { | |
if (event.getWorld().equals(world)) { | |
cacheChunk(event.getChunk()); | |
} | |
} | |
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) | |
public static void onChunkUnload(ChunkUnloadEvent event) { | |
if (event.getWorld().equals(world)) { | |
final Identifier chunkId = event.getChunk().getIdentifier(); | |
final List<Location> list = jackCache.get(chunkId); | |
if (list != null) { | |
list.clear(); | |
} | |
} | |
} | |
@EventHandler | |
public static void onWorldLoad(WorldLoadEvent event) { | |
if ("event".equals(event.getWorld().getName())) { | |
world = event.getWorld(); | |
} | |
} | |
@EventHandler | |
public static void onWorldUnload(WorldUnloadEvent event) { | |
if (event.getWorld().equals(world)) { | |
world.getPlayers().forEach(p -> { | |
Util.sendMsg(p, "&cSorry, Halloween town has been closed!"); | |
p.teleport(Worlds.getSpawnLocation(Worlds.TOWN)); | |
}); | |
world = null; | |
} | |
} | |
@EventHandler(ignoreCancelled = true) | |
public static void onMerge(ItemMergeEvent event) { | |
if (event.getEntity().getWorld().equals(world)) { | |
event.setCancelled(true); | |
} | |
} | |
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) | |
public static void onDamage(EntityDamageEvent event) { | |
final Entity entity = event.getEntity(); | |
if (entity.getWorld().equals(world) && entity instanceof Villager) { | |
event.setCancelled(true); | |
} | |
} | |
@EventHandler | |
public static void onProjLaunch(ProjectileLaunchEvent event) { | |
if (event.getEntity().getWorld().equals(world) && event.getEntity() instanceof Fireball) { | |
event.setCancelled(true); | |
} | |
} | |
@EventHandler | |
public static void onDeath(EntityDeathEvent event) { | |
final LivingEntity entity = event.getEntity(); | |
if (entity instanceof Player) { | |
return; | |
} | |
if (entity.getWorld().equals(world)) { | |
if (entity instanceof Ghast) { | |
event.getDrops().clear(); | |
} | |
if (NumUtil.rand(1,2) == 1) { | |
spawnFirework(entity.getLocation(), 1, 1, 1); | |
spawnCandy(entity.getLocation()); | |
if (NumUtil.rand(1, 4) != 1) { | |
spawnCandy(entity.getLocation()); | |
if (Util.randBool()) { | |
spawnCandy(entity.getLocation()); | |
} | |
} | |
} | |
} | |
} | |
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) | |
public static void onMove(EntityPathfindEvent event) { | |
final Entity entity = event.getEntity(); | |
if (entity.getWorld().equals(world)) { | |
Residence residence = Residence.getResidence(event.getLoc()); | |
if (residence == null) { | |
event.setCancelled(true); | |
} | |
} | |
} | |
@EventHandler(ignoreCancelled = true) | |
public static void onWeather(WeatherChangeEvent event) { | |
if (event.getWorld().equals(world) && event.toWeatherState()) { | |
event.setCancelled(true); | |
} | |
} | |
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) | |
public static void onPickup(PlayerPickupItemEvent event) { | |
final Player player = event.getPlayer(); | |
if (!player.getWorld().equals(world)) { | |
return; | |
} | |
final ItemStack itemStack = event.getItem().getItemStack(); | |
if (!isCandy(itemStack)) { | |
return; | |
} | |
final String ownerName = MetaApi.getEntityMeta(event.getItem(), PersistentMetaKey.ITEM_OWNER); | |
if (ownerName == null || player.getName().equals(ownerName)) { | |
return; | |
} | |
Player throwerPlayer = Bukkit.getPlayerExact(ownerName); | |
if (throwerPlayer == null) { | |
return; | |
} | |
if (Chat.isAway(throwerPlayer)) { | |
event.setCancelled(true); | |
return; | |
} | |
EmpireUser picker = player.getUser(); | |
EmpireUser thrower = throwerPlayer.getUser(); | |
if (!processPickup(picker, thrower)) { | |
event.setCancelled(true); | |
} | |
} | |
@EventHandler(ignoreCancelled = true) | |
public void onDropItem(PlayerDropItemEvent event) { | |
final Player player = event.getPlayer(); | |
if (!player.getWorld().equals(world)) { | |
return; | |
} | |
if (Chat.isAway(player)) { | |
event.setCancelled(true); | |
return; | |
} | |
final Location location = event.getItemDrop().getLocation(); | |
location.setY(location.getWorld().getHighestBlockYAt(location)); | |
if (world.getNearbyEntitiesByType(Item.class, location, 6, 6, 6).size() > 2) { | |
event.setCancelled(true); | |
Util.sendMsg(player, "&cToo many items are already nearby! Throw somewhere else."); | |
} | |
} | |
private static void scoreBroadcast() { | |
if (world != null) { | |
Empire.newChain() | |
.asyncFirst( () -> { | |
try { | |
final String server = EmpireServer.getServer().label.toUpperCase(); | |
final List<DbRow> top3SMP = getTopPlayers(SMP_SCORE_KEY, 3); | |
final List<DbRow> top3Global = getTopPlayers(GLOBAL_SCORE_KEY, 3); | |
final Function<DbRow, String> buildNameString = row -> { | |
final Integer groupId = row.get("user_group_id"); | |
final String score = row.get("score"); | |
final String name = row.get("name"); | |
return EmpireGroup.colorUserName(name, groupId) + " &b(" + score + ")"; | |
}; | |
String smpScore = top3SMP.stream().map(buildNameString).collect(Collectors.joining("&b, ")); | |
String globalScore = top3Global.stream().map(buildNameString).collect(Collectors.joining("&b, ")); | |
return Lists.newArrayList( | |
Util.color(" &b" + server + ": " + smpScore), | |
Util.color(" &bGlobal: " + globalScore) | |
); | |
} catch (SQLException e) { | |
Util.printException(e); | |
} | |
return null; | |
}) | |
.abortIfNull() | |
.syncLast((result) -> { | |
final String heading = Formatting.heading("Current Top Scores"); | |
world.getPlayers().forEach(player -> { | |
Util.sendMsg(player, heading); | |
Util.sendMsg(player, result.get(0)); | |
Util.sendMsg(player, result.get(1)); | |
Util.sendMsg(player, " &bSee TOP 10 with &f/smpscore&b for per-SMP, &f/hscore &bfor global"); | |
}); | |
}) | |
.execute(); | |
} | |
} | |
private static boolean processPickup(EmpireUser picker, EmpireUser thrower) { | |
final EmpireCustomMeta<Set<Long>> meta = picker.getMeta(PICKUP_LOG_KEY); | |
Set<Long> pickups = meta.getOrDefault(); | |
if (pickups == null) { | |
return true; // shouldnt happen on this API but make IDE happy | |
} | |
final Residence residence = Residence.getResidence(thrower.player); | |
if (residence == null || !"event".equals(residence.getName())) { | |
return false; | |
} | |
CuboidArea area = residence.getArea("entrance"); | |
if (area.containsLoc(picker.player.getLocation())) { | |
return false; | |
} | |
if (pickups.contains(thrower.userId)) { | |
return false; | |
} | |
pickups.add(thrower.userId); | |
meta.save(); | |
String server = EmpireServer.getServer().label.toUpperCase(); | |
int pickerPoints = picker.incrementMeta(GLOBAL_SCORE_KEY, 1); | |
int pickerSMPPoints = picker.incrementMeta(SMP_SCORE_KEY, 1); | |
picker.sendMsg( "&aYou received candy from " + thrower.colorName + "&a!"); | |
picker.sendMsg( "&a - Your scores: &b" + pickerSMPPoints + " &a/&b " + pickerPoints + " &e(" + server + "/GLOBAL)"); | |
processRewards(picker, pickerPoints); | |
int giverPoints = thrower.incrementMeta(GLOBAL_SCORE_KEY, 1); | |
int giverSMPPoints = thrower.incrementMeta(SMP_SCORE_KEY, 1); | |
thrower.sendMsg("&aYou gave candy to " + picker.colorName + "&a, you get bonus candy!"); | |
thrower.sendMsg("&a - Your scores: &b" + giverSMPPoints + " &a/&b " + giverPoints + " &e(" + server + "/GLOBAL)"); | |
processRewards(thrower, giverPoints); | |
UserUtil.givePlayerItems(thrower.player, Util.random(CANDIES)); | |
return true; | |
} | |
private static void processRewards(EmpireUser user, int score) { | |
if (score == 50) { | |
user.sendMsg(" &a» &bCongratulations! You have earned a &aHaunted Head&a!"); | |
UserUtil.givePlayerItems(user.player, PromoItems.HAUNTED_HEAD); | |
} else if (score == 150) { | |
user.sendMsg(" &a» &bCongratulations! You have earned a &6&oHeadless Horseman Mask&a!"); | |
UserUtil.givePlayerItems(user.player, PromoItems.HEADLESS_HORSEMAN_MASK); | |
} | |
if (score % 25 == 0) { | |
user.sendMsg(" &a» &bCongratulations! You have earned &a500&b rupees!"); | |
Empire.newChain().async(() -> { | |
Rupees.credit(user.getUserId(), 500, RupeeTransType.PROMOTIONAL_CREDIT.id(), "Halloween 2016 Bonus: " + score); | |
}).execute(); | |
} | |
} | |
private static boolean isCandy(ItemStack item) { | |
for (UsableItem candy : CANDIES) { | |
if (UsableItem.isSame(candy, item)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
private static void cacheChunk(Chunk chunk) { | |
int cX = chunk.getX() << 4; | |
int cZ = chunk.getZ() << 4; | |
final Identifier chunkId = chunk.getIdentifier(); | |
jackCache.get(chunkId).clear(); | |
Residence residence = ResidenceManager.getByName("event"); | |
if (residence == null) { | |
return; | |
} | |
Residence pumpkin = residence.getSubzone("pumpkin"); | |
for (int x = 0; x < 16; x++) { | |
for (int z = 0; z < 16; z++) { | |
for (int y = 0; y < 20; y++) { | |
final Block block = world.getBlockAt(cX + x, y, cZ + z); | |
final Location blockLoc = block.getLocation(); | |
if (!residence.containsLoc(blockLoc) || (pumpkin != null && pumpkin.containsLoc(blockLoc))) { | |
continue; | |
} | |
final Material type = block.getType(); | |
if (type == Material.JACK_O_LANTERN || type == Material.PUMPKIN) { | |
jackCache.put(chunkId, blockLoc); | |
} | |
} | |
} | |
} | |
} | |
@SuppressWarnings("deprecation") | |
private static void toggleJacks() { | |
if (world == null) { | |
return; | |
} | |
for (Chunk chunk : world.getLoadedChunks()) { | |
final List<Location> list = jackCache.get(chunk.getIdentifier()); | |
if (list == null || list.isEmpty()) { | |
continue; | |
} | |
for (Iterator<Location> iterator = list.iterator(); iterator.hasNext(); ) { | |
try (Timing ignored = jackTiming.startTiming()) { | |
Location loc = iterator.next(); | |
final Block block = loc.getBlock(); | |
final Material type = block.getType(); | |
if (type != Material.JACK_O_LANTERN && type != Material.PUMPKIN) { | |
iterator.remove(); | |
continue; | |
} | |
if (NumUtil.rand(1,3) != 1) { | |
continue; | |
} | |
byte data = block.getData(); | |
if (type == Material.PUMPKIN) { | |
block.setTypeIdAndData(Material.JACK_O_LANTERN.getId(), data, false); | |
} else { | |
block.setTypeIdAndData(Material.PUMPKIN.getId(), data, false); | |
} | |
} | |
} | |
} | |
} | |
private static void cycleMobs() { | |
if (world == null) { | |
return; | |
} | |
int limit = TimeUtil.MINUTE.inTicks(1); | |
int batLimit = TimeUtil.MINUTE.inTicks(3); | |
world.getEntities().forEach(entity -> { | |
final int ticksLived = entity.getTicksLived(); | |
if ((Util.isMonster(entity) && ticksLived > limit) || (entity instanceof Bat && ticksLived > batLimit)) { | |
entity.remove(); | |
} | |
}); | |
} | |
private static void spawnCandy(Location location) { | |
world.dropItemNaturally(location, Util.random(CANDIES)); | |
} | |
private static void worldEvent() { | |
if (world == null) { | |
return; | |
} | |
final Residence res = Residence.getResidenceByName("event"); | |
if (res == null) { | |
return; | |
} | |
final CuboidArea main = res.getArea("main"); | |
if (main == null) { | |
return; | |
} | |
final Location highLoc = main.getHighLoc(); | |
final Location lowLoc = main.getLowLoc(); | |
for (int i = 0, count = 0; i < 150 && count < 4; i++) { | |
int randX = NumUtil.rand(lowLoc.getBlockX(), highLoc.getBlockX()); | |
int randZ = NumUtil.rand(lowLoc.getBlockZ(), highLoc.getBlockZ()); | |
Location loc = new Location(world, randX, NumUtil.rand(20,60), randZ); | |
if (BlockUtil.isAreaAir(loc, 3)) { | |
count++; | |
spawnFirework(loc.clone(), NumUtil.rand(2, 6), NumUtil.rand(1,3), NumUtil.rand(1,3)); | |
spawnMob(loc.clone()); | |
} | |
} | |
} | |
private static void spawnMob(Location loc) { | |
loc.setY(world.getHighestBlockYAt(loc)+1); | |
Entity entity; | |
int type = NumUtil.rand(1, 6); | |
if (type == 1) { | |
entity = world.spawnEntity(loc, EntityType.SKELETON, SpawnReason.FORCE); | |
} else if (type == 2) { | |
entity = world.spawnEntity(loc, EntityType.ZOMBIE, SpawnReason.FORCE); | |
} else if (type == 3) { | |
entity = world.spawnEntity(loc, EntityType.PIG_ZOMBIE, SpawnReason.FORCE); | |
} else if (type == 4 && NumUtil.rand(1, 3) == 1) { | |
entity = world.spawnEntity(loc, EntityType.GHAST, SpawnReason.FORCE); | |
} else { | |
entity = world.spawnEntity(loc, EntityType.BAT, SpawnReason.FORCE); | |
} | |
if (entity instanceof Creature) { | |
Creature creature = (Creature) entity; | |
prepareMonster(creature); | |
} | |
} | |
private static void prepareMonster(Creature creature) { | |
ItemStack head = new ItemStack(Material.LEATHER_HELMET); | |
ItemStack body = new ItemStack(Material.LEATHER_CHESTPLATE); | |
ItemStack legs = new ItemStack(Material.LEATHER_LEGGINGS); | |
ItemStack boots = new ItemStack(Material.LEATHER_BOOTS); | |
CustomItems.colorLeatherItem(head, Util.randBool() ? 0x000000 : 0xffa500); | |
CustomItems.colorLeatherItem(body, Util.randBool() ? 0x000000 : 0xffa500); | |
CustomItems.colorLeatherItem(legs, Util.randBool() ? 0x000000 : 0xffa500); | |
CustomItems.colorLeatherItem(boots, Util.randBool() ? 0x000000 : 0xffa500); | |
final EntityEquipment equipment = creature.getEquipment(); | |
equipment.setHelmet(head); | |
equipment.setChestplate(body); | |
equipment.setLeggings(legs); | |
equipment.setBoots(boots); | |
EntityAIApi.makePeaceful(creature); | |
EntityAIApi.setTargetRange(creature, 0); | |
} | |
private static void spawnFirework(Location loc, int power, int oranges, int blacks) { | |
world.spawnEntity(loc, EntityType.FIREWORK, input -> { | |
if (input == null) { | |
return false; | |
} | |
Firework firework = (Firework) input; | |
FireworkMeta meta = firework.getFireworkMeta(); | |
meta.setPower(power); | |
final Type type = randType(); | |
final Color black = Color.fromRGB(0, 0, 0); | |
for (int i = 0; i < blacks; i++) { | |
meta.addEffects( | |
createEffect(type, black, randOrange(), true, false), | |
createEffect(type, black, randOrange(), false, true) | |
); | |
} | |
for (int i = 0; i < oranges; i++) { | |
meta.addEffects( | |
createEffect(type, randOrange(), black, true, false), | |
createEffect(type, randOrange(), black, false, true) | |
); | |
} | |
firework.setFireworkMeta(meta); | |
firework.detonate(); | |
return false; | |
}); | |
} | |
private static FireworkEffect createEffect(Type type, Color color, Color fade, boolean trail, boolean flicker) { | |
return FireworkEffect.builder().with(type).withColor(color).withFade(fade).trail(trail).flicker(flicker).build(); | |
} | |
private static Type randType() { | |
return Util.random(Type.values()); | |
} | |
private static Color randOrange() { | |
return Color.fromRGB(NumUtil.rand(255-5, 255), NumUtil.rand(165-10, 170), 0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment