diff --git a/src/main/java/fr/openmc/api/cooldown/DynamicCooldownManager.java b/src/main/java/fr/openmc/api/cooldown/DynamicCooldownManager.java index 47aea6ea9..2e6dc7349 100644 --- a/src/main/java/fr/openmc/api/cooldown/DynamicCooldownManager.java +++ b/src/main/java/fr/openmc/api/cooldown/DynamicCooldownManager.java @@ -270,9 +270,9 @@ public static void cleanup() { public static void clear(String group) { cooldowns.forEach((uuid, userCooldowns) -> { Cooldown removed = userCooldowns.remove(group); - if (removed != null) removed.cancelTask(); + clear(removed); }); - cooldowns.entrySet().removeIf(entry -> entry.getValue().isEmpty()); // A test + cooldowns.entrySet().removeIf(entry -> entry.getValue().isEmpty()); } /** @@ -288,8 +288,19 @@ public static void clear(UUID uuid, String group, boolean callEvent) { if (callEvent) Bukkit.getPluginManager().callEvent(new CooldownEndEvent(uuid, group)); Cooldown removed = userCooldowns.remove(group); - if (removed != null) removed.cancelTask(); + clear(removed); if (userCooldowns.isEmpty()) cooldowns.remove(uuid); } } + + private static void clear(Cooldown cooldown) { + if (cooldown == null) return; + + cooldown.cancelTask(); + try { + cooldownDao.delete(cooldown); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } } diff --git a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java index 64e8b396e..948e2d085 100644 --- a/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java +++ b/src/main/java/fr/openmc/api/datapacks/OMCDatapack.java @@ -2,7 +2,7 @@ import fr.openmc.api.datapacks.injectors.PackMetadataInjector; import fr.openmc.core.OMCPlugin; -import fr.openmc.core.utils.FilesUtils; +import fr.openmc.core.utils.file.FilesUtils; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import lombok.Getter; diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index cf22b4ed9..b963168ee 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -35,7 +35,8 @@ import fr.openmc.core.features.economy.TransactionsManager; import fr.openmc.core.features.events.EventsManager; import fr.openmc.core.features.events.contents.dailyevents.DailyEventsManager; -import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +//import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; import fr.openmc.core.features.events.contents.open.OpenManager; import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestParticlesUtils; @@ -63,6 +64,7 @@ import fr.openmc.core.hooks.github.GitHubHook; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; import fr.openmc.core.listeners.ItemsAddersListener; +import fr.openmc.core.registry.structures.model.CustomStructureManager; import fr.openmc.core.utils.text.MotdUtils; import io.papermc.paper.datapack.Datapack; import lombok.Getter; @@ -112,7 +114,7 @@ public class OMCPlugin extends JavaPlugin { AdminShopManager::new, HelpConfigManager::new, () -> new AnimationsManager(), - () -> new HalloweenManager(), +// () -> new HalloweenManager(), pas cette année mon vieux QuestProgressSaveManager::new, MotdUtils::new, MascotsManager::new, @@ -120,6 +122,8 @@ public class OMCPlugin extends JavaPlugin { MailboxManager::new, DiscordLinkManager::new, ProfileManager::new, + CustomStructureManager::new, + () -> new HalloweenFestivalManager(), () -> new ElevatorManager(), () -> new CorpseManager(), QuestsManager::new, @@ -152,7 +156,8 @@ public class OMCPlugin extends JavaPlugin { new WorldGuardHook(), new ItemsAdderHook(), new FancyNpcsHook(), - new GitHubHook() + new GitHubHook(), + new WorldEditHook() )); @Override diff --git a/src/main/java/fr/openmc/core/OMCRegistry.java b/src/main/java/fr/openmc/core/OMCRegistry.java index 94db57547..5fbc753f8 100644 --- a/src/main/java/fr/openmc/core/OMCRegistry.java +++ b/src/main/java/fr/openmc/core/OMCRegistry.java @@ -14,6 +14,7 @@ import fr.openmc.core.registry.loottable.CustomLootTableRegistry; import fr.openmc.core.registry.mobs.CustomMobRegistry; import fr.openmc.core.registry.regions.CustomRegionRegistry; +import fr.openmc.core.registry.structures.CustomStructureRegistry; import fr.openmc.riftengine.api.registry.scanner.ScannerRegistry; import fr.openmc.core.registry.worldtemplates.WorldTemplateRegistry; import io.papermc.paper.plugin.bootstrap.BootstrapContext; @@ -32,6 +33,7 @@ public final class OMCRegistry { public static CustomLootTableRegistry CUSTOM_LOOT_TABLES; public static CustomAmbientRegistry CUSTOM_AMBIENTS; public static CustomLootboxRegistry CUSTOM_LOOTBOXES; + public static CustomStructureRegistry CUSTOM_STRUCTURES; public static CustomRegionRegistry CUSTOM_REGIONS; public static WorldTemplateRegistry WORLD_TEMPLATES; @@ -62,6 +64,8 @@ public final class OMCRegistry { RegistryLoadingType.AFTER_IA), new RegistryContext(() -> CUSTOM_MOBS = new CustomMobRegistry(), RegistryLoadingType.AFTER_IA), + new RegistryContext(() -> CUSTOM_STRUCTURES = new CustomStructureRegistry(), + RegistryLoadingType.AFTER_IA), new RegistryContext(() -> WORLD_TEMPLATES = new WorldTemplateRegistry(), RegistryLoadingType.BOOTSTRAP, RegistryLoadingType.RUNTIME), new RegistryContext(() -> WEEKLY_EVENTS = new WeeklyEventsRegistry(), diff --git a/src/main/java/fr/openmc/core/bootstrap/integration/DatapackLoader.java b/src/main/java/fr/openmc/core/bootstrap/integration/DatapackLoader.java index 5e5f23b32..6eebc1e64 100644 --- a/src/main/java/fr/openmc/core/bootstrap/integration/DatapackLoader.java +++ b/src/main/java/fr/openmc/core/bootstrap/integration/DatapackLoader.java @@ -1,6 +1,6 @@ package fr.openmc.core.bootstrap.integration; -import fr.openmc.core.utils.FilesUtils; +import fr.openmc.core.utils.file.FilesUtils; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; diff --git a/src/main/java/fr/openmc/core/bootstrap/integration/ResourcePacksGenerator.java b/src/main/java/fr/openmc/core/bootstrap/integration/ResourcePacksGenerator.java index 6fa895c18..a865e8852 100644 --- a/src/main/java/fr/openmc/core/bootstrap/integration/ResourcePacksGenerator.java +++ b/src/main/java/fr/openmc/core/bootstrap/integration/ResourcePacksGenerator.java @@ -1,6 +1,6 @@ package fr.openmc.core.bootstrap.integration; -import fr.openmc.core.utils.FilesUtils; +import fr.openmc.core.utils.file.FilesUtils; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import java.io.IOException; diff --git a/src/main/java/fr/openmc/core/features/dimopener/DimensionOpenerManager.java b/src/main/java/fr/openmc/core/features/dimopener/DimensionOpenerManager.java index e927baf7c..60909895b 100644 --- a/src/main/java/fr/openmc/core/features/dimopener/DimensionOpenerManager.java +++ b/src/main/java/fr/openmc/core/features/dimopener/DimensionOpenerManager.java @@ -16,7 +16,7 @@ import fr.openmc.core.features.dimopener.listener.DimensionAccessListener; import fr.openmc.core.features.economy.EconomyManager; import fr.openmc.core.registry.items.CustomItem; -import fr.openmc.core.utils.FilesUtils; +import fr.openmc.core.utils.file.FilesUtils; import fr.openmc.core.utils.text.messages.MessageType; import fr.openmc.core.utils.text.messages.MessagesManager; import fr.openmc.core.utils.text.messages.Prefix; diff --git a/src/main/java/fr/openmc/core/features/displays/scoreboards/BaseScoreboard.java b/src/main/java/fr/openmc/core/features/displays/scoreboards/BaseScoreboard.java index 41ac353c3..5ee0de4da 100644 --- a/src/main/java/fr/openmc/core/features/displays/scoreboards/BaseScoreboard.java +++ b/src/main/java/fr/openmc/core/features/displays/scoreboards/BaseScoreboard.java @@ -151,7 +151,10 @@ private InfoSwapper getNextInfo() { infos = infos.stream().filter(InfoSwapper::isActive).toList(); - if (infos.size() <= 1) + if (infos.size() == 1) + return infos.getFirst(); + + if (infos.isEmpty()) return null; currentSwappingInfoIndex = (currentSwappingInfoIndex + 1) % infos.size(); diff --git a/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java b/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java index 697df1ab3..66575330c 100644 --- a/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java +++ b/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java @@ -12,8 +12,9 @@ import fr.openmc.core.features.corpse.npc.CorpseNPCManager; import fr.openmc.core.features.displays.scoreboards.BaseScoreboard; import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; import fr.openmc.core.features.events.sbinfos.ContestInfos; +import fr.openmc.core.features.events.sbinfos.HalloweenFestivalInfos; import fr.openmc.core.hooks.FancyNpcsHook; import fr.openmc.core.hooks.LuckPermsHook; import fr.openmc.core.hooks.WorldGuardHook; @@ -71,7 +72,7 @@ public void update(Player player, SternalBoard board) { @Override protected List getSwapping() { return List.of( - //new HalloweenFestivalInfos(), + new HalloweenFestivalInfos(), new ContestInfos() ); } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/CandyItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/CandyItem.java new file mode 100644 index 000000000..a6c1b8df0 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/CandyItem.java @@ -0,0 +1,37 @@ +package fr.openmc.core.features.events.contents.halloween.festival; + +import fr.openmc.core.registry.items.CustomItem; +import fr.openmc.core.registry.items.CustomItemMeta; +import fr.openmc.core.utils.text.messages.TranslationManager; +import lombok.Getter; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jspecify.annotations.NonNull; + +import java.util.HashMap; +import java.util.Map; + +public class CandyItem extends CustomItem { + + @Getter + public int diabetesIndex; + public Material baseItem; + + public static final Map candies = new HashMap<>(); + + public CandyItem(String candyID , int diabetesIndex, Material baseItem) { + super(new CustomItemMeta(candyID)); + this.diabetesIndex = diabetesIndex; + this.baseItem = baseItem; + candies.put(candyID, this); + } + + @Override + public @NonNull ItemStack getVanilla() { + ItemStack item = new ItemStack(baseItem); + item.editMeta(meta -> meta.itemName( + TranslationManager.translation("itemsadder." + super.getId().replace(":", ".") + ".name") + )); + return item; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java new file mode 100644 index 000000000..4287bd91b --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java @@ -0,0 +1,234 @@ +package fr.openmc.core.features.events.contents.halloween.festival; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; +import fr.openmc.api.cooldown.DynamicCooldownManager; +import fr.openmc.api.omcplayer.OMCOfflinePlayer; +import fr.openmc.api.omcplayer.OMCPlayer; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.bootstrap.features.Feature; +import fr.openmc.core.bootstrap.features.types.*; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.bootstrap.listeners.ListenerFactory; +import fr.openmc.core.features.events.contents.halloween.festival.commands.HalloweenFestivalCommands; +import fr.openmc.core.features.events.contents.halloween.festival.listeners.TerrorHouseListener; +import fr.openmc.core.features.events.contents.halloween.festival.npc.WitchNPCS; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.listeners.CandyListener; +import fr.openmc.core.features.events.contents.halloween.festival.model.HalloweenDB; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests.LootChestManager; +import fr.openmc.core.features.mailboxes.MailboxManager; +import fr.openmc.core.hooks.WorldEditHook; +import fr.openmc.core.registry.structures.model.CustomStructureManager; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import net.minecraft.core.UUIDUtil; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.inventory.ItemStack; + +import java.sql.SQLException; +import java.util.*; +import java.util.concurrent.ExecutionException; + +public class HalloweenFestivalManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { + + @Getter + private static HalloweenDB halloweenDB; + + private static Dao halloweenDao; + + @Getter + private static Set participant; + + public static final String EVENT_GROUP = "halloween_festival_event"; + private static final UUID EVENT_UUID = UUIDUtil.createOfflinePlayerUUID(EVENT_GROUP); + private static final UUID TERROR_HOUSE_UUID = UUIDUtil.createOfflinePlayerUUID("halloween_terror_house"); + + @Override + public void init() { + halloweenDB = loadEvent(); + participant = halloweenDB.getParticipants(); + DimensionGenerator.init(); + WitchShopManager.init(); + TerrorHouseManager.init( + halloweenDB.getGlobalAdvancement(), + halloweenDB.getFloorAdvancement() + ); + new LootChestManager(); + } + + @Override + public void initDB(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTableIfNotExists(connectionSource, HalloweenDB.class); + halloweenDao = DaoManager.createDao(connectionSource, HalloweenDB.class); + } + + @Override + protected void save() { + saveEvent(); + } + + public static HalloweenDB loadEvent() { + try { + HalloweenDB halloweenDB = halloweenDao.queryForFirst(); + + if (halloweenDB == null) { + halloweenDB = new HalloweenDB(0, 0, false); + halloweenDao.create(halloweenDB); + } + + return halloweenDB; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void saveEvent() { + try { + halloweenDB.setFloorAdvancement(TerrorHouseManager.floorAdvancement); + halloweenDB.setGlobalAdvancement(TerrorHouseManager.globalAdvancement); + halloweenDB.setParticipants(participant); + + halloweenDao.createOrUpdate(halloweenDB); + } catch (Exception e) { + OMCLogger.error( + "Impossible de sauvegarder l'event d'halloween pendant l'arrêt.", + e + ); + } + } + + public static void startEvent(long duration) { + if (hasStart()) + return; + + DynamicCooldownManager.use(EVENT_UUID, EVENT_GROUP, duration); + halloweenDB.setActive(true); + broadcast(TranslationManager.translation( + "feature.events.halloween.festival.start_message", + Component.text(2026).color(NamedTextColor.GOLD).decorate(TextDecoration.BOLD) + )); + } + + public static void stopEvent() { + if (!DynamicCooldownManager.isReady(EVENT_UUID, EVENT_GROUP)) { + DynamicCooldownManager.clear(EVENT_UUID, EVENT_GROUP, false); + } + halloweenDB.setActive(false); + broadcast(TranslationManager.translation( + "feature.events.halloween.festival.end_message", + Component.text(2026).color(NamedTextColor.GOLD).decorate(TextDecoration.BOLD) + )); + } + + public static void forceStopEvent() { + DynamicCooldownManager.clear(EVENT_UUID, EVENT_GROUP, false); + halloweenDB.setActive(false); + broadcast(TranslationManager.translation("feature.events.halloween.festival.end_message", Component.text(2026))); + } + + public static boolean hasStart() { + return DynamicCooldownManager.getCooldowns(EVENT_UUID) != null; + } + + public static long getRemainingTime() { + if (!hasStart()) return 0; + return DynamicCooldownManager.getRemaining(EVENT_UUID, EVENT_GROUP); + } + + public static boolean hasParticipant(UUID uuid) { + return participant.contains(uuid); + } + + public static boolean isActive() { + return halloweenDB.isActive(); + } + + public static void addParticipant(UUID uuid) { + participant.add(uuid); + } + + public static void broadcast(Component text) { + OMCPlugin.getInstance().getServer().getOnlinePlayers().forEach( + player -> MessagesManager.sendMessage(player, text, Prefix.HALLOWEEN, MessageType.INFO, true) + ); + } + + public static void sendMailItems(OMCPlayer player, OMCOfflinePlayer receiver, ItemStack[] items) { + Bukkit.getScheduler().runTask(OMCPlugin.getInstance(), () -> { + if (!MailboxManager.sendItems(player, receiver, items)) + MailboxManager.givePlayerItems(player, items); + }); + } + + public static void placeWitchStore(Location location) { + try { + OMCRegistry.CUSTOM_STRUCTURES.WITCH_SHOP.place(EVENT_UUID, location); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void removeWitchStore() { + try { + OMCRegistry.CUSTOM_STRUCTURES.WITCH_SHOP.remove(EVENT_UUID); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void placeTerrorHouse() { + + try { + if (CustomStructureManager.existsPlacement(TERROR_HOUSE_UUID)) + return; + } catch (SQLException e) { + throw new RuntimeException(e); + } + + try { + OMCRegistry.CUSTOM_STRUCTURES.TERROR_HOUSE.place( + TERROR_HOUSE_UUID, + new Location(DimensionGenerator.HALLOWEEN_WORLD, 0, 0, 0) + ); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void removeTerrorHouse() { + try { + OMCRegistry.CUSTOM_STRUCTURES.TERROR_HOUSE.remove(TERROR_HOUSE_UUID); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Set getListeners() { + return Set.of( + CandyListener::new, + TerrorHouseListener::new, + WitchNPCS::new + ); + } + + @Override + public Set getCommands() { + return Set.of( + new HalloweenFestivalCommands() + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/commands/HalloweenFestivalCommands.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/commands/HalloweenFestivalCommands.java new file mode 100644 index 000000000..814eb6ba4 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/commands/HalloweenFestivalCommands.java @@ -0,0 +1,58 @@ +package fr.openmc.core.features.events.contents.halloween.festival.commands; + +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.npc.WitchNPCS; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopMainMenu; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopStoreMenu; +import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; +import org.bukkit.entity.Player; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.Subcommand; +import revxrsal.commands.bukkit.annotation.CommandPermission; + +@Command("halloween_festival") +public class HalloweenFestivalCommands { + + // two weeks 14L * 24 * 60 * 60 * 1000 = 1_209_600_000 + + @Subcommand("start") + @CommandPermission("omc.admins.commands.halloween_festival.start") + public void startHalloweenFestival(long duration) { + HalloweenFestivalManager.startEvent(duration); + } + + @Subcommand("force-end") + @CommandPermission("omc.admins.commands.halloween_festival.force-end") + public void endHalloweenFestival() { + HalloweenFestivalManager.forceStopEvent(); + } + + @Subcommand("store") + public void openStoreMenu(Player player) { + new WitchShopStoreMenu(player, 1).open(); + } + + @Subcommand("place house") + @CommandPermission("omc.admins.commands.halloween_festival.place.house") + public void placeHouse(Player player) { + HalloweenFestivalManager.placeTerrorHouse(); + } + + @Subcommand("remove house") + @CommandPermission("omc.admins.commands.halloween_festival.remove.house") + public void removeHouse(Player player) { + HalloweenFestivalManager.removeTerrorHouse(); + } + + @Subcommand("place npc") + @CommandPermission("omc.admins.commands.halloween_festival.place.npc") + public void placeNPC(Player player) { + WitchNPCS.createNPC(player.getLocation()); + } + + @Subcommand("remove npc") + @CommandPermission("omc.admins.commands.halloween_festival.remove.npc") + public void removeNPC(Player player) { + WitchNPCS.removeNPCS(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/CandyListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/CandyListener.java new file mode 100644 index 000000000..152cf2001 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/CandyListener.java @@ -0,0 +1,48 @@ +package fr.openmc.core.features.events.contents.halloween.festival.listeners; + +import dev.lone.itemsadder.api.CustomStack; +import fr.openmc.core.features.events.contents.halloween.festival.CandyItem; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class CandyListener implements Listener { + + private final Map sugarIndex = new HashMap<>(); + + @EventHandler + public void onCandyEat(PlayerItemConsumeEvent event) { + Player player = event.getPlayer(); + ItemStack item = event.getItem(); + + CustomStack stack = CustomStack.byItemStack(item); + + if (stack == null) return; + + if (!CandyItem.candies.containsKey(stack.getId())) return; + + CandyItem candy = CandyItem.candies.get(stack.getId()); + + UUID uuid = player.getUniqueId(); + + int sugarIdx = sugarIndex.computeIfAbsent(uuid, key -> 0); + + sugarIdx += candy.getDiabetesIndex(); + + if (sugarIdx >= 20) { + player.addPotionEffect(new PotionEffect(PotionEffectType.NAUSEA, 20 * 20, 0)); + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 20 * 20, 1)); + sugarIndex.put(uuid, 0); + } else + sugarIndex.put(uuid, sugarIdx); + } + +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java new file mode 100644 index 000000000..2e85e3937 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java @@ -0,0 +1,166 @@ +package fr.openmc.core.features.events.contents.halloween.festival.listeners; + +import fr.openmc.api.cooldown.CooldownEndEvent; +import fr.openmc.core.commands.utils.SpawnManager; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floors; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests.LootChestManager; +import fr.openmc.core.registry.regions.CustomRegion; +import fr.openmc.core.registry.regions.events.EntityCustomRegionEnterEvent; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.entity.EntityToggleGlideEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.inventory.EquipmentSlot; + +public class TerrorHouseListener implements Listener { + + @EventHandler + public void onEventEnd(CooldownEndEvent event) { + if (!event.getGroup().equals(HalloweenFestivalManager.EVENT_GROUP)) return; + + HalloweenFestivalManager.stopEvent(); + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + player.teleport(SpawnManager.getSpawnLocation()); + } + + @EventHandler + public void onPlayerDeath(PlayerDeathEvent event) { + Player player = event.getPlayer(); + + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) { + player.teleport(SpawnManager.getSpawnLocation()); + event.setCancelled(true); + } + } + + @EventHandler + public void onWorldChange(PlayerChangedWorldEvent event) { + Player player = event.getPlayer(); + + if (HalloweenFestivalManager.getHalloweenDB().isActive()) { + if (event.getFrom().equals(DimensionGenerator.HALLOWEEN_WORLD)) + TerrorHouseManager.getWitchHouseAmbient().reset(player); + + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + TerrorHouseManager.getWitchHouseAmbient().apply(player); + } else { + if (player.isOp()) return; + + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) { + player.teleport(SpawnManager.getSpawnLocation()); + MessagesManager.sendMessage(player, + TranslationManager.translation("feature.events.halloween.festival.player_not_allow"), + Prefix.HALLOWEEN, + MessageType.INFO, + true + ); + } + } + } + + @EventHandler + public void onHouseRegionEnter(EntityCustomRegionEnterEvent event) { + CustomRegion region = event.getRegion(); + + if (!region.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + return; + + Entity entity = event.getEntity(); + + Floors floors = TerrorHouseManager.enabledFloors.stream() + .filter(floor -> floor.getFloor().getRegion().equals(region)) + .findAny().orElse(null); + + if (floors == null) + checkAndRepulse(region, entity); + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Block block = event.getClickedBlock(); + + if (!event.getPlayer().getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + return; + + if (block != null && block.getType().equals(Material.CHEST)) { + LootChestManager.openChestAt(block.getLocation(), event.getPlayer()); + event.setCancelled(true); + return; + } + + if (event.getHand() != EquipmentSlot.HAND) + return; + + Material item = event.getMaterial(); + + if (item == Material.ENDER_PEARL || item == Material.CHORUS_FRUIT || item == Material.WIND_CHARGE) { + event.setCancelled(true); + MessagesManager.sendMessage( + event.getPlayer(), + TranslationManager.translation("feature.events.halloween.festival.player_not_allow"), + Prefix.HALLOWEEN, + MessageType.INFO, + false + ); + } + } + + @EventHandler + public void onPlayerBreakBlock(BlockBreakEvent event) { + if (!event.getPlayer().getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + return; + + if (!event.getPlayer().isOp()) + event.setCancelled(true); + } + + @EventHandler + public void onPlayerToggleGlide(EntityToggleGlideEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + + if (event.isGliding()) { + event.setCancelled(true); + MessagesManager.sendMessage( + player, + TranslationManager.translation("feature.events.halloween.festival.player_not_allow"), + Prefix.HALLOWEEN, + MessageType.INFO, + false + ); + } + } + + private void checkAndRepulse(CustomRegion region, Entity entity) { + if (TerrorHouseManager.useRegions.contains(region)) + if (entity instanceof Player player) { + TerrorHouseManager.repulsePlayer(region, player, -2); + MessagesManager.sendMessage(player, + TranslationManager.translation("feature.events.halloween.festival.floor_lock"), + Prefix.HALLOWEEN, + MessageType.INFO, + true + ); + } + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/model/HalloweenDB.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/model/HalloweenDB.java new file mode 100644 index 000000000..ea2431493 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/model/HalloweenDB.java @@ -0,0 +1,57 @@ +package fr.openmc.core.features.events.contents.halloween.festival.model; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; +import lombok.Setter; + +import java.lang.reflect.Type; +import java.util.*; + +@Getter +@Setter +@DatabaseTable(tableName = "halloween_festival_event") +public class HalloweenDB { + + private static final Gson GSON = new Gson(); + + private static final Type UUID_SET_TYPE = + new TypeToken>() {}.getType(); + + @DatabaseField(columnName = "global_advancement") + private int globalAdvancement; + + @DatabaseField(columnName = "floor_advancement") + private int floorAdvancement; + + @DatabaseField(columnName = "is_active") + private boolean active; + + @DatabaseField(generatedId = true) + private int id; + + @Getter(lombok.AccessLevel.NONE) + @Setter(lombok.AccessLevel.NONE) + @DatabaseField(columnName = "participants") + private String participantsJson = "[]"; + + public HalloweenDB() { + } + + public HalloweenDB(int globalAdvancement, int floorAdvancement, boolean active) { + this.globalAdvancement = globalAdvancement; + this.floorAdvancement = floorAdvancement; + this.active = active; + } + + public Set getParticipants() { + Set participants = GSON.fromJson(participantsJson, UUID_SET_TYPE); + return participants != null ? participants : new HashSet<>(); + } + + public void setParticipants(Set participants) { + this.participantsJson = GSON.toJson(participants); + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/npc/WitchNPCS.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/npc/WitchNPCS.java new file mode 100644 index 000000000..2f2a53f15 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/npc/WitchNPCS.java @@ -0,0 +1,87 @@ +package fr.openmc.core.features.events.contents.halloween.festival.npc; + +import de.oliver.fancynpcs.api.FancyNpcsPlugin; +import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.NpcData; +import de.oliver.fancynpcs.api.data.property.NpcVisibility; +import de.oliver.fancynpcs.api.events.NpcInteractEvent; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopMainMenu; +import fr.openmc.core.hooks.FancyNpcsHook; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class WitchNPCS implements Listener { + + public static List witchNPCS = new ArrayList<>(); + + private static final Sound WITCH_MENU_OPEN = Sound.ENTITY_WITCH_CELEBRATE; + + public WitchNPCS() { + // fetch les npcs apres 30 secondes le temps que fancy npc s'initialise. + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { + FancyNpcsPlugin.get().getNpcManager().getAllNpcs().forEach(npc -> { + if (npc.getData().getName().startsWith("witch-")) { + witchNPCS.add(npc); + } + }); + }, 20L * 30); + } + + public static boolean createNPC(Location location) { + if (!FancyNpcsHook.isEnable()) return false; + + UUID uuid = UUID.randomUUID(); + + NpcData dataCorpse = new NpcData("witch-" + uuid, uuid, location); + + dataCorpse.setType(EntityType.WITCH); + + dataCorpse.setDisplayName(""); + + dataCorpse.setVisibility(NpcVisibility.ALL); + + Npc npcWitch = FancyNpcsPlugin.get().getNpcAdapter().apply(dataCorpse); + + FancyNpcsPlugin.get().getNpcManager().registerNpc(npcWitch); + + npcWitch.create(); + + Bukkit.getScheduler().runTaskAsynchronously(OMCPlugin.getInstance(), npcWitch::spawnForAll); + + witchNPCS.add(npcWitch); + + return true; + } + + public static void removeNPCS() { + if (!FancyNpcsHook.isEnable()) return; + + witchNPCS.forEach(npc -> FancyNpcsPlugin.get().getNpcManager().removeNpc(npc)); + witchNPCS.clear(); + } + + @EventHandler + public void onNPCInteract(NpcInteractEvent event) { + if (!event.getNpc().getData().getName().startsWith("witch-")) return; + + if (!HalloweenFestivalManager.isActive()) + return; + + Player player = event.getPlayer(); + + player.playSound(player, WITCH_MENU_OPEN, 1f, 1f); + + new WitchShopMainMenu(player).open(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java new file mode 100644 index 000000000..aca4768da --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java @@ -0,0 +1,27 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.registry.items.CustomItem; +import fr.openmc.core.utils.text.messages.TranslationManager; +import lombok.Getter; +import net.kyori.adventure.text.Component; + +@Getter +public enum ShopMoney { + RED_CANDY(TranslationManager.translation("itemsadder.omc_halloween.candy_red.name"), OMCRegistry.CUSTOM_ITEMS.CANDY_RED, 1000), + YELLOW_CANDY(TranslationManager.translation("itemsadder.omc_halloween.candy_yellow.name"), OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW, 10000), //extremely rare no craft + GREEN_CANDY(TranslationManager.translation("itemsadder.omc_halloween.candy_green.name"), OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 10), + BLUE_CANDY(TranslationManager.translation("itemsadder.omc_halloween.candy_blue.name"), OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 100), + MONSTER_CANDY(TranslationManager.translation("itemsadder.omc_halloween.candy_brown.name"), OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 1), + ; + + private final Component name; + private final CustomItem item; + private final int scores; + + ShopMoney(Component name, CustomItem item, int scores) { + this.name = name; + this.item = item; + this.scores = scores; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopItem.java new file mode 100644 index 000000000..bef1c30af --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopItem.java @@ -0,0 +1,42 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop; + +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floors; +import fr.openmc.core.registry.items.CustomItem; +import lombok.Getter; +import net.kyori.adventure.text.Component; + +public class WitchShopItem { + + @Getter public final Floors advancements; + @Getter public final CustomItem item; + public final Component name; + @Getter public final ShopMoney shopMoney; + @Getter public final int price; + + + public WitchShopItem(Floors advancements, CustomItem item, Component name, ShopMoney moneyItem, int price) { + this.advancements = advancements; + this.item = item; + this.name = name; + this.shopMoney = moneyItem; + this.price = price; + } + public WitchShopItem(Floors advancements, CustomItem item, Component name, int price) { + this(advancements, item, name, ShopMoney.MONSTER_CANDY, price); + } + + public WitchShopItem(Floors advancements, CustomItem item, ShopMoney moneyItem, int price) { + this(advancements, item, item.getBest().effectiveName(), moneyItem, price); + } + + public WitchShopItem(Floors advancements, CustomItem item, int price) { + this(advancements, item, item.getBest().effectiveName(), price); + } + + public Component getName() { + if (TerrorHouseManager.enabledFloors.contains(advancements)) + return name; + return Component.text("§knotunlockyet"); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopManager.java new file mode 100644 index 000000000..3887cc32d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopManager.java @@ -0,0 +1,263 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.omcplayer.OMCPlayer; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.adminshop.AdminShopUtils; +import fr.openmc.core.features.economy.EconomyManager; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floors; +import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; +import fr.openmc.core.utils.bukkit.ItemUtils; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Sound; +import org.bukkit.entity.Player; + +import java.util.*; + +public class WitchShopManager { + + public static LinkedHashSet witchStoreItems; + public static Map> paginateWitchStoreItems; + + public static int maxPage; + + public static int SLOT_FACTOR = 28; + private static final Sound BUY_SOUND = Sound.ENTITY_WITCH_CELEBRATE; + private static final Sound ERROR_SOUND = Sound.ENTITY_WITCH_AMBIENT; + + public static void init() { + witchStoreItems = getWitchStoreItems(); + paginateWitchStoreItems = getPaginateWitchStoreItems(); + maxPage = getWitchStorePages(); + } + + private static Map> getPaginateWitchStoreItems() { + Map> paginateItems = new HashMap<>(); + + List list = new ArrayList<>(witchStoreItems); + + int page = 1; + + for (int i = 0; i < list.size(); i += SLOT_FACTOR) { + Set subItems = new LinkedHashSet<>( + list.subList(i, Math.min(i + SLOT_FACTOR, list.size())) + ); + + paginateItems.put(page++, subItems); + } + + return paginateItems; + } + + public static Set getStoreContent(int page) { + if (paginateWitchStoreItems == null) + paginateWitchStoreItems = getPaginateWitchStoreItems(); + + if (page > maxPage) + page = maxPage; + + return paginateWitchStoreItems.get(page); + } + + private static int getWitchStorePages() { + return paginateWitchStoreItems.size(); + } + + public static void buyItem(Player player, WitchShopItem item, int amount) { + if (item == null) return; + + if (amount <= 0) { + sendError(player, TranslationManager.translation("feature.adminshop.amount_sup")); + return; + } + + if (!ItemUtils.hasEnoughSpace(player, item.getItem().getBest(), amount)) { + sendError(player, TranslationManager.translation("feature.adminshop.inventory_full")); + return; + } + + int totalPrice = item.getPrice() * amount; + if (ItemUtils.hasEnoughItems(player, item.getShopMoney().getItem().getBest(), totalPrice)) { + + ItemUtils.giveItem((OMCPlayer) player, item.getItem().getBest(), amount); + + ItemUtils.removeItemsFromPlayerInventory(player, item.getShopMoney().getItem().getBest(), totalPrice); + + sendInfo(player, TranslationManager.translation( + "feature.events.halloween.festival.shop.player_buy_item", + Component.text(amount), + item.getName(), + Component.text(totalPrice), + item.getShopMoney().getItem().getSprite() + )); + + player.playSound(player, BUY_SOUND, 1f, new Random().nextFloat(0.6f, 1.4f)); + + TerrorHouseManager.updateAdvancement(item.getShopMoney().getScores() * item.getPrice()); + + HalloweenFestivalManager.addParticipant(player.getUniqueId()); + + } else { + sendError(player, TranslationManager.translation( + "feature.events.halloween.festival.player_not_enough_item", + item.getShopMoney().getName() + )); + } + } + + /** + * Handles the selling of an item by the player. + * + * @param player The player selling the item. + * @param item The item sell. + * @param amount The quantity to sell. + */ + public static void sellItem(Player player, ShopMoney item, int amount) { + if (item == null) return; + + if (amount <= 0) { + sendError(player, TranslationManager.translation("feature.adminshop.amount_sup")); + return; + } + + // Check if the player has enough items to sell + if (!ItemUtils.hasEnoughItems(player, item.getItem().getBest(), amount)) { + sendError(player, TranslationManager.translation( + "feature.events.halloween.festival.player_not_enough_item", + item.getName() + )); + return; + } + + int totalScore = item.getScores() * amount; // Calculate the total price for the items + ItemUtils.removeItemsFromPlayerInventory(player, item.getItem().getBest(), amount); // Remove items from the player's inventory + + player.playSound(player, BUY_SOUND, 1f, new Random().nextFloat(0.6f, 1.4f)); + + TerrorHouseManager.updateAdvancement(totalScore); + + if (totalScore >= 100_000) { + + HalloweenFestivalManager.broadcast(TranslationManager.translation( + "feature.events.halloween.festival.deposit.broadcast_add_point", + player.displayName(), + Component.text(EconomyManager.getFormattedSimplifiedNumber(totalScore)), + Component.text(getHalloweenPointIcon()), + Component.text(amount), + item.getItem().getSprite() + ).color(NamedTextColor.GOLD)); + } else { + sendInfo(player, TranslationManager.translation( + "feature.events.halloween.festival.deposit.add_point", + Component.text(EconomyManager.getFormattedSimplifiedNumber(totalScore)), + Component.text(getHalloweenPointIcon()), + Component.text(amount), + item.getItem().getSprite() + )); + } + } + + private static void sendError(Player player, Component message) { + MessagesManager.sendMessage(player, message, Prefix.HALLOWEEN, MessageType.ERROR, true); + player.playSound(player, ERROR_SOUND, 1f,1f); + } + + private static void sendInfo(Player player, Component message) { + MessagesManager.sendMessage(player, message, Prefix.HALLOWEEN, MessageType.INFO, true); + } + + public static List extractLoreForItem(WitchShopItem item) { + List lore = new ArrayList<>(); + + if (TerrorHouseManager.enabledFloors.contains(item.getAdvancements())) { + lore.add(TranslationManager.translation("feature.events.halloween.festival.shop.lore_item.buy", + getPrice(item) + ).color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); + lore.add(TranslationManager.translation("feature.events.halloween.festival.shop.lore_item.point", + Component.text(item.getShopMoney().getScores() * item.getPrice()), + Component.text(getHalloweenPointIcon()) + ).decoration(TextDecoration.ITALIC, false).color(NamedTextColor.GOLD)); + + } + else { + lore.add(TranslationManager.translation("feature.events.halloween.festival.shop.lore_item.lock", + Component.text(item.getAdvancements().getSimplifyFloor())) + ); + } + + return lore; + } + + public static Component getPrice(WitchShopItem item) { + return Component.text(item.getPrice()) + .appendSpace() + .append(item.getShopMoney().getItem().getSprite()); + } + + public static String getHalloweenPointIcon() { + if (ItemsAdderHook.isEnable()) { + return FontImageWrapper.replaceFontImages("§f:halloween_point:"); + } else { + return "Ⓟ"; + } + } + + private static LinkedHashSet getWitchStoreItems() { + LinkedHashSet items = new LinkedHashSet<>(); + + items.add(new WitchShopItem(Floors.FLOOR_1, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_CANDLE, 10)); + items.add(new WitchShopItem(Floors.FLOOR_1, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_PUMPKIN, 10)); + + items.add(new WitchShopItem(Floors.FLOOR_2, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_PUMPKIN_1, 15)); + items.add(new WitchShopItem(Floors.FLOOR_2, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_WOOD_CROSS, 15)); + + items.add(new WitchShopItem(Floors.FLOOR_3, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_SKULL_JAR, 20)); + items.add(new WitchShopItem(Floors.FLOOR_3, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_TOMBE_1, 20)); + + items.add(new WitchShopItem(Floors.FLOOR_4, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_PUMPKIN_2, 25)); + items.add(new WitchShopItem(Floors.FLOOR_4, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_CAULDRON, 25)); + + items.add(new WitchShopItem(Floors.FLOOR_5, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_SPIDER_IN_JAR, ShopMoney.GREEN_CANDY, 5)); + + items.add(new WitchShopItem(Floors.FLOOR_6, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_ROSE_IN_GLASS, ShopMoney.GREEN_CANDY, 10)); + + items.add(new WitchShopItem(Floors.FLOOR_7, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_PICTURE, ShopMoney.GREEN_CANDY, 10)); + items.add(new WitchShopItem(Floors.FLOOR_7, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_TOMBE_2, ShopMoney.GREEN_CANDY, 10)); + + items.add(new WitchShopItem(Floors.FLOOR_8, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_PUMPKIN_3, ShopMoney.BLUE_CANDY, 5)); + items.add(new WitchShopItem(Floors.FLOOR_8, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_COFFIN_OPEN, ShopMoney.BLUE_CANDY, 5)); + + items.add(new WitchShopItem(Floors.FLOOR_9, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_WALL_LAMP, ShopMoney.BLUE_CANDY, 5)); + items.add(new WitchShopItem(Floors.FLOOR_9, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_TOILE_2, ShopMoney.BLUE_CANDY, 5)); + + items.add(new WitchShopItem(Floors.FLOOR_10, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_WITCH_POT, ShopMoney.BLUE_CANDY, 10)); + items.add(new WitchShopItem(Floors.FLOOR_10, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_PUMPKIN_HAT, ShopMoney.BLUE_CANDY, 10)); + + items.add(new WitchShopItem(Floors.FLOOR_11, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_SCARECROW, 10)); + + items.add(new WitchShopItem(Floors.FLOOR_12, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_TOMB_STONE_1, ShopMoney.RED_CANDY, 2)); + + items.add(new WitchShopItem(Floors.FLOOR_13, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_SKULL_SUN_FLOWER, ShopMoney.RED_CANDY, 2)); + + items.add(new WitchShopItem(Floors.FLOOR_14, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_TOMB_STONE_2, ShopMoney.RED_CANDY, 2)); + items.add(new WitchShopItem(Floors.FLOOR_14, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_COFFIN_CLOSE, ShopMoney.RED_CANDY, 2)); + + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_TRICK_OR_TREAT_BOWL, ShopMoney.RED_CANDY, 3)); + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_BROOM, ShopMoney.RED_CANDY, 3)); + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_CELLING_LAMP, ShopMoney.RED_CANDY, 3)); + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_MR_THING, ShopMoney.RED_CANDY, 4)); + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_PUMPKIN_4, ShopMoney.RED_CANDY, 4)); + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_DECORATION_V1_SMILE_FLAG, ShopMoney.RED_CANDY, 4)); + items.add(new WitchShopItem(Floors.FLOOR_15, OMCRegistry.CUSTOM_ITEMS.HALLOWEEN_PACK_TOILE_1, ShopMoney.RED_CANDY, 4)); + + return items; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmBuyMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmBuyMenu.java new file mode 100644 index 000000000..5cac85a38 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmBuyMenu.java @@ -0,0 +1,216 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; + +import dev.lone.itemsadder.api.CustomStack; +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.input.dialog.DialogInput; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.adminshop.AdminShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopItem; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.registry.items.CustomItem; +import fr.openmc.core.utils.bukkit.ItemUtils; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public class ConfirmBuyMenu extends Menu { + + //TODO template ConfirmItemMenu + + private final WitchShopItem shopItem; + private int quantity; + private final int maxQuantity; + + public ConfirmBuyMenu(Player owner, WitchShopItem shopItem) { + super(owner); + this.shopItem = shopItem; + this.quantity = 1; + this.maxQuantity = getMaxBuyQuantity(owner, shopItem); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.adminshop.menu.confirm.name"); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_purchase_confirm_menu:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + + int pricePerUnit = shopItem.getPrice(); + int totalPrice = pricePerUnit * quantity; + + int scorePerUnit = shopItem.getShopMoney().getScores(); + int totalScore = scorePerUnit * quantity; + + int quantityToStack = Math.max(0, quantity / 64); + + //TODO il bug aaaaaaaaaaaaaaa + List lore = TranslationManager.translationLore("feature.events.halloween.festival.shop.confirm_lore", + Component.text(String.valueOf(quantity), NamedTextColor.WHITE), + Component.text(String.valueOf(quantityToStack), NamedTextColor.WHITE), + quantityToStack > 1 ? Component.text("s", NamedTextColor.WHITE) : Component.empty(), + Component.text(AdminShopManager.priceFormat.format(pricePerUnit), NamedTextColor.GREEN), + shopItem.getShopMoney().getItem().getSprite(), + Component.text(AdminShopManager.priceFormat.format(scorePerUnit), NamedTextColor.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon()), + Component.text(AdminShopManager.priceFormat.format(totalPrice), NamedTextColor.GREEN), + shopItem.getShopMoney().getItem().getSprite(), + Component.text(AdminShopManager.priceFormat.format(totalScore), NamedTextColor.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon()) + ); + + content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); + + content.put(10, createQuantityButton("-64", OMCRegistry.CUSTOM_ITEMS.BTN_64, event -> { + if (quantity > 64) quantity -= 64; + else quantity = 1; + this.open(); + })); + + content.put(11, createQuantityButton("-10", OMCRegistry.CUSTOM_ITEMS.MINUS_BTN, event -> { + if (quantity > 10) quantity -= 10; + else quantity = 1; + this.open(); + })); + + content.put(12, createQuantityButton("-1", OMCRegistry.CUSTOM_ITEMS.BTN_1, event -> { + if (quantity > 1) quantity--; + else quantity = 1; + this.open(); + })); + + content.put(13, new ItemMenuBuilder(this, shopItem.getItem(), meta -> { + meta.displayName(shopItem.getName()); + meta.lore(lore); + }).setOnClick(event -> { + if (event.getClick() == ClickType.MIDDLE) { + DialogInput.sendFloat( + getOwner(), + TranslationManager.translation("feature.adminshop.menu.confirm.input"), + 1, + maxQuantity, + quantity, + input -> { + if (input != null) { + int inputQuantity = (int) input.doubleValue(); + if (inputQuantity > 0) { + quantity = Math.min(inputQuantity, maxQuantity); + this.open(); + } + } + } + ); + } + })); + + content.put(14, createQuantityButton("+1", OMCRegistry.CUSTOM_ITEMS.BTN_1, event -> increaseQuantity(1))); + + content.put(15, createQuantityButton("+10", OMCRegistry.CUSTOM_ITEMS.BTN_10, event -> increaseQuantity(10))); + + content.put(16, createQuantityButton("+64", OMCRegistry.CUSTOM_ITEMS.BTN_64, event -> increaseQuantity(64))); + + content.put(17, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ACCEPT_BTN, meta -> { + meta.displayName(TranslationManager.translation("messages.global.accept")); + }).setOnClick(event -> { + getOwner().closeInventory(); + WitchShopManager.buyItem(getOwner(), shopItem, quantity); + })); + + return content; + } + + /** + * Creates a quantity button with the specified text and item stack. + * + * @param text The text to display on the button. + * @param itemStack The item stack to use for the button. + * @param action The action to perform when the button is clicked. + * @return The created item stack. + */ + private ItemMenuBuilder createQuantityButton(String text, ItemStack itemStack, Consumer action) { + boolean plus = text.contains("+"); + return new ItemMenuBuilder(this, itemStack, meta -> + meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", + plus ? + TranslationManager.translation("feature.adminshop.menu.confirm.add") : + TranslationManager.translation("feature.adminshop.menu.confirm.remove"), + Component.text(text.replace("+", "").replace("-", ""))) + .color(plus ? NamedTextColor.GREEN : NamedTextColor.RED) + .decoration(TextDecoration.ITALIC, false))) + .setItemId("quantity_" + text.replace("+", "plus").replace("-", "minus")) + .setOnClick(action); + } + + /** + * Creates a quantity button with the specified text and item stack. + * + * @param text The text to display on the button. + * @param customItem The CustomItem to use for the button. + * @param action The action to perform when the button is clicked. + * @return The created item stack. + */ + private ItemMenuBuilder createQuantityButton(String text, CustomItem customItem, Consumer action) { + return this.createQuantityButton(text, customItem.getBest(), action); + } + + /** + * Increases the quantity by the specified amount, ensuring it does not exceed the maximum allowed quantity. + * + * @param amount The amount to increase the quantity by. + */ + private void increaseQuantity(int amount) { + quantity = Math.min(quantity + amount, maxQuantity); + this.open(); + } + + private int getMaxBuyQuantity(Player player, WitchShopItem shopItem) { + int freePlaces = ItemUtils.getFreePlacesForItem(player, shopItem.getItem().getBest()); + + double buyPrice = shopItem.getPrice(); + if (buyPrice <= 0) return freePlaces; + + double balance = ItemUtils.countItems(player, shopItem.getShopMoney().getItem().getBest()); + int affordable = (int) Math.floor(balance / buyPrice); + + return Math.min(freePlaces, affordable); + } + + @Override + public void onClose(InventoryCloseEvent event) { + //empty + } + + @Override + public List getTakableSlot() { + return List.of(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchChoiceMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchChoiceMenu.java new file mode 100644 index 000000000..b31002bcd --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchChoiceMenu.java @@ -0,0 +1,71 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons.DepositButton; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons.TerrorHouseButton; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WitchChoiceMenu extends Menu { + + private static final int[] WITCH_HOUSE_SLOT = {11}; + private static final int[] DEPOSIT_SLOTS = {15}; + private static final Sound WITCH_MENU_CLOSE = Sound.ENTITY_WITCH_AMBIENT; + + public WitchChoiceMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.menu.choice.name"); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_choice_menu:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public @NotNull Map getContent() { + Map inventory = new HashMap<>(); + + TerrorHouseButton.init(this, inventory, WITCH_HOUSE_SLOT); + + DepositButton.init(this, inventory, DEPOSIT_SLOTS); + + return inventory; + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + @Override + public void onClose(InventoryCloseEvent event) { + Player player = getOwner(); + player.playSound(player, WITCH_MENU_CLOSE, 1f, 1f); + } + + @Override + public void onInventoryClick(InventoryClickEvent click) { + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopMainMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopMainMenu.java new file mode 100644 index 000000000..9f11a629d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopMainMenu.java @@ -0,0 +1,71 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons.ChoiceButton; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons.WitchStoreButton; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WitchShopMainMenu extends Menu { + + private static final int[] WITCH_HOUSE_SLOTS = {9, 10, 11, 12, 13, 18, 19, 20, 21, 22, 27, 28, 29, 30, 31, 36, 37, 38, 39, 40, 45, 46, 47, 48, 49}; + private static final int[] WITCH_SHOP_SLOTS = {23, 24, 25, 26, 32, 33, 34, 35, 41, 42, 43, 44, 50, 51, 52, 53}; + private static final Sound WITCH_MENU_CLOSE = Sound.ENTITY_WITCH_AMBIENT; + + public WitchShopMainMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.menu.main.name"); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_event_main_menu:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public @NotNull Map getContent() { + Map inventory = new HashMap<>(); + + ChoiceButton.init(this, inventory, WITCH_HOUSE_SLOTS); + + WitchStoreButton.init(this, inventory, WITCH_SHOP_SLOTS); + + return inventory; + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + @Override + public void onClose(InventoryCloseEvent event) { + Player player = getOwner(); + player.playSound(player, WITCH_MENU_CLOSE, 1f, 1f); + } + + @Override + public void onInventoryClick(InventoryClickEvent click) { + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopStoreMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopStoreMenu.java new file mode 100644 index 000000000..b23e7fc1d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopStoreMenu.java @@ -0,0 +1,167 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.menulib.MenuLib; +import fr.openmc.api.menulib.PaginatedMenu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.api.menulib.utils.StaticSlots; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.commands.utils.Restart; +import fr.openmc.core.features.city.menu.CityChestMenu; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopItem; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.utils.text.messages.TranslationManager; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.minecraft.world.level.levelgen.Column; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +public class WitchShopStoreMenu extends PaginatedMenu { + + @Getter + private final int page; + + public WitchShopStoreMenu(Player owner, int page) { + super(owner); + this.page = page; + + if (this.page < 1) { + throw new IllegalArgumentException("Page must be greater than 0"); + } + + if (this.page > WitchShopManager.maxPage) { + throw new IllegalArgumentException("Page must be less than or equal to " + WitchShopManager.maxPage); + } + } + + @Override + public @Nullable Material getBorderMaterial() { + return Material.AIR; + } + + @Override + public @NotNull List getStaticSlots() { + return StaticSlots.combine(StaticSlots.getBottomSlots(getInventorySize()), + StaticSlots.combine(StaticSlots.getLeftSlots(getInventorySize()), + StaticSlots.combine(StaticSlots.getRightSlots(getInventorySize()), + List.of(36, 37, 38, 39, 40, 41, 42, 43, 44)) // LINE 5 in the LARGEST Inventory + ) + ); + } + + @Override + public List getItems() { + + List items = new ArrayList<>(); + + Set contents = WitchShopManager.getStoreContent(this.page); + + for (WitchShopItem item : contents) + items.add(new ItemMenuBuilder(this, item.getItem(), itemMeta -> { + itemMeta.displayName(item.getName()); + itemMeta.lore(WitchShopManager.extractLoreForItem(item)); + }).setOnClick(event -> { + if (TerrorHouseManager.enabledFloors.contains(item.getAdvancements())) + new ConfirmBuyMenu(getOwner(), item).open(); + })); + + return items; + } + + @Override + public Map getButtons() { + if (Restart.isRestarting) return null; + + Map map = new HashMap<>(); + + if (hasPreviousPage()) { + map.put(45, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_BACK_ORANGE, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.previous_page")); + }).setOnClick(inventoryClickEvent -> { + if (hasPreviousPage()) + new WitchShopStoreMenu(getOwner(), this.getPage() - 1).open(); + })); + } + + map.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.close")); + }).setOnClick(event -> { + new WitchShopMainMenu(getOwner()).open(); + })); + + if (hasNextPage()) { + map.put(53, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_NEXT_ORANGE, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); + }).setOnClick(inventoryClickEvent -> { + if (hasNextPage()) + new WitchShopStoreMenu(getOwner(), this.getPage() + 1).open(); + })); + } + + return map; + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation( + "feature.events.halloween.festival.menu.store.name", + Component.text(this.page) + ); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_store_menu:"); + } + + @Override + public void onInventoryClick(InventoryClickEvent inventoryClickEvent) { + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public int getSizeOfItems() { + return getItems().size(); + } + + @Override + public void onClose(InventoryCloseEvent event) { + if (Restart.isRestarting) return; + HumanEntity humanEntity = event.getPlayer(); + if (!(humanEntity instanceof Player player)) return; + // fixes #1007 + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), ()-> MenuLib.updateMenu(player), 5L); + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + public boolean hasNextPage() { + return this.page < WitchShopManager.maxPage; + } + + public boolean hasPreviousPage() { + return this.page > 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/ChoiceButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/ChoiceButton.java new file mode 100644 index 000000000..49c8e9b41 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/ChoiceButton.java @@ -0,0 +1,30 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons; + +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.api.menulib.utils.MenuUtils; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchChoiceMenu; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopStoreMenu; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; + +import java.util.Map; + +public class ChoiceButton { + public static void init(Menu menu, Map contents, int[] slots) { + MenuUtils.createButtonItem( + contents, + slots, + new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.house.name")); + itemMeta.lore(TranslationManager.translationLore( + "feature.events.halloween.festival.button.house.lore" + )); + itemMeta.setItemModel(NamespacedKey.minecraft("air")); + }).setOnClick(inventoryClickEvent -> new WitchChoiceMenu(menu.getOwner()).open()) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/DepositButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/DepositButton.java new file mode 100644 index 000000000..f4954178d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/DepositButton.java @@ -0,0 +1,30 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons; + +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.api.menulib.utils.MenuUtils; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchChoiceMenu; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.menu.AdvancementMenu; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; + +import java.util.Map; + +public class DepositButton { + public static void init(Menu menu, Map contents, int[] slots) { + MenuUtils.createButtonItem( + contents, + slots, + new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.deposit.name")); + itemMeta.lore(TranslationManager.translationLore( + "feature.events.halloween.festival.button.deposit.lore" + )); + itemMeta.setItemModel(NamespacedKey.minecraft("air")); + }).setOnClick(inventoryClickEvent -> new AdvancementMenu(menu.getOwner()).open()) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerrorHouseButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerrorHouseButton.java new file mode 100644 index 000000000..1cd05918c --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerrorHouseButton.java @@ -0,0 +1,36 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons; + +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.api.menulib.utils.MenuUtils; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; + +import java.util.Map; + +public class TerrorHouseButton { + public static void init(Menu menu, Map contents, int[] slots) { + MenuUtils.createButtonItem( + contents, + slots, + new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.terror_house.name")); + itemMeta.lore(TranslationManager.translationLore( + "feature.events.halloween.festival.button.terror_house.lore" + )); + itemMeta.setItemModel(NamespacedKey.minecraft("air")); + }).setOnClick(inventoryClickEvent -> { + menu.getOwner().teleport( + new Location( + DimensionGenerator.HALLOWEEN_WORLD, + -58, -60, -67 + ) + ); + menu.getOwner().closeInventory(); + }) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchStoreButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchStoreButton.java new file mode 100644 index 000000000..e4c932d86 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchStoreButton.java @@ -0,0 +1,32 @@ +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons; + +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.api.menulib.utils.MenuUtils; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopStoreMenu; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class WitchStoreButton { + public static void init(Menu menu, Map contents, int[] slots) { + Player player = menu.getOwner(); + + MenuUtils.createButtonItem( + contents, + slots, + new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.store.name")); + itemMeta.lore(TranslationManager.translationLore( + "feature.events.halloween.festival.button.store.lore" + )); + itemMeta.setItemModel(NamespacedKey.minecraft("air")); + }).setOnClick(inventoryClickEvent -> { + new WitchShopStoreMenu(player, 1).open(); + }) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/DimensionGenerator.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/DimensionGenerator.java new file mode 100644 index 000000000..69d8f8469 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/DimensionGenerator.java @@ -0,0 +1,58 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse; + +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import org.bukkit.Bukkit; +import org.bukkit.GameRules; +import org.bukkit.World; +import org.bukkit.entity.SpawnCategory; + +public class DimensionGenerator { + + public static final String DIMENSION_NAME = "world_omc_halloween_witch_house"; + public static World HALLOWEEN_WORLD; + + public static void init() { + HALLOWEEN_WORLD = Bukkit.getWorld(DIMENSION_NAME); + + setupDimension(); + } + + private static void setupDimension() { + if (!HALLOWEEN_WORLD.getName().equals(DIMENSION_NAME)) return; + + // ** SPAWNING RULES ** + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.MONSTER, 55); + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.AMBIENT, 10); + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.ANIMAL, 0); + + HALLOWEEN_WORLD.setTicksPerSpawns(SpawnCategory.MONSTER, 30); + HALLOWEEN_WORLD.setTicksPerSpawns(SpawnCategory.AMBIENT, 15); + HALLOWEEN_WORLD.setTicksPerSpawns(SpawnCategory.ANIMAL, 30); + + // ** SET GAMERULE FOR THE WORLD ** + HALLOWEEN_WORLD.setGameRule(GameRules.ADVANCE_TIME, false); + HALLOWEEN_WORLD.setGameRule(GameRules.SHOW_ADVANCEMENT_MESSAGES, false); + HALLOWEEN_WORLD.setGameRule(GameRules.ADVANCE_WEATHER, false); + HALLOWEEN_WORLD.setGameRule(GameRules.RAIDS, true); + HALLOWEEN_WORLD.setGameRule(GameRules.SPAWN_PATROLS, false); + HALLOWEEN_WORLD.setGameRule(GameRules.SPAWN_WANDERING_TRADERS, false); + HALLOWEEN_WORLD.setGameRule(GameRules.NATURAL_HEALTH_REGENERATION, false); + HALLOWEEN_WORLD.setGameRule(GameRules.LOCATOR_BAR, false); + HALLOWEEN_WORLD.setGameRule(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS, false); + HALLOWEEN_WORLD.setGameRule(GameRules.SPAWN_MONSTERS, false); + HALLOWEEN_WORLD.setGameRule(GameRules.SPAWN_MOBS, false); + HALLOWEEN_WORLD.setGameRule(GameRules.RANDOM_TICK_SPEED, 0); + HALLOWEEN_WORLD.setGameRule(GameRules.PVP, false); + + // ** SET WORLD BORDER AND TIME ** + HALLOWEEN_WORLD.getWorldBorder().setSize(500); + HALLOWEEN_WORLD.setTime(14000); + HALLOWEEN_WORLD.setThundering(true); + HALLOWEEN_WORLD.setStorm(true); + + HalloweenFestivalManager.placeTerrorHouse(); + + OMCLogger.infoFormatted("Dimension de la Maison de la Sorcière setup (gamerules, worldborder, time)"); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/TerrorHouseManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/TerrorHouseManager.java new file mode 100644 index 000000000..b509ae20c --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/TerrorHouseManager.java @@ -0,0 +1,222 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse; + +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.PointRewards; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floor; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floors; +import fr.openmc.core.registry.ambient.CustomAmbient; +import fr.openmc.core.registry.regions.CustomRegion; +import fr.openmc.core.utils.EnumUtils; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +import java.util.ArrayList; +import java.util.List; + +public class TerrorHouseManager { + + public static Floors currentFloorToReach; + public static PointRewards currentRewardToReach; + + public static List enabledFloors; + public static List useRegions = new ArrayList<>(); + + public static int globalAdvancement; + public static int floorAdvancement; + public static boolean finalFloorReach; + + public static final Floors FINAL_FLOOR = Floors.FLOOR_15; + + public static int entityCount = 0; + public static final int MAX_ENTITY = 225; // 15 entities * 15 floors + + @Getter + public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.TERROR_HOUSE; + + public static void init(int gAdvancement, int fAdvancement) { + // Advancement + globalAdvancement = gAdvancement; + floorAdvancement = fAdvancement; + + // Current things that are reachable + currentFloorToReach = getFloorFromAdvancement(globalAdvancement); + currentRewardToReach = getRewardFromAdvancement(globalAdvancement); + + // Floors + finalFloorReach = currentFloorToReach.equals(FINAL_FLOOR); + enabledFloors = EnumUtils.getValuesBefore(currentFloorToReach, finalFloorReach); + + for (Floors floors : Floors.values()) { + Floor floor = floors.getFloor(); + if (floor == null) + continue; + + if (enabledFloors.contains(floors)) + floor.enableSpawn(); + + CustomRegion region = floor.getRegion(); + if (region != null) + useRegions.add(region); + } + } + + public static void updateAdvancement(int increase) { + globalAdvancement += increase; + floorAdvancement += increase; + + checkForPointRewards(); + + if (finalFloorReach) + return; + + if (currentFloorToReach.getRequire() > floorAdvancement) + return; + + updateFloor(); + } + + private static void checkForPointRewards() { + if (currentRewardToReach.equals(PointRewards.NULL)) + return; + + if (globalAdvancement >= currentRewardToReach.getGlobalPointsRequire()) { + currentRewardToReach.getReward().giveReward(); + + currentRewardToReach = currentRewardToReach.getNextReward(); + } + } + + private static void updateFloor() { + if (finalFloorReach) + return; + + floorAdvancement -= currentFloorToReach.getRequire(); + + enabledFloors.add(currentFloorToReach); + + Floor floor = currentFloorToReach.getFloor(); + + if (floor == null) + return; + + floor.enableSpawn(); + + if (currentFloorToReach.equals(Floors.FLOOR_15)) { + + finalFloorReach = true; + + HalloweenFestivalManager.broadcast( + TranslationManager.translation( + "feature.events.halloween.festival.last_floor_unlock", + Component.text(currentRewardToReach.getGlobalPointsRequire()), + Component.text(globalAdvancement), + Component.text(WitchShopManager.getHalloweenPointIcon()) + ) + ); + + return; + } + + currentFloorToReach = EnumUtils.getValueAfter(currentFloorToReach); + + if (currentFloorToReach == null) + return; + + if (floorAdvancement >= currentFloorToReach.getRequire()) + updateFloor(); + + else + HalloweenFestivalManager.broadcast( + TranslationManager.translation( + "feature.events.halloween.festival.new_floor_unlock", + Component.text(currentFloorToReach.getRequire()), + Component.text(floorAdvancement), + Component.text(WitchShopManager.getHalloweenPointIcon()) + ) + ); + + } + + public static Floors getFloorFromAdvancement(int advancement) { + Floors currentFloors = Floors.FLOOR_2; + + for (Floors floors : Floors.values()) { + if (floors.getRequire() < advancement) + currentFloors = floors; + else break; + } + + return currentFloors; + } + + public static PointRewards getRewardFromAdvancement(int points) { + + for (PointRewards rewards : PointRewards.values()) + if (rewards.getGlobalPointsRequire() >= points) + return rewards; + + return PointRewards.NULL; + } + + public void broadcast(Component text) { + for (Player player : OMCPlugin.getInstance().getServer().getOnlinePlayers()) { + MessagesManager.sendMessage( + player, + TranslationManager.translation("", text), + Prefix.HALLOWEEN, + MessageType.INFO, + true + ); + } + } + + public static void repulsePlayer(CustomRegion region, Entity entity, double force) { + BlockVector3 coords = region.getCenter(); + Location center = new Location(region.getWorld(), coords.x(), coords.y(), coords.z()); + repulsePlayer(center, entity, force); + } + + public static void repulsePlayer(Location source, Entity entity, double force) { + Location playerLocation = entity.getLocation(); + + if (source.getWorld() == null + || !source.getWorld().equals(playerLocation.getWorld())) { + return; + } + + Vector knockback = playerLocation.toVector() + .subtract(source.toVector()); + + knockback.setY(0); + + if (knockback.lengthSquared() < 1.0E-6) { + knockback = playerLocation.getDirection().setY(0); + } + + if (knockback.lengthSquared() < 1.0E-6) { + knockback = new Vector(1, 0, 0); + } + + knockback.normalize().multiply(force); + + knockback.setY(-0.15); + + entity.setVelocity(knockback); + } + + public static boolean limitPassed() { + return entityCount >= MAX_ENTITY; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/PointRewards.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/PointRewards.java new file mode 100644 index 000000000..2b3232a4b --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/PointRewards.java @@ -0,0 +1,24 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement; + +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward.EmptyReward; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward.PointReward; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward.plush.HalloweenRoot2026; +import lombok.Getter; + +@Getter +public enum PointRewards { + + NULL(new EmptyReward(),-1, null), + HALLOWEEN_ROOT_PLUSH(new HalloweenRoot2026(), 1000000, PointRewards.NULL), + ; + + private final PointReward reward; + private final int globalPointsRequire; + private final PointRewards nextReward; + + PointRewards(PointReward reward, int globalPointsRequire, PointRewards nextReward) { + this.reward = reward; + this.globalPointsRequire = globalPointsRequire; + this.nextReward = nextReward; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floor.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floor.java new file mode 100644 index 000000000..32ef862ec --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floor.java @@ -0,0 +1,117 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor; + +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.mobs.CustomMobEntry; +import fr.openmc.core.registry.regions.preset.SquareRegion; +import fr.openmc.core.utils.RandomUtils; +import fr.openmc.core.utils.world.LocationUtils; +import lombok.Getter; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Getter +public class Floor { + + private final SquareRegion region; + private final List entities; + private final List spawnLocations; + private final int entityToSpawn; + + private final int RADIUS = 3; + + private final List clearLag = new ArrayList<>(); + private BukkitTask spawnTask; + private int timeTask = 0; + + public Floor(SquareRegion region, List entities, int entityToSpawn, List spawnLocations) { + this.region = region; + this.entities = entities; + this.entityToSpawn = entityToSpawn; + this.spawnLocations = spawnLocations; + } + + public void enableSpawn() { + + spawnTask = Bukkit.getScheduler().runTaskTimer(OMCPlugin.getInstance(), () -> { + + timeTask += 30; + + if (timeTask>=300) // 5 minutes + clearLag(); + + if (entities.isEmpty()) { + OMCLogger.warn("No mob register for the spawn mob, spawn disable for this floor"); + clearLag(); + spawnTask.cancel(); + return; + } + + if (spawnLocations.isEmpty()) { + OMCLogger.warn("No spawn location register for the spawn mob, spawn disable for this floor"); + clearLag(); + spawnTask.cancel(); + return; + } + + CustomMobEntry mobToSpawn = RandomUtils.getRandomObjectFromList(entities); + + if (mobToSpawn == null) + return; + + if (!hasPlayer()) + return; + + if (TerrorHouseManager.limitPassed()) + return; + + int toSpawn = RandomUtils.randomBetween(1, entityToSpawn); + + for (int i = 0; i < toSpawn; i++) + clearLag.add(mobToSpawn.spawn(getRandomLocation())); + + TerrorHouseManager.entityCount += toSpawn; + }, 0L, 15 * 20L); + } + + private void clearLag() { + for (Entity entity : clearLag) + entity.remove(); + clearLag.clear(); + } + + public Location getRandomLocation() { + + BlockVector3 pos = RandomUtils.getRandomObjectFromList(spawnLocations); + + Location newloc = LocationUtils.randomLocation( + LocationUtils.fromVector( + DimensionGenerator.HALLOWEEN_WORLD, + pos + ), + RADIUS + ); + + newloc.setY(pos.y()); + + return newloc; + } + + public boolean hasPlayer() { + return DimensionGenerator.HALLOWEEN_WORLD.getPlayers() + .stream() + .filter(p -> region.contains(p.getLocation())) + .findAny().orElse(null) != null; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floors.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floors.java new file mode 100644 index 000000000..111d8b6cb --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floors.java @@ -0,0 +1,159 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor; + +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.OMCRegistry; +import lombok.Getter; + +import java.util.List; + +@Getter +public enum Floors { + + FLOOR_1(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_1, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV1, + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV1, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV1 + ), 3, List.of( + BlockVector3.at(-32, -51, -74), + BlockVector3.at(-48, -51, -67), + BlockVector3.at(-60, -51, -68), + BlockVector3.at(-58, -51, -49), + BlockVector3.at(-35, -51, -52) + )), 0), + + FLOOR_2(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_2, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV1, + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV1, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV1 + ), 3, List.of( + BlockVector3.at(-59, -43, -76), + BlockVector3.at(-56, -43, -57) + )), 1000), + + FLOOR_3(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_3, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV1, + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV1, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV1 + ), 3, List.of( + BlockVector3.at(-58, -35, -61), + BlockVector3.at(-64, -35, -47) + )), 5000), + + FLOOR_4(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_4, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV2 + ), 5, List.of( + BlockVector3.at(-76, -34, -65), + BlockVector3.at(-48, -34, -51) + )), 10000), + + FLOOR_5(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_5, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV2 + ), 5, List.of( + BlockVector3.at(-49, -27, -58), + BlockVector3.at(-37, -27, -71), + BlockVector3.at(-62, -27, -71) + )), 15000), + + FLOOR_6(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_6, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV2 + ), 5, List.of( + BlockVector3.at(-59, -19, -72), + BlockVector3.at(-64, -19, -59), + BlockVector3.at(-45, -19, -63) + )), 20000), + + FLOOR_7(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_7, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV2 + ), 5, List.of( + BlockVector3.at(-54, -11, -51), + BlockVector3.at(-63, -11, -69), + BlockVector3.at(-46, -11, -61) + )), 25000), + + FLOOR_8(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_8, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV1 + ), 5, List.of( + BlockVector3.at(-48, -3, -56), + BlockVector3.at(-60, -3, -62) + )), 30000), + + FLOOR_9(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_9, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_BLAZE_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV2 + ), 5, List.of( + BlockVector3.at(-70, 5, -73), + BlockVector3.at(-57, 5, -63), + BlockVector3.at(-72, 5, -47), + BlockVector3.at(-44, 5, -68), + BlockVector3.at(-50, 5, -48) + )), 35000), + + FLOOR_10(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_10, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_BLAZE_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_WITHER_SKELETON_LV2 + ), 7, List.of( + BlockVector3.at(-68, 14, -73), + BlockVector3.at(-46, 14, -67), + BlockVector3.at(-44, 14, -81), + BlockVector3.at(-52, 14, -49), + BlockVector3.at(-67, 14, -53) + )), 40000), + + FLOOR_11(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_11, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_SKELETON_LV2 + ), 7, List.of( + BlockVector3.at(-46, 21, -49), + BlockVector3.at(-60, 21, -73), + BlockVector3.at(-41, 21, -73) + )), 45000), + + FLOOR_12(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_12, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_MOSSY_SKELETON_LV2 + ), 7, List.of( + BlockVector3.at(-57, 29, -62), + BlockVector3.at(-70, 29, -56), + BlockVector3.at(-74, 29, -80) + )), 50000), + + FLOOR_13(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_13, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_SPIDER_LV2, + OMCRegistry.CUSTOM_MOBS.HOUSE_ZOMBIE_LV3 + ), 7, List.of( + BlockVector3.at(-44, 37, -81), + BlockVector3.at(-64, 37, -53), + BlockVector3.at(-46, 37, -49), + BlockVector3.at(-65, 37, -77) + )), 59000), + + FLOOR_14(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_14, List.of( + OMCRegistry.CUSTOM_MOBS.HOUSE_WITCH_LV3, + OMCRegistry.CUSTOM_MOBS.HOUSE_BRUTE_LV3 + ), 7, List.of( + BlockVector3.at(-63, 45, -76), + BlockVector3.at(-68, 45, -63), + BlockVector3.at(-51, 45, -70) + )), 65000), + + FLOOR_15(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_15, List.of(), 3, List.of()), 100000); + + + private final Floor floor; + private final int require; + + Floors(Floor floor, int require) { + this.floor = floor; // 15 au totale + this.require = require; // 500k global au totale + } + + public String getSimplifyFloor() { + return "Floor " + (ordinal() + 1); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/AdvancementMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/AdvancementMenu.java new file mode 100644 index 000000000..0d89c0c15 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/AdvancementMenu.java @@ -0,0 +1,105 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.menu; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.economy.EconomyManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchChoiceMenu; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.PointRewards; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AdvancementMenu extends Menu { + + public AdvancementMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.menu.advancement"); + } + + @Override + public String getTexture() { + + int textureIndex = 4; + + PointRewards reward = TerrorHouseManager.currentRewardToReach; + int advancement = TerrorHouseManager.globalAdvancement; + + if (!reward.equals(PointRewards.NULL) && advancement < reward.getGlobalPointsRequire()) { + textureIndex = (int) Math.floor( + (double) TerrorHouseManager.globalAdvancement / reward.getGlobalPointsRequire() * 5 + ) - 1; + textureIndex = Math.clamp(textureIndex, 0, 4); + } + + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_candy_jar_" + textureIndex + ":"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) { + + } + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + + content.put(22, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.CANDY_RED, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.menu.advancement.item_name")); + itemMeta.lore(List.of( + TranslationManager.translation( + "feature.events.halloween.festival.menu.advancement.item_lore", + Component.text(EconomyManager.getFormattedSimplifiedNumber(TerrorHouseManager.globalAdvancement)), + Component.text(WitchShopManager.getHalloweenPointIcon()) + ) + )); + }).setOnClick(click -> { + if (click.isRightClick()) { + new RewardViewMenu(getOwner()).open(); + } + + if (click.isLeftClick()) { + new CandyChoiceMenu(getOwner()).open(); + } + })); + + content.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.close")); + }).setOnClick(event -> { + new WitchChoiceMenu(getOwner()).open(); + })); + + return content; + } + + @Override + public void onClose(InventoryCloseEvent event) { + + } + + @Override + public List getTakableSlot() { + return List.of(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/CandyChoiceMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/CandyChoiceMenu.java new file mode 100644 index 000000000..7ca887e5e --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/CandyChoiceMenu.java @@ -0,0 +1,112 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.menu; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.shop.ShopMoney; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CandyChoiceMenu extends Menu { + + public CandyChoiceMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.menu.candy_choice"); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_deposit_menu:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) { + + } + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + + content.put(9, new ItemMenuBuilder(this, ShopMoney.MONSTER_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("itemsadder.omc_halloween.candy_brown.name")); + itemMeta.lore(getCandyPoints(ShopMoney.MONSTER_CANDY)); + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.MONSTER_CANDY).open(); + })); + + content.put(20, new ItemMenuBuilder(this, ShopMoney.GREEN_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("itemsadder.omc_halloween.candy_green.name")); + itemMeta.lore(getCandyPoints(ShopMoney.GREEN_CANDY)); + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.GREEN_CANDY).open(); + })); + + content.put(13, new ItemMenuBuilder(this, ShopMoney.BLUE_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("itemsadder.omc_halloween.candy_blue.name")); + itemMeta.lore(getCandyPoints(ShopMoney.BLUE_CANDY)); + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.BLUE_CANDY).open(); + })); + + content.put(24, new ItemMenuBuilder(this, ShopMoney.RED_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("itemsadder.omc_halloween.candy_red.name")); + itemMeta.lore(getCandyPoints(ShopMoney.RED_CANDY)); + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.RED_CANDY).open(); + })); + + content.put(17, new ItemMenuBuilder(this, ShopMoney.YELLOW_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("itemsadder.omc_halloween.candy_yellow.name")); + itemMeta.lore(getCandyPoints(ShopMoney.YELLOW_CANDY)); + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.YELLOW_CANDY).open(); + })); + + content.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.close")); + }).setOnClick(event -> { + new AdvancementMenu(getOwner()).open(); + })); + + return content; + } + + @Override + public void onClose(InventoryCloseEvent event) { + + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + private List getCandyPoints(ShopMoney money) { + return List.of(TranslationManager.translation( + "feature.events.halloween.festival.menu.candy_choice.candy_point", + Component.text(money.getScores()), + Component.text(WitchShopManager.getHalloweenPointIcon()) + )); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/ConfirmSellMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/ConfirmSellMenu.java new file mode 100644 index 000000000..ac2e2e4f7 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/ConfirmSellMenu.java @@ -0,0 +1,211 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.menu; + +import dev.lone.itemsadder.api.CustomStack; +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.input.dialog.DialogInput; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.adminshop.AdminShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.ShopMoney; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.registry.items.CustomItem; +import fr.openmc.core.utils.bukkit.ItemUtils; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public class ConfirmSellMenu extends Menu { + + // Copy of the ConfirmMenu from the AdminShop // + //TODO template ConfirmItemMenu + + private final ShopMoney shopItem; + private int quantity; + private final int maxQuantity; + + public ConfirmSellMenu(Player owner, ShopMoney shopItem) { + super(owner); + this.shopItem = shopItem; + this.quantity = 1; + this.maxQuantity = ItemUtils.countItems(getOwner(), shopItem.getItem().getBest()); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.adminshop.menu.confirm.name"); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_purchase_confirm_menu:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + double scorePerUnit = shopItem.getScores(); + double totalScore = scorePerUnit * quantity; + int quantityToStack = Math.max(0, quantity / 64); + + Component shiftRightSellAll = TranslationManager.translation("feature.adminshop.menu.confirm.sell_all"); + + List lore = TranslationManager.translationLore("feature.adminshop.menu.confirm.lore", + Component.text(String.valueOf(quantity), NamedTextColor.WHITE), + Component.text(String.valueOf(quantityToStack), NamedTextColor.WHITE), + quantityToStack > 1 ? Component.text("s", NamedTextColor.WHITE) : Component.empty(), + Component.text(AdminShopManager.priceFormat.format(scorePerUnit), NamedTextColor.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GOLD), + Component.text(AdminShopManager.priceFormat.format(totalScore), NamedTextColor.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GOLD), + shiftRightSellAll + + ); + + content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); + + content.put(10, createQuantityButton("-64", OMCRegistry.CUSTOM_ITEMS.BTN_64, event -> { + if (quantity > 64) quantity -= 64; + else quantity = 1; + this.open(); + })); + + content.put(11, createQuantityButton("-10", OMCRegistry.CUSTOM_ITEMS.MINUS_BTN, event -> { + if (quantity > 10) quantity -= 10; + else quantity = 1; + this.open(); + })); + + content.put(12, createQuantityButton("-1", OMCRegistry.CUSTOM_ITEMS.BTN_1, event -> { + if (quantity > 1) quantity--; + else quantity = 1; + this.open(); + })); + + content.put(13, new ItemMenuBuilder(this, shopItem.getItem(), meta -> { + meta.displayName(shopItem.getName().color(NamedTextColor.WHITE).decoration(TextDecoration.ITALIC, false)); + meta.lore(lore); + }).setOnClick(event -> { + switch (event.getClick()) { + case ClickType.MIDDLE -> DialogInput.sendFloat( + getOwner(), + TranslationManager.translation("feature.adminshop.menu.confirm.input"), + 1, + maxQuantity, + quantity, + input -> { + if (input != null) { + int inputQuantity = (int) input.doubleValue(); + if (inputQuantity > 0) { + quantity = Math.min(inputQuantity, maxQuantity); + this.open(); + } + } + } + ); + case ClickType.SHIFT_RIGHT -> { + int itemCount = ItemUtils.countItems(getOwner(), shopItem.getItem().getBest()); + if (itemCount > 0) { + getOwner().closeInventory(); + WitchShopManager.sellItem( + getOwner(), + shopItem, + itemCount + ); + } + } + } + })); + + content.put(14, createQuantityButton("+1", OMCRegistry.CUSTOM_ITEMS.BTN_1, event -> increaseQuantity(1))); + + content.put(15, createQuantityButton("+10", OMCRegistry.CUSTOM_ITEMS.BTN_10, event -> increaseQuantity(10))); + + content.put(16, createQuantityButton("+64", OMCRegistry.CUSTOM_ITEMS.BTN_64, event -> increaseQuantity(64))); + + content.put(17, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ACCEPT_BTN, meta -> { + meta.displayName(TranslationManager.translation("messages.global.accept")); + }).setOnClick(event -> { + getOwner().closeInventory(); + WitchShopManager.sellItem(getOwner(), shopItem, quantity); + })); + + return content; + } + + /** + * Creates a quantity button with the specified text and item stack. + * + * @param text The text to display on the button. + * @param itemStack The item stack to use for the button. + * @param action The action to perform when the button is clicked. + * @return The created item stack. + */ + private ItemMenuBuilder createQuantityButton(String text, ItemStack itemStack, Consumer action) { + boolean plus = text.contains("+"); + return new ItemMenuBuilder(this, itemStack, meta -> + meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", + plus ? + TranslationManager.translation("feature.adminshop.menu.confirm.add") : + TranslationManager.translation("feature.adminshop.menu.confirm.remove"), + Component.text(text.replace("+", "").replace("-", ""))) + .color(plus ? NamedTextColor.GREEN : NamedTextColor.RED) + .decoration(TextDecoration.ITALIC, false))) + .setItemId("quantity_" + text.replace("+", "plus").replace("-", "minus")) + .setOnClick(action); + } + + /** + * Creates a quantity button with the specified text and item stack. + * + * @param text The text to display on the button. + * @param customItem The CustomItem to use for the button. + * @param action The action to perform when the button is clicked. + * @return The created item stack. + */ + private ItemMenuBuilder createQuantityButton(String text, CustomItem customItem, Consumer action) { + return this.createQuantityButton(text, customItem.getBest(), action); + } + + /** + * Increases the quantity by the specified amount, ensuring it does not exceed the maximum allowed quantity. + * + * @param amount The amount to increase the quantity by. + */ + private void increaseQuantity(int amount) { + int playerItemCount = ItemUtils.countItems(getOwner(), shopItem.getItem().getBest()); + quantity = Math.min(quantity + amount, playerItemCount); + this.open(); + } + + @Override + public void onClose(InventoryCloseEvent event) { + //empty + } + + @Override + public List getTakableSlot() { + return List.of(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardViewMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardViewMenu.java new file mode 100644 index 000000000..d34933886 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardViewMenu.java @@ -0,0 +1,88 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.menu; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.PointRewards; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +public class RewardViewMenu extends Menu { + + public RewardViewMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.menu.reward"); + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_reward_menu:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) { + + } + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + + PointRewards reward = TerrorHouseManager.currentRewardToReach; + + List lore = Stream.concat( + Stream.of(Component.text( + "Goal : " + reward.getGlobalPointsRequire() + + WitchShopManager.getHalloweenPointIcon()) + .color(NamedTextColor.WHITE) + ), + reward.getReward().getRewardLore().stream() + ).toList(); + + content.put(13, new ItemMenuBuilder(this, reward.getReward().getItemMenuPreview(), itemMeta -> { + itemMeta.displayName(reward.getReward().getRewardName()); + itemMeta.lore(lore); + })); + + content.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.close")); + }).setOnClick(event -> { + new AdvancementMenu(getOwner()).open(); + })); + + return content; + } + + @Override + public void onClose(InventoryCloseEvent event) { + + } + + @Override + public List getTakableSlot() { + return List.of(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/EmptyReward.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/EmptyReward.java new file mode 100644 index 000000000..3ed879966 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/EmptyReward.java @@ -0,0 +1,27 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward; + +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class EmptyReward implements PointReward{ + @Override public void giveReward() {} + + @Override + public ItemStack getItemMenuPreview() { + return new ItemStack(Material.BARRIER); + } + + @Override + public Component getRewardName() { + return Component.empty(); + } + + @Override + public List getRewardLore() { + return List.of(Component.empty()); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/PointReward.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/PointReward.java new file mode 100644 index 000000000..a9e4aba9c --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/PointReward.java @@ -0,0 +1,15 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward; + +import net.kyori.adventure.text.Component; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public interface PointReward { + void giveReward(); + + ItemStack getItemMenuPreview(); + + Component getRewardName(); + List getRewardLore(); +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/plush/HalloweenRoot2026.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/plush/HalloweenRoot2026.java new file mode 100644 index 000000000..408c16fbc --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/plush/HalloweenRoot2026.java @@ -0,0 +1,69 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward.plush; + +import fr.openmc.api.omcplayer.OMCPlayer; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward.PointReward; +import fr.openmc.core.features.mailboxes.MailboxManager; +import fr.openmc.core.registry.items.CustomItem; +import fr.openmc.core.utils.cache.CacheOfflinePlayer; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.UUID; + +public class HalloweenRoot2026 implements PointReward { + + CustomItem reward = OMCRegistry.CUSTOM_ITEMS.PELUCHE_ROOT_HALLOWEEN_2026; + + @Override + public void giveReward() { + + //Get all participant and give them the HalloweenRootPlush2026 + + ItemStack[] rewardToGive = new ItemStack[]{reward.getBest()}; + + for (UUID uuid : HalloweenFestivalManager.getParticipant()) { + + Player player = Bukkit.getPlayer(uuid); + + if (player != null) { + + OMCPlayer omcPlayer = OMCPlayer.of(player); + + HalloweenFestivalManager.sendMailItems(omcPlayer, omcPlayer, rewardToGive); + } else { + OfflinePlayer offlinePlayer = CacheOfflinePlayer.getOfflinePlayer(uuid); + + if (offlinePlayer == null) { + OMCLogger.error("no offline player for " + uuid); + continue; + } + + MailboxManager.sendItemsToOfflinePlayer(offlinePlayer, rewardToGive); + } + } + + } + + @Override + public ItemStack getItemMenuPreview() { + return reward.getBest(); + } + + @Override + public Component getRewardName() { + return TranslationManager.translation("itemsadder.omc_halloween.root_plush.name"); + } + + @Override + public List getRewardLore() { + return TranslationManager.translationLore("itemsadder.omc_halloween.root_plush.lore.0"); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/TerrorHouseAmbient.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/TerrorHouseAmbient.java new file mode 100644 index 000000000..579384d23 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/TerrorHouseAmbient.java @@ -0,0 +1,54 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.ambient; + +import fr.openmc.api.datapacks.builders.EnvironnementAttributeBuilder; +import fr.openmc.core.registry.ambient.CustomAmbient; +import fr.openmc.core.registry.ambient.CustomAmbientRegistry; +import fr.openmc.core.registry.ambient.builder.AmbientBuilder; +import fr.openmc.core.utils.nms.WeatherType; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.dimension.DimensionType; +import org.bukkit.Particle; + +public class TerrorHouseAmbient extends CustomAmbient { + @Override + public String getId() { + return "terror_house_ambient"; + } + + @Override + public AmbientBuilder getAmbientBuilder() { + return new AmbientBuilder(CustomAmbientRegistry.NAMESPACE, this.getId()) + .attributesBuilder(new EnvironnementAttributeBuilder() + .attributes(obj -> { + obj.addProperty("visual/sky_light_color", "#5435A6"); + obj.addProperty("visual/ambient_light_color", "#1A0600"); + + obj.addProperty("visual/sunrise_sunset_color", "#e540e58b"); + obj.addProperty("visual/sky_color", "#0D0030"); + + obj.addProperty("visual/fog_start_distance", 0); + obj.addProperty("visual/fog_end_distance", 90); + obj.addProperty("visual/fog_color", "#3C374A"); + obj.addProperty("visual/water_fog_color", "#3D2E42"); + + obj.addProperty("visual/cloud_height", 240); + }) + .ambientParticles(Particle.WITCH, 0.005) + .ambientParticles(Particle.DRAGON_BREATH, 0.005) + ) + .ambientLight(0.2f) + .skybox(DimensionType.Skybox.OVERWORLD) + .hasSkylight(true) + .waterColor("#604f7d") + .defaultClock("overworld") + .timelines("#minecraft:in_overworld") + .hasFixedTime(true, 200) + .hasPrecipitation(true, WeatherType.STORM); + } + + @Override + public ResourceKey getTransitionDimension() { + return Level.END; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChest.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChest.java new file mode 100644 index 000000000..ca264852a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChest.java @@ -0,0 +1,74 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests; + +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests.menu.LootChestMenu; +import fr.openmc.core.registry.loottable.CustomLootTable; +import fr.openmc.core.registry.loottable.LootReward; +import fr.openmc.core.utils.text.DateUtils; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; + +import java.util.HashMap; + +import java.util.Map; +import java.util.UUID; + +public class LootChest { + private final Map playerUsage = new HashMap<>(); + + private final int timeToReload; + @Getter public final BlockVector3 pos; + + private final CustomLootTable lootTable = OMCRegistry.CUSTOM_LOOT_TABLES.LOOTCHEST; + + public LootChest(int timeToReload, BlockVector3 pos) { + this.timeToReload = timeToReload; + this.pos = pos; + } + + public void use(Player player) { + if (!canUse(player.getUniqueId())) { + MessagesManager.sendMessage( + player, + Component.text(DateUtils.convertSecondToTime(playerUsage.get(player.getUniqueId()))).color(NamedTextColor.RED), + Prefix.HALLOWEEN, + MessageType.INFO, + true + ); + return; + } + + playerUsage.put(player.getUniqueId(), timeToReload); + + LootReward loot = lootTable.rollLoots(); + + if (loot == null) + return; + + new LootChestMenu(player, loot).open(); + } + + public boolean canUse(UUID uuid) { + return !playerUsage.containsKey(uuid); + } + + public void update(int time) { + playerUsage.entrySet().removeIf(entry -> { + int newTime = entry.getValue() - time; + + if (newTime <= 0) { + return true; + } + + entry.setValue(newTime); + return false; + }); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChestManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChestManager.java new file mode 100644 index 000000000..d65e776ba --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChestManager.java @@ -0,0 +1,93 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import java.util.List; + +public class LootChestManager { + + private static List chests; + + public LootChestManager() { + chests = getChests(); + placeChest(); + startCooldown(); + } + + public void startCooldown() { + Bukkit.getScheduler().runTaskTimer(OMCPlugin.getInstance(), () -> { + for (LootChest chest : chests) { + chest.update(5); + } + }, 0L, 5L * 20L); // 5 seconds + } + + private void placeChest() { + for (LootChest chest : chests) { + DimensionGenerator.HALLOWEEN_WORLD + .getBlockAt( + chest.getPos().x(), + chest.getPos().y(), + chest.getPos().z() + ).setType(Material.CHEST); + } + } + + public static void openChestAt(Location location, Player player) { + LootChest chest = getChest(location); + + if (chest == null) + return; + chest.use(player); + } + + private static LootChest getChest(Location location) { + + return chests.stream() + .filter(lootChest -> lootChest.getPos().equals(BukkitAdapter.asBlockVector(location))) + .findFirst().orElse(null); + } + + private List getChests() { + return List.of( + + new LootChest(15 * 60, BlockVector3.at(-58, -59, -67)), + new LootChest(15 * 60, BlockVector3.at(-50, -59, -75)), + new LootChest(15 * 60, BlockVector3.at(-58, -51, -63)), + new LootChest(15 * 60, BlockVector3.at(-47, -50, -62)), + new LootChest(15 * 60, BlockVector3.at(-63, -43, -46)), + new LootChest(15 * 60, BlockVector3.at(-67, -35, -70)), + new LootChest(15 * 60, BlockVector3.at(-81, -34, -46)), + new LootChest(15 * 60, BlockVector3.at(-43, -35, -48)), + new LootChest(15 * 60, BlockVector3.at(-63, -27, -90)), + new LootChest(15 * 60, BlockVector3.at(-43, -19, -76)), + new LootChest(15 * 60, BlockVector3.at(-77, -19, -80)), + new LootChest(15 * 60, BlockVector3.at(-65, -11, -67)), + new LootChest(15 * 60, BlockVector3.at(-46, -2, -70)), + new LootChest(15 * 60, BlockVector3.at(-56, -3, -57)), + new LootChest(15 * 60, BlockVector3.at(-41, 21, -71)), + new LootChest(15 * 60, BlockVector3.at(-39, 15, -62)), + new LootChest(15 * 60, BlockVector3.at(-38, 5, -64)), + new LootChest(15 * 60, BlockVector3.at(-63, 10, -72)), + new LootChest(15 * 60, BlockVector3.at(-78, 30, -56)), + new LootChest(15 * 60, BlockVector3.at(-40, 37, -66)), + new LootChest(15 * 60, BlockVector3.at(-60, 40, -81)), + new LootChest(15 * 60, BlockVector3.at(-53, 45, -78)), + new LootChest(15 * 60, BlockVector3.at(-68, 45, -61)), + new LootChest(15 * 60, BlockVector3.at(-60, 55, -70)), + new LootChest(15 * 60, BlockVector3.at(-56, 55, -76)), + new LootChest(15 * 60, BlockVector3.at(-58, 55, -62)), + new LootChest(10 * 60, BlockVector3.at(-44, 54, -72)), + new LootChest(10 * 60, BlockVector3.at(-49, 54, -62)), + new LootChest(5 * 60, BlockVector3.at(-63, 56, -75)) + ); + } + +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/loottable/LootChestLootTable.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/loottable/LootChestLootTable.java new file mode 100644 index 000000000..9fa3e5c11 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/loottable/LootChestLootTable.java @@ -0,0 +1,41 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests.loottable; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.registry.loottable.CustomLootTable; +import fr.openmc.core.registry.loottable.loots.CustomLoot; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class LootChestLootTable extends CustomLootTable { + + @Override + public Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.chest_lootbox"); + } + + @Override + public String getNamespace() { + return "omc_halloween:loot_chest_loot"; + } + + @Override + public Set getLoots() { + return new LinkedHashSet<>(List.of( + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW,0.003, 1, 2),// 0.0845% : 1/1884 coffre + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_RED,0.018, 1, 3),// 0.5068% : 1/198 coffre + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE,0.055, 1, 3),// 1.5489% : 1/65 coffre + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN,0.075, 1, 3),// 2.1121% : 1/48 coffre + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN,0.4, 1, 5),// 11.2644% : 1/9 coffre + new ItemLoot(Material.COBWEB,1, 2, 10), + new ItemLoot(Material.SUGAR, 0.8, 2, 5),// 22.5289% : 1/5 coffre + new ItemLoot(Material.REDSTONE, 0.5, 2, 5),// 14.0805% : 1/8 coffre + new ItemLoot(Material.PUMPKIN, 0.7, 1)// 19.7128% : 1/6 coffre + )); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/menu/LootChestMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/menu/LootChestMenu.java new file mode 100644 index 000000000..f331c9084 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/menu/LootChestMenu.java @@ -0,0 +1,125 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests.menu; + +import fr.openmc.api.menulib.Menu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemMenuBuilder; +import fr.openmc.api.menulib.utils.MenuUtils; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.registry.loottable.LootReward; +import fr.openmc.core.registry.loottable.loots.CustomLoot; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.utils.RandomUtils; +import fr.openmc.core.utils.text.messages.MessageType; +import fr.openmc.core.utils.text.messages.MessagesManager; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class LootChestMenu extends Menu { + + private final LootReward loot; + + public LootChestMenu(Player owner, LootReward loot) { + super(owner); + this.loot = loot; + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.events.halloween.festival.chest_lootbox.menu.name"); + } + + @Override + public String getTexture() { + return ""; //il n'a pas besoin de texture + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGE; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) { + + } + + @Override + public void onClose(InventoryCloseEvent event) { + + if (event.getReason().equals(InventoryCloseEvent.Reason.PLUGIN)) + return; + + MessagesManager.sendMessage(event.getPlayer(), + TranslationManager.translation("feature.events.halloween.festival.chest_lootbox.prevention"), + Prefix.HALLOWEEN, + MessageType.INFO, + true + ); + } + + private static final List CHEST_MENU_ITEM_SLOTS = + IntStream.rangeClosed(0, 26) + .boxed() + .toList(); + + @Override + public @NotNull Map getContent() { + Map inventory = new HashMap<>(); + + List slots = new ArrayList<>(CHEST_MENU_ITEM_SLOTS); + + for (CustomLoot cloot : loot.loots()) { + + if (cloot instanceof ItemLoot itemLoot) { + + int amount = itemLoot.getRandomAmount(); + + while (amount > 0) { + int slot = RandomUtils.getRandomObjectFromList(slots); + + int amountToDepose = Math.min( + amount, + RandomUtils.randomBetween(1, 3) + ); + + ItemStack item = itemLoot.getItem().clone(); + item.setAmount(amountToDepose); + + inventory.put(slot, new ItemMenuBuilder(this, item)); + + slots.remove(Integer.valueOf(slot)); + + amount -= amountToDepose; + } + } + } + + inventory.put(31, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.MAILBOX_HOURGLASS, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.chest_lootbox.menu.button.name")); + itemMeta.lore(List.of(TranslationManager.translation("feature.events.halloween.festival.chest_lootbox.menu.button.lore"))); + }).setCloseButton()); + + return inventory; + } + + @Override + public List getTakableSlot() { + return Stream.concat( + CHEST_MENU_ITEM_SLOTS.stream(), + MenuUtils.getInventoryItemSlots(this.getInventorySize().getSize()).stream() + ).toList(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSkeletonLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSkeletonLV1.java new file mode 100644 index 000000000..ec0dcffa6 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSkeletonLV1.java @@ -0,0 +1,47 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseSkeletonLV1 extends CustomMob { + + public HouseSkeletonLV1(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.skeleton.name.0"), + Skeleton.class, + 20, + 3.0, + List.of( + new XpLoot(35, 60, 0.5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.2, 1, 2) + ) + ); + } + + @Override + public Skeleton spawn(Location spawnLocation) { + Skeleton skeleton = getPreBuildMob(spawnLocation); + + skeleton.getEquipment().setHelmet(new ItemStack(Material.LEATHER_HELMET)); + skeleton.getEquipment().setItemInMainHand(new ItemStack(Material.BOW)); + + return skeleton; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSpiderLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSpiderLV1.java new file mode 100644 index 000000000..a9d750990 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSpiderLV1.java @@ -0,0 +1,40 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.entity.Spider; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.List; + +public class HouseSpiderLV1 extends CustomMob { + + public HouseSpiderLV1(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.spider.name.0"), + Spider.class, + 16, + 3.0, + List.of( + new XpLoot(25, 50, 0.5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.2, 1, 2) + ) + ); + } + + @Override + public Spider spawn(Location spawnLocation) { + return getPreBuildMob(spawnLocation); + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseZombieLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseZombieLV1.java new file mode 100644 index 000000000..645ce5c29 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseZombieLV1.java @@ -0,0 +1,69 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.RandomUtils; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.*; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseZombieLV1 extends CustomMob { + + public HouseZombieLV1(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.zombie.name.0"), + Zombie.class, + 20, + 3.0 , + List.of( + new XpLoot(50, 75, 0.5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.3, 1, 4) + ) + ); + } + + @Override + public Zombie spawn(Location spawnLocation) { + Zombie zombie = this.getPreBuildMob(spawnLocation); + + zombie.getEquipment().setHelmet(new ItemStack( + RandomUtils.getRandomObject( + Material.PUMPKIN, + Material.AIR + ) + )); + + zombie.getEquipment().setLeggings(new ItemStack(Material.CHAINMAIL_LEGGINGS)); + + zombie.getEquipment().setBoots(new ItemStack( + RandomUtils.getRandomObject( + Material.LEATHER_BOOTS, + Material.COPPER_BOOTS + ) + )); + + zombie.getEquipment().setItemInMainHand(new ItemStack( + RandomUtils.getRandomObject( + Material.IRON_AXE, + Material.IRON_SHOVEL, + Material.AIR + ) + )); + + return zombie; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseBruteLV3.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseBruteLV3.java new file mode 100644 index 000000000..351e484c3 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseBruteLV3.java @@ -0,0 +1,56 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.PiglinBrute; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseBruteLV3 extends CustomMob { + + public HouseBruteLV3(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.brute.name.2"), + PiglinBrute.class, + 50, + 8.0, + List.of( + new XpLoot(200, 350, 1.0), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.8, 4, 10), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 0.3, 1, 5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.01, 1, 2), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_RED, 0.0002, 1), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW, 0.00005, 1) + ) + ); + } + + @Override + public PiglinBrute spawn(Location spawnLocation) { + PiglinBrute zombie = getPreBuildMob(spawnLocation); + + zombie.getEquipment().setHelmet(new ItemStack(Material.IRON_HELMET)); + zombie.getEquipment().setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); + zombie.getEquipment().setLeggings(new ItemStack(Material.IRON_LEGGINGS)); + zombie.getEquipment().setBoots(new ItemStack(Material.IRON_BOOTS)); + zombie.getEquipment().setItemInMainHand(new ItemStack(Material.IRON_AXE)); + + zombie.setAdult(); + + return zombie; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseWitchLV3.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseWitchLV3.java new file mode 100644 index 000000000..6352b4a03 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseWitchLV3.java @@ -0,0 +1,44 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.entity.Witch; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.List; + +public class HouseWitchLV3 extends CustomMob { + + public HouseWitchLV3(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.witch.name.2"), + Witch.class, + 32, + 6.0, + List.of( + new XpLoot(150, 250, 0.9), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.6, 2, 6), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 0.2, 1, 5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.008, 1, 2), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_RED, 0.0001, 1), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW, 0.00004, 1) + ) + ); + } + + @Override + public Witch spawn(Location spawnLocation) { + return getPreBuildMob(spawnLocation); + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseZombieLV3.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseZombieLV3.java new file mode 100644 index 000000000..9c064348a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseZombieLV3.java @@ -0,0 +1,60 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.RandomUtils; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Zombie; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseZombieLV3 extends CustomMob { + + public HouseZombieLV3(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.zombie.name.2"), + Zombie.class, + 40, + 7.0, + List.of( + new XpLoot(120, 200, 0.85), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.5, 3, 7), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 0.3, 1, 5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.01, 1, 2), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_RED, 0.0002, 1), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW, 0.00005, 1) + ) + ); + } + + @Override + public Zombie spawn(Location spawnLocation) { + Zombie zombie = getPreBuildMob(spawnLocation); + + zombie.getEquipment().setHelmet(new ItemStack(Material.IRON_HELMET)); + zombie.getEquipment().setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); + zombie.getEquipment().setLeggings(new ItemStack(Material.IRON_LEGGINGS)); + zombie.getEquipment().setBoots(new ItemStack(Material.IRON_BOOTS)); + zombie.getEquipment().setItemInMainHand( + new ItemStack(RandomUtils.getRandomObject( + Material.IRON_AXE, + Material.IRON_SWORD + )) + ); + + return zombie; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseBlazeLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseBlazeLV2.java new file mode 100644 index 000000000..d4f632b08 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseBlazeLV2.java @@ -0,0 +1,59 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.entity.Blaze; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.List; + +public class HouseBlazeLV2 extends CustomMob { + + public HouseBlazeLV2(String id) { + super( + id, + TranslationManager.translation( + "feature.events.halloween.festival.mob.blaze.name.1" + ), + Blaze.class, + 25, + 6.0, + List.of( + new XpLoot(75, 110, 0.7), + new ItemLoot( + OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, + 0.35, + 1, + 4 + ), + new ItemLoot( + OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, + 0.10, + 1, + 4 + ), + new ItemLoot( + OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, + 0.02, + 1 + ) + ) + ); + } + + @Override + public Blaze spawn(Location spawnLocation) { + return getPreBuildMob(spawnLocation); + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseMossySkeletonLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseMossySkeletonLV2.java new file mode 100644 index 000000000..15b73460e --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseMossySkeletonLV2.java @@ -0,0 +1,51 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Bogged; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseMossySkeletonLV2 extends CustomMob { + + public HouseMossySkeletonLV2(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.skeleton.name.1"), + Bogged.class, + 24, + 4.0, + List.of( + new XpLoot(75, 110, 0.7), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.35, 1, 4), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 0.10, 1, 4), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.04, 1) + ) + ); + } + + @Override + public Bogged spawn(Location spawnLocation) { + Bogged skeleton = getPreBuildMob(spawnLocation); + + skeleton.getEquipment().setHelmet(new ItemStack(Material.CHAINMAIL_HELMET)); + skeleton.getEquipment().setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); + skeleton.getEquipment().setItemInMainHand(new ItemStack(Material.BOW)); + + return skeleton; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSkeletonLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSkeletonLV2.java new file mode 100644 index 000000000..05e410db5 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSkeletonLV2.java @@ -0,0 +1,50 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Skeleton; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseSkeletonLV2 extends CustomMob { + + public HouseSkeletonLV2(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.skeleton.name.1"), + Skeleton.class, + 24, + 4.0, + List.of( + new XpLoot(75, 110, 0.7), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.35, 1, 4), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 0.10, 1, 4), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.04, 1) + ) + ); + } + + @Override + public Skeleton spawn(Location spawnLocation) { + Skeleton skeleton = getPreBuildMob(spawnLocation); + + skeleton.getEquipment().setHelmet(new ItemStack(Material.CHAINMAIL_HELMET)); + skeleton.getEquipment().setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); + skeleton.getEquipment().setItemInMainHand(new ItemStack(Material.BOW)); + + return skeleton; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSpiderLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSpiderLV2.java new file mode 100644 index 000000000..cbbddfd40 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSpiderLV2.java @@ -0,0 +1,42 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.entity.CaveSpider; +import org.bukkit.event.entity.EntityDeathEvent; + +import java.util.List; + +public class HouseSpiderLV2 extends CustomMob { + + public HouseSpiderLV2(String id) { + super(id, + TranslationManager.translation("feature.events.halloween.festival.mob.spider.name.1"), + CaveSpider.class, + 18, + 3.0, + List.of( + new XpLoot(60, 90, 0.65), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.3, 1, 3), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 0.07, 1, 4), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.02, 1) + ) + ); + } + + @Override + public CaveSpider spawn(Location spawnLocation) { + return getPreBuildMob(spawnLocation); + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseWitherSkeletonLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseWitherSkeletonLV2.java new file mode 100644 index 000000000..c79455a81 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseWitherSkeletonLV2.java @@ -0,0 +1,75 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.WitherSkeleton; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class HouseWitherSkeletonLV2 extends CustomMob { + + public HouseWitherSkeletonLV2(String id) { + super( + id, + TranslationManager.translation( + "feature.events.halloween.festival.mob.wither_skeleton.name.1" + ), + WitherSkeleton.class, + 30, + 6.0, + List.of( + new XpLoot(90, 130, 0.75), + new ItemLoot( + OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, + 0.4, + 1, + 4 + ), + new ItemLoot( + OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, + 0.13, + 1, + 2 + ), + new ItemLoot( + OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, + 0.04, + 1 + ) + ) + ); + } + + @Override + public WitherSkeleton spawn(Location spawnLocation) { + WitherSkeleton skeleton = getPreBuildMob(spawnLocation); + + skeleton.getEquipment().setHelmet( + new ItemStack(Material.CHAINMAIL_HELMET) + ); + + skeleton.getEquipment().setChestplate( + new ItemStack(Material.IRON_CHESTPLATE) + ); + + skeleton.getEquipment().setItemInMainHand( + new ItemStack(Material.STONE_SWORD) + ); + + return skeleton; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseZombieLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseZombieLV2.java new file mode 100644 index 000000000..613de04c8 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseZombieLV2.java @@ -0,0 +1,59 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.registry.loottable.loots.ItemLoot; +import fr.openmc.core.registry.loottable.loots.XpLoot; +import fr.openmc.core.registry.mobs.CustomMob; +import fr.openmc.core.utils.text.messages.TranslationManager; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Zombie; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class HouseZombieLV2 extends CustomMob { + + public HouseZombieLV2(String id) { + super( + id, + TranslationManager.translation("feature.events.halloween.festival.mob.zombie.name.1"), + Zombie.class, + 30, + 5.0, + List.of( + new XpLoot(75, 125, 0.7), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.4, 2, 5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.13, 2, 5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 0.04, 1) + ) + ); + } + + @Override + public Zombie spawn(Location spawnLocation) { + Zombie zombie = getPreBuildMob(spawnLocation); + + zombie.getEquipment().setHelmet(new ItemStack(Material.CARVED_PUMPKIN)); + zombie.getEquipment().setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); + zombie.getEquipment().setLeggings(new ItemStack(Material.IRON_LEGGINGS)); + zombie.getEquipment().setBoots(new ItemStack(Material.IRON_BOOTS)); + + Material weapon = ThreadLocalRandom.current().nextBoolean() + ? Material.IRON_AXE + : Material.IRON_SWORD; + + zombie.getEquipment().setItemInMainHand(new ItemStack(weapon)); + + return zombie; + } + + @Override + public void onDeath(CustomMob thisMob, EntityDeathEvent event) { + if (TerrorHouseManager.entityCount > 0) + TerrorHouseManager.entityCount -= 1; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/commands/HalloweenCommands.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java similarity index 68% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/commands/HalloweenCommands.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java index 11bde75c0..9cbe88aa3 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/commands/HalloweenCommands.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java @@ -1,6 +1,6 @@ -package fr.openmc.core.features.events.contents.halloween.commands; +package fr.openmc.core.features.events.contents.halloween.pumpkin.commands; -import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; import revxrsal.commands.annotation.Command; import revxrsal.commands.annotation.Subcommand; import revxrsal.commands.bukkit.annotation.CommandPermission; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/listeners/HalloweenNPCListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/listeners/HalloweenNPCListener.java similarity index 81% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/listeners/HalloweenNPCListener.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/listeners/HalloweenNPCListener.java index fb954e064..4a819d3ba 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/listeners/HalloweenNPCListener.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/listeners/HalloweenNPCListener.java @@ -1,8 +1,8 @@ -package fr.openmc.core.features.events.contents.halloween.listeners; +package fr.openmc.core.features.events.contents.halloween.pumpkin.listeners; import de.oliver.fancynpcs.api.events.NpcInteractEvent; import fr.openmc.core.bootstrap.features.types.LoadIfEnable; -import fr.openmc.core.features.events.contents.halloween.menus.HalloweenPumpkinDepositMenu; +import fr.openmc.core.features.events.contents.halloween.pumpkin.menus.HalloweenPumpkinDepositMenu; import fr.openmc.core.hooks.FancyNpcsHook; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/managers/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/managers/HalloweenManager.java similarity index 96% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/managers/HalloweenManager.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/managers/HalloweenManager.java index 27a5eaee2..410071651 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/managers/HalloweenManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/managers/HalloweenManager.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.managers; +package fr.openmc.core.features.events.contents.halloween.pumpkin.managers; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; @@ -16,9 +16,9 @@ import fr.openmc.core.bootstrap.integration.OMCLogger; import fr.openmc.core.bootstrap.listeners.ListenerFactory; import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.contents.halloween.commands.HalloweenCommands; -import fr.openmc.core.features.events.contents.halloween.listeners.HalloweenNPCListener; -import fr.openmc.core.features.events.contents.halloween.models.HalloweenData; +import fr.openmc.core.features.events.contents.halloween.pumpkin.commands.HalloweenCommands; +import fr.openmc.core.features.events.contents.halloween.pumpkin.listeners.HalloweenNPCListener; +import fr.openmc.core.features.events.contents.halloween.pumpkin.models.HalloweenData; import fr.openmc.core.features.mailboxes.MailboxManager; import fr.openmc.core.utils.cache.CachePlayerName; import fr.openmc.core.utils.text.messages.TranslationManager; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/menus/HalloweenPumpkinDepositMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/menus/HalloweenPumpkinDepositMenu.java similarity index 95% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/menus/HalloweenPumpkinDepositMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/menus/HalloweenPumpkinDepositMenu.java index 008f48839..66003dd33 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/menus/HalloweenPumpkinDepositMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/menus/HalloweenPumpkinDepositMenu.java @@ -1,9 +1,9 @@ -package fr.openmc.core.features.events.contents.halloween.menus; +package fr.openmc.core.features.events.contents.halloween.pumpkin.menus; import fr.openmc.api.menulib.Menu; import fr.openmc.api.menulib.utils.InventorySize; import fr.openmc.api.menulib.utils.ItemMenuBuilder; -import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; import fr.openmc.core.utils.bukkit.ItemUtils; import fr.openmc.core.utils.text.messages.MessageType; import fr.openmc.core.utils.text.messages.MessagesManager; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/models/HalloweenData.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/models/HalloweenData.java similarity index 89% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/models/HalloweenData.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/models/HalloweenData.java index ffc4cac6e..0c7954c2a 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/models/HalloweenData.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/models/HalloweenData.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.models; +package fr.openmc.core.features.events.contents.halloween.pumpkin.models; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; diff --git a/src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java b/src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java new file mode 100644 index 000000000..06c299e68 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java @@ -0,0 +1,72 @@ +package fr.openmc.core.features.events.sbinfos; + +import fr.openmc.core.features.displays.scoreboards.sb.InfoSwapper; +import fr.openmc.core.features.economy.EconomyManager; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenFestivalManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.WitchShopManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.PointRewards; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floors; +import fr.openmc.core.utils.bedrock.CharRemplacementUtils; +import fr.openmc.core.utils.text.DateUtils; +import fr.openmc.core.utils.text.messages.Prefix; +import fr.openmc.core.utils.text.messages.TranslationManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.entity.Player; + +import java.util.List; + +import static net.kyori.adventure.text.Component.text; + +public class HalloweenFestivalInfos implements InfoSwapper { + + @Override + public boolean isActive() { + return HalloweenFestivalManager.isActive(); + } + + @Override + public void addInfosTo(Player player, List lines) { + + lines.add(Prefix.HALLOWEEN.getPrefix().decoration(TextDecoration.BOLD, true)); + + PointRewards reward = TerrorHouseManager.currentRewardToReach; + Floors floorToReach = TerrorHouseManager.currentFloorToReach; + + double globalAdvancement = TerrorHouseManager.globalAdvancement; + double floorAdvancement = TerrorHouseManager.floorAdvancement; + + lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) + .append(reward.equals(PointRewards.NULL) + ? TranslationManager.translation("feature.events.halloween.festival.sb.info.0", + text(EconomyManager.getFormattedSimplifiedNumber(globalAdvancement)) + ) + + : TranslationManager.translation("feature.events.halloween.festival.sb.info.1", + text(EconomyManager.getFormattedSimplifiedNumber(globalAdvancement)), + text(EconomyManager.getFormattedSimplifiedNumber(reward.getGlobalPointsRequire())) + ) + ) + .append(text(WitchShopManager.getHalloweenPointIcon())) + ); + + lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) + .append(TerrorHouseManager.finalFloorReach + ? TranslationManager.translation("feature.events.halloween.festival.sb.info.2") + : TranslationManager.translation("feature.events.halloween.festival.sb.info.3", + text(floorToReach.getSimplifyFloor()), + text(EconomyManager.getFormattedSimplifiedNumber(floorAdvancement)), + text(EconomyManager.getFormattedSimplifiedNumber(floorToReach.getRequire())), + text(WitchShopManager.getHalloweenPointIcon()) + )) + ); + + lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) + .appendSpace() + .append(text(DateUtils.convertMillisToTime(HalloweenFestivalManager.getRemainingTime()), TextColor.color(0xFF8F06))) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/leaderboards/leaderboards/PumpkinCountLeaderBoard.java b/src/main/java/fr/openmc/core/features/leaderboards/leaderboards/PumpkinCountLeaderBoard.java index 2b696b5d1..08835c714 100644 --- a/src/main/java/fr/openmc/core/features/leaderboards/leaderboards/PumpkinCountLeaderBoard.java +++ b/src/main/java/fr/openmc/core/features/leaderboards/leaderboards/PumpkinCountLeaderBoard.java @@ -2,10 +2,9 @@ import fr.openmc.api.omcplayer.OMCOfflinePlayer; import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; -import fr.openmc.core.features.events.contents.halloween.models.HalloweenData; +import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.pumpkin.models.HalloweenData; import fr.openmc.core.features.leaderboards.LeaderBoard; -import fr.openmc.core.utils.cache.CachePlayerName; import fr.openmc.core.utils.text.ColorUtils; import fr.openmc.core.utils.text.messages.TranslationManager; import net.kyori.adventure.text.Component; @@ -32,7 +31,7 @@ public String getId() { @Override public Component createComponent() { - if (HalloweenManager.getAllHalloweenData().isEmpty()) + if (HalloweenManager.getAllHalloweenData() == null || HalloweenManager.getAllHalloweenData().isEmpty()) return TranslationManager.translation("feature.leaderboards.empty.players") .color(NamedTextColor.RED); diff --git a/src/main/java/fr/openmc/core/hooks/WorldEditHook.java b/src/main/java/fr/openmc/core/hooks/WorldEditHook.java new file mode 100644 index 000000000..4a6a8c61e --- /dev/null +++ b/src/main/java/fr/openmc/core/hooks/WorldEditHook.java @@ -0,0 +1,32 @@ +package fr.openmc.core.hooks; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.hooks.Hooks; +import org.bukkit.plugin.PluginManager; + +import java.util.Set; + +public class WorldEditHook extends Hooks { + + private static final String WE = "WorldEdit"; + private static final String FAWE = "FastAsyncWorldEdit"; + + public static boolean isEnable() { + return Hooks.isEnabled(WorldEditHook.class); + } + + @Override + protected Set getPluginsName() { + return Set.of(WE, FAWE); + } + + @Override + public boolean arePluginEnabled() { + return isLoaded(WE) || isLoaded(FAWE); + } + + private static boolean isLoaded(String name) { + PluginManager pm = OMCPlugin.getInstance().getServer().getPluginManager(); + return pm.getPlugin(name) != null && pm.isPluginEnabled(name); + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/hooks/itemsadder/ItemsAdderHook.java b/src/main/java/fr/openmc/core/hooks/itemsadder/ItemsAdderHook.java index 3716709f5..a4857306e 100644 --- a/src/main/java/fr/openmc/core/hooks/itemsadder/ItemsAdderHook.java +++ b/src/main/java/fr/openmc/core/hooks/itemsadder/ItemsAdderHook.java @@ -8,7 +8,7 @@ import fr.openmc.core.hooks.itemsadder.behaviours.BehaviourUpBlock; import fr.openmc.core.hooks.itemsadder.events.IAItemLoadEvent; import fr.openmc.core.hooks.itemsadder.placeholders.IAPlaceholderRegistry; -import fr.openmc.core.utils.FilesUtils; +import fr.openmc.core.utils.file.FilesUtils; import fr.openmc.core.utils.ZipUtils; import io.papermc.paper.plugin.bootstrap.BootstrapContext; import lombok.Getter; diff --git a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java index 9f4cdff71..9a0e65dd6 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java @@ -10,6 +10,7 @@ import fr.openmc.core.features.events.contents.dailyevents.contents.bloodynight.contents.ambient.BloodyAmbient; import fr.openmc.core.features.events.contents.dailyevents.contents.goldenharvest.contents.ambient.GoldenAmbient; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.ambient.BlessedAmbient; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.ambient.TerrorHouseAmbient; import fr.openmc.core.registry.ambient.contents.DarkAmbient; import fr.openmc.core.registry.ambient.contents.HellAmbient; import fr.openmc.core.registry.ambient.contents.OpenAmbient; @@ -39,6 +40,7 @@ public class CustomAmbientRegistry extends Registry public final CustomAmbient GOLDEN = register(new GoldenAmbient()); public final CustomAmbient BLOODY = register(new BloodyAmbient()); public final CustomAmbient BLESSED = register(new BlessedAmbient()); + public final CustomAmbient TERROR_HOUSE = register(new TerrorHouseAmbient()); @Override public Set getListeners() { diff --git a/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java index 87c23880c..832c14375 100644 --- a/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java +++ b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java @@ -15,6 +15,7 @@ import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.items.FishingFurnitureLootbox; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.items.LegendaryFishingTreasureLootbox; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.items.RareFishingTreasureLootbox; +import fr.openmc.core.features.events.contents.halloween.festival.CandyItem; import fr.openmc.core.features.itemsadder.elevator.ElevatorBlock; import fr.openmc.core.features.itemsadder.elevator.ElevatorColor; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; @@ -94,6 +95,7 @@ public class CustomItemRegistry extends Registry public final CustomItem PELUCHE_ROOT = register("omc_plush:peluche_root", Material.PAPER); public final CustomItem URNE = register("omc_blocks:urne", Material.GLASS); public final CustomItem CAISSE = register("omc_shops:caisse", Material.PAPER); + public final CustomItem PELUCHE_ROOT_HALLOWEEN_2026 = register("omc_halloween:peluche_root_halloween_2026", Material.PAPER); public final CustomItem ELEVATOR_GRAY = register(new ElevatorBlock(ElevatorColor.GRAY)); public final CustomItem ELEVATOR_RED = register(new ElevatorBlock(ElevatorColor.RED)); @@ -196,6 +198,13 @@ public class CustomItemRegistry extends Registry public final CustomItem ABONDANCE_LEGGINGS = register("omc_daily_events:abondance_leggings", Material.IRON_LEGGINGS); public final CustomItem ABONDANCE_BOOTS = register("omc_daily_events:abondance_boots", Material.IRON_BOOTS); + public final CustomItem CANDY_RED = register(new CandyItem("omc_halloween:candy_red", 4, Material.APPLE)); + public final CustomItem CANDY_YELLOW = register(new CandyItem("omc_halloween:candy_yellow", 2, Material.APPLE)); + public final CustomItem CANDY_GREEN = register(new CandyItem("omc_halloween:candy_green", 3, Material.APPLE)); + public final CustomItem CANDY_BLUE = register(new CandyItem("omc_halloween:candy_blue", 5, Material.APPLE)); + public final CustomItem CANDY_BROWN = register(new CandyItem("omc_halloween:candy_brown", 20, Material.APPLE)); + + /* Lootbox */ public final CustomItem KITCHEN_BARSTOOL = register("kitchen:kitchen_barstool", Material.PAPER); public final CustomItem KITCHEN_BIN = register("kitchen:kitchen_bin", Material.PAPER); public final CustomItem KITCHEN_CHAIR = register("kitchen:kitchen_chair", Material.PAPER); @@ -278,6 +287,38 @@ public class CustomItemRegistry extends Registry public final CustomItem MODERN_FURNITURE_PACK_VOL2_WARDROBE_01 = register("elitecreatures:modern_furniture_pack_vol2_wardrobe_01", Material.PAPER); public final CustomItem MODERN_FURNITURE_PACK_VOL2_WARDROBE_02 = register("elitecreatures:modern_furniture_pack_vol2_wardrobe_02", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_BROOM = register("elitecreatures:halloween_decoration_v1_broom", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_CANDLE = register("elitecreatures:halloween_decoration_v1_candle", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_CELLING_LAMP = register("elitecreatures:halloween_decoration_v1_celling_lamp", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_MR_THING = register("elitecreatures:halloween_decoration_v1_mr_thing", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_PICTURE = register("elitecreatures:halloween_decoration_v1_picture", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_PUMPKIN_1 = register("elitecreatures:halloween_decoration_v1_pumpkin_1", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_PUMPKIN_2 = register("elitecreatures:halloween_decoration_v1_pumpkin_2", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_PUMPKIN_3 = register("elitecreatures:halloween_decoration_v1_pumpkin_3", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_PUMPKIN_4 = register("elitecreatures:halloween_decoration_v1_pumpkin_4", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_ROSE_IN_GLASS = register("elitecreatures:halloween_decoration_v1_rose_in_glass", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_SCARECROW = register("elitecreatures:halloween_decoration_v1_scarecrow", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_SKULL_JAR = register("elitecreatures:halloween_decoration_v1_skull_jar", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_SKULL_SUN_FLOWER = register("elitecreatures:halloween_decoration_v1_skull_sun_flower", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_SMILE_FLAG = register("elitecreatures:halloween_decoration_v1_smile_flag", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_SPIDER_IN_JAR = register("elitecreatures:halloween_decoration_v1_spider_in_jar", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_TOMB_STONE_1 = register("elitecreatures:halloween_decoration_v1_tomb_stone_1", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_TOMB_STONE_2 = register("elitecreatures:halloween_decoration_v1_tomb_stone_2", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_TRICK_OR_TREAT_BOWL = register("elitecreatures:halloween_decoration_v1_trick_or_treat_bowl", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_WALL_LAMP = register("elitecreatures:halloween_decoration_v1_wall_lamp", Material.PAPER); + public final CustomItem HALLOWEEN_DECORATION_V1_WITCH_POT = register("elitecreatures:halloween_decoration_v1_witch_pot", Material.PAPER); + + public final CustomItem HALLOWEEN_PACK_CAULDRON = register("pack_halloween_pack_fur:cauldron", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_TOILE_1 = register("pack_halloween_pack_fur:toile_1", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_TOILE_2 = register("pack_halloween_pack_fur:toile_2", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_TOMBE_1 = register("pack_halloween_pack_fur:tombe_1", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_TOMBE_2 = register("pack_halloween_pack_fur:tombe_2", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_WOOD_CROSS = register("pack_halloween_pack_fur:wood_cross", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_COFFIN_OPEN = register("pack_halloween_pack_fur:coffin_open", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_COFFIN_CLOSE = register("pack_halloween_pack_fur:coffin_close", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_PUMPKIN_HAT = register("pack_halloween_pack_fur:pumpkin_hat", Material.PAPER); + public final CustomItem HALLOWEEN_PACK_PUMPKIN = register("pack_halloween_pack_fur:pumpkin", Material.PAPER); + public final CustomItem MODERN_BOX = register(new ModernBox("omc_bits:modern_box")); public final CustomItem KITCHEN_BOX = register(new KitchenBox("omc_bits:kitchen_box")); public final CustomItem OFFICE_BOX = register(new OfficeBox("omc_bits:office_box")); diff --git a/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java b/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java index 5cc2abe7c..095bae96b 100644 --- a/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java +++ b/src/main/java/fr/openmc/core/registry/loottable/CustomLootTableRegistry.java @@ -21,6 +21,7 @@ import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.loottable.lootbox.FishingFurnitureLootTable; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.loottable.lootbox.LegendaryFishingTreasureLootTable; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.loottable.lootbox.RareFishingTreasureLootTable; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.chests.loottable.LootChestLootTable; import fr.openmc.core.registry.loottable.contents.MachineBallLootTable; public class CustomLootTableRegistry extends Registry implements KeyedRegistry { @@ -51,7 +52,7 @@ public class CustomLootTableRegistry extends Registry i public final CustomLootTable QUIZZ = register(new QuizzLootTable()); public final CustomLootTable CHALLENGE = register(new ChallengeLootTable()); - + public final CustomLootTable LOOTCHEST = register(new LootChestLootTable()); @Override public String key(CustomLootTable registryObject) { return registryObject.getNamespace(); diff --git a/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java b/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java index e829f95ff..163b891ec 100644 --- a/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java +++ b/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java @@ -16,6 +16,13 @@ import fr.openmc.core.features.events.contents.dailyevents.contents.bloodynight.contents.mobs.vampire.VampireSlave; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.mobs.*; import fr.openmc.core.features.events.contents.dailyevents.contents.miraculousfishing.contents.mobs.kraken.Kraken; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy.HouseSkeletonLV1; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy.HouseSpiderLV1; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy.HouseZombieLV1; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard.HouseBruteLV3; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard.HouseWitchLV3; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard.HouseZombieLV3; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal.*; import fr.openmc.core.registry.mobs.listeners.CustomMobBossbarListener; import fr.openmc.core.registry.mobs.listeners.CustomMobDeathListener; import fr.openmc.core.registry.mobs.listeners.CustomMobLoadListener; @@ -122,6 +129,69 @@ public class CustomMobRegistry extends Registry VampireSlave::new )); + // TERROR HOUSE MOB // + + public final CustomMobEntry HOUSE_ZOMBIE_LV1 = register(new CustomMobEntry( + "omc_witch_house:house_zombie_lv1", + HouseZombieLV1::new + )); + + public final CustomMobEntry HOUSE_SKELETON_LV1 = register(new CustomMobEntry( + "omc_witch_house:house_skeleton_lv1", + HouseSkeletonLV1::new + )); + + public final CustomMobEntry HOUSE_SPIDER_LV1 = register(new CustomMobEntry( + "omc_witch_house:house_spider_lv1", + HouseSpiderLV1::new + )); + + + public final CustomMobEntry HOUSE_ZOMBIE_LV2 = register(new CustomMobEntry( + "omc_witch_house:house_zombie_lv2", + HouseZombieLV2::new + )); + + public final CustomMobEntry HOUSE_SKELETON_LV2 = register(new CustomMobEntry( + "omc_witch_house:house_skeleton_lv2", + HouseSkeletonLV2::new + )); + + public final CustomMobEntry HOUSE_MOSSY_SKELETON_LV2 = register(new CustomMobEntry( + "omc_witch_house:house_mossy_skeleton_lv2", + HouseMossySkeletonLV2::new + )); + + public final CustomMobEntry HOUSE_SPIDER_LV2 = register(new CustomMobEntry( + "omc_witch_house:house_spider_lv2", + HouseSpiderLV2::new + )); + + public final CustomMobEntry HOUSE_BLAZE_LV2 = register(new CustomMobEntry( + "omc_witch_house:house_blaze_lv2", + HouseBlazeLV2::new + )); + + public final CustomMobEntry HOUSE_WITHER_SKELETON_LV2 = register(new CustomMobEntry( + "omc_witch_house:house_wither_skeleton_lv2", + HouseWitherSkeletonLV2::new + )); + + public final CustomMobEntry HOUSE_ZOMBIE_LV3 = register(new CustomMobEntry( + "omc_witch_house:house_zombie_lv3", + HouseZombieLV3::new + )); + + public final CustomMobEntry HOUSE_WITCH_LV3 = register(new CustomMobEntry( + "omc_witch_house:house_witch_lv3", + HouseWitchLV3::new + )); + + public final CustomMobEntry HOUSE_BRUTE_LV3 = register(new CustomMobEntry( + "omc_witch_house:house_brute_lv3", + HouseBruteLV3::new + )); + public final static Set HAS_BOSSBAR = new HashSet<>(); @Override diff --git a/src/main/java/fr/openmc/core/registry/regions/CustomRegion.java b/src/main/java/fr/openmc/core/registry/regions/CustomRegion.java index b5866b083..071a661a3 100644 --- a/src/main/java/fr/openmc/core/registry/regions/CustomRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/CustomRegion.java @@ -1,5 +1,6 @@ package fr.openmc.core.registry.regions; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.math.BlockVector3; import net.kyori.adventure.key.Key; import org.bukkit.Location; @@ -10,14 +11,16 @@ public abstract class CustomRegion { public abstract World getWorld(); public abstract boolean contains(BlockVector3 pos); + public abstract BlockVector3 getPos1(); public abstract BlockVector3 getPos2(); + public abstract BlockVector3 getCenter(); public final boolean contains(Location loc) { if (loc == null || loc.getWorld() == null) return false; if (getWorld() == null) return false; if (!loc.getWorld().getName().equals(getWorld().getName())) return false; - return contains(BlockVector3.at(loc.getX(), loc.getY(), loc.getZ())); + return contains(BukkitAdapter.asBlockVector(loc)); } } diff --git a/src/main/java/fr/openmc/core/registry/regions/CustomRegionRegistry.java b/src/main/java/fr/openmc/core/registry/regions/CustomRegionRegistry.java index 80e154a70..b19cf4ad8 100644 --- a/src/main/java/fr/openmc/core/registry/regions/CustomRegionRegistry.java +++ b/src/main/java/fr/openmc/core/registry/regions/CustomRegionRegistry.java @@ -1,8 +1,12 @@ package fr.openmc.core.registry.regions; +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.bootstrap.integration.OMCLogger; import fr.openmc.core.bootstrap.registries.KeyedRegistry; import fr.openmc.core.bootstrap.registries.Registry; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; import fr.openmc.core.registry.regions.content.ExampleRegion; +import fr.openmc.core.registry.regions.preset.SquareRegion; import net.kyori.adventure.key.Key; import org.bukkit.Location; @@ -15,6 +19,115 @@ public class CustomRegionRegistry extends Registry public final ExampleRegion EXAMPLE_REGION = register(new ExampleRegion()); + //Terror House Floor + + private final int MIN_X = -91; + private final int MAX_X = -22; + private final int MIN_Z = -94; + private final int MAX_Z = -28; + + public final SquareRegion FLOOR_1 = register(new SquareRegion( + "floor_1", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -60, MIN_Z), + BlockVector3.at(MAX_X, -53, MAX_Z) + )); + + public final SquareRegion FLOOR_2 = register(new SquareRegion( + "floor_2", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -52, MIN_Z), + BlockVector3.at(MAX_X, -44, MAX_Z) + )); + + public final SquareRegion FLOOR_3 = register(new SquareRegion( + "floor_3", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -44, MIN_Z), + BlockVector3.at(MAX_X, -36, MAX_Z) + )); + + public final SquareRegion FLOOR_4 = register(new SquareRegion( + "floor_4", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -36, MIN_Z), + BlockVector3.at(MAX_X, -28, MAX_Z) + )); + + public final SquareRegion FLOOR_5 = register(new SquareRegion( + "floor_5", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -28, MIN_Z), + BlockVector3.at(MAX_X, -20, MAX_Z) + )); + + public final SquareRegion FLOOR_6 = register(new SquareRegion( + "floor_6", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -20, MIN_Z), + BlockVector3.at(MAX_X, -12, MAX_Z) + )); + + public final SquareRegion FLOOR_7 = register(new SquareRegion( + "floor_7", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -12, MIN_Z), + BlockVector3.at(MAX_X, -4, MAX_Z) + )); + + public final SquareRegion FLOOR_8 = register(new SquareRegion( + "floor_8", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, -4, MIN_Z), + BlockVector3.at(MAX_X, 4, MAX_Z) + )); + + public final SquareRegion FLOOR_9 = register(new SquareRegion( + "floor_9", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 4, MIN_Z), + BlockVector3.at(MAX_X, 12, MAX_Z) + )); + + public final SquareRegion FLOOR_10 = register(new SquareRegion( + "floor_10", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 12, MIN_Z), + BlockVector3.at(MAX_X, 20, MAX_Z) + )); + + public final SquareRegion FLOOR_11 = register(new SquareRegion( + "floor_11", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 20, MIN_Z), + BlockVector3.at(MAX_X, 27, MAX_Z) + )); + public final SquareRegion FLOOR_12 = register(new SquareRegion( + "floor_12", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 28, MIN_Z), + BlockVector3.at(MAX_X, 36, MAX_Z) + )); + public final SquareRegion FLOOR_13 = register(new SquareRegion( + "floor_13", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 36, MIN_Z), + BlockVector3.at(MAX_X, 44, MAX_Z) + )); + public final SquareRegion FLOOR_14 = register(new SquareRegion( + "floor_14", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 45, MIN_Z), + BlockVector3.at(MAX_X, 55, MAX_Z) + )); + + public final SquareRegion FLOOR_15 = register(new SquareRegion( + "floor_15", + DimensionGenerator.DIMENSION_NAME, + BlockVector3.at(MIN_X, 53, MIN_Z), + BlockVector3.at(MAX_X, 68, MAX_Z) + )); + @Override public Key key(CustomRegion registryObject) { return registryObject.getKey(); diff --git a/src/main/java/fr/openmc/core/registry/regions/content/ExampleRegion.java b/src/main/java/fr/openmc/core/registry/regions/content/ExampleRegion.java index 5d2322faf..0f84dd937 100644 --- a/src/main/java/fr/openmc/core/registry/regions/content/ExampleRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/content/ExampleRegion.java @@ -25,4 +25,9 @@ public BlockVector3 getPos1() { public BlockVector3 getPos2() { return null; } + + @Override + public BlockVector3 getCenter() { + return null; + } } diff --git a/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java b/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java new file mode 100644 index 000000000..083bf129b --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java @@ -0,0 +1,77 @@ +package fr.openmc.core.registry.regions.preset; + +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.registry.regions.CustomRegion; +import lombok.Getter; +import net.kyori.adventure.key.Key; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.World; + +public class SquareRegion extends CustomRegion { + + public String world; + public BlockVector3 pos1; + public BlockVector3 pos2; + + @Getter + public BlockVector3 min; + + @Getter + public BlockVector3 max; + + public Key key; + + public SquareRegion(String key, String world, BlockVector3 pos1, BlockVector3 pos2) { + this.world = world; + min = pos1.getMinimum(pos2); + max = pos1.getMaximum(pos2); + this.pos1 = pos1; + this.pos2 = pos2; + this.key = new NamespacedKey("openmc_custom_region", key).key(); + } + + @Override + public Key getKey() { + return key; + } + + @Override + public World getWorld() { + return Bukkit.getWorld(world); + } + + @Override + public boolean contains(BlockVector3 pos) { + double x = pos.x(); + double y = pos.y(); + double z = pos.z(); + + return x >= getMin().x() && + x <= getMax().x() && + y >= getMin().y() && + y <= getMax().y() && + z >= getMin().z() && + z <= getMax().z(); + } + + @Override + public BlockVector3 getPos1() { + return pos1; + } + + @Override + public BlockVector3 getPos2() { + return pos2; + } + + @Override + public BlockVector3 getCenter() { + return BlockVector3.at( + (min.x() - max.x()/2), + (min.y() - max.y()/2), + (min.z() - max.z()/2) + ); + } +} diff --git a/src/main/java/fr/openmc/core/registry/regions/types/SphericalRegion.java b/src/main/java/fr/openmc/core/registry/regions/types/SphericalRegion.java index cab10eea8..cdab13b4f 100644 --- a/src/main/java/fr/openmc/core/registry/regions/types/SphericalRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/types/SphericalRegion.java @@ -5,8 +5,6 @@ public abstract class SphericalRegion extends CustomRegion { - public abstract BlockVector3 getCenter(); - public abstract double getRadius(); @Override diff --git a/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java new file mode 100644 index 000000000..aa465d21e --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java @@ -0,0 +1,247 @@ +package fr.openmc.core.registry.structures; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.session.ClipboardHolder; +import fr.openmc.core.registry.structures.model.CustomStructureManager; +import fr.openmc.core.registry.structures.model.DBPlacedStructure; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.structure.Structure; +import org.bukkit.util.BlockVector; +import org.jetbrains.annotations.NotNull; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.UUID; + +/** + * Represents a reusable structure that can be placed multiple times. + * All public methods must be called on the server's main thread. + */ +public class CustomStructure { + + private static final ClipboardFormat BACKUP_FORMAT = BuiltInClipboardFormat.SPONGE_V3_SCHEMATIC; + + @Getter + private final String id; + private final File file; + + public CustomStructure(String id, File file) { + this.id = id; + this.file = file; + } + + /** + * Places this structure and generates a unique ID for the placement. + */ + public UUID place(Location location) throws Exception { + return place(UUID.randomUUID(), location); + } + + /** + * Places this structure using the provided placement ID. + * An ID that already exists in the database is rejected. + */ + public UUID place(UUID placementId, Location location) throws Exception { + requireMainThread(); + + if (!CustomStructureManager.actionAllow()) { + throw new IllegalStateException("WorldEdit or FastAsyncWorldEdit is not enabled."); + } + if (placementId == null || location == null || location.getWorld() == null) { + throw new IllegalArgumentException("Placement ID, location and world must not be null."); + } + if (CustomStructureManager.existsPlacement(placementId)) { + throw new IllegalStateException("A structure placement with ID " + placementId + " already exists."); + } + + Clipboard structure = readStructure(file); + World world = location.getWorld(); + BlockVector3 target = BukkitAdapter.asBlockVector(location); + BlockVector3 offset = target.subtract(structure.getOrigin()); + BlockVector3 min = structure.getRegion().getMinimumPoint().add(offset); + BlockVector3 max = structure.getRegion().getMaximumPoint().add(offset); + + com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world); + CuboidRegion affectedRegion = new CuboidRegion(weWorld, min, max); + byte[] backupData; + + try (EditSession session = WorldEdit.getInstance().newEditSession(weWorld)) { + BlockArrayClipboard backup = new BlockArrayClipboard(affectedRegion); + backup.setOrigin(min); + + ForwardExtentCopy copy = new ForwardExtentCopy(session, affectedRegion, backup, min); + copy.setCopyingEntities(false); + Operations.complete(copy); + + backupData = serialize(backup); + + Operations.complete(new ClipboardHolder(structure) + .createPaste(session) + .to(target) + .ignoreAirBlocks(false) + .build()); + } + + DBPlacedStructure placement = new DBPlacedStructure( + placementId, + id, + world.getUID().toString(), + min.x(), + min.y(), + min.z(), + backupData + ); + + try { + CustomStructureManager.savePlacement(placement); + } catch (Exception exception) { + // Roll back the paste if the placement could not be recorded. + restoreBackup(world, min, backupData); + throw exception; + } + + return placementId; + } + + /** + * Restores the blocks that were present before the specified placement. + * + * @return true if a placement was found and restored, otherwise false + */ + public boolean remove(UUID placementId) throws Exception { + requireMainThread(); + + if (!CustomStructureManager.actionAllow()) { + throw new IllegalStateException("WorldEdit or FastAsyncWorldEdit is not enabled."); + } + + DBPlacedStructure placement = CustomStructureManager.getPlacement(placementId); + if (placement == null || !id.equals(placement.getStructureId())) { + return false; + } + + World world = Bukkit.getWorld(UUID.fromString(placement.getWorld())); + if (world == null) { + throw new IllegalStateException("World not found: " + placement.getWorld()); + } + + BlockVector3 min = BlockVector3.at(placement.getX(), placement.getY(), placement.getZ()); + restoreBackup(world, min, placement.getBackup()); + CustomStructureManager.deletePlacement(placementId); + return true; + } + + private void restoreBackup(World world, BlockVector3 min, byte[] data) throws Exception { + Clipboard backup = deserialize(data); + try (EditSession session = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) { + Operations.complete(new ClipboardHolder(backup) + .createPaste(session) + .to(min) + .ignoreAirBlocks(false) + .build()); + } + } + + private static Clipboard readStructure(File file) throws IOException { + if (file == null || !file.isFile()) { + throw new IOException("Structure file not found: " + file); + } + + if (file.getName().toLowerCase().endsWith(".nbt")) { + return readNbt(file); + } + + ClipboardFormat format = ClipboardFormats.findByFile(file); + if (format == null) { + throw new IOException("Unsupported structure format: " + file.getName()); + } + + try (FileInputStream input = new FileInputStream(file); + ClipboardReader reader = format.getReader(input)) { + return reader.read(); + } + } + + /** + * Converts a vanilla structure-block NBT file into a WorldEdit clipboard. + * This basic conversion copies block data only, not entities or block-entity contents. + */ + private static Clipboard readNbt(File file) throws IOException { + Structure structure = Bukkit.getStructureManager().loadStructure(file); + BlockArrayClipboard clipboard = getBlockArrayClipboard(file, structure); + + try { + for (BlockState state : structure.getPalettes().getFirst().getBlocks()) { + BlockVector3 position = BlockVector3.at(state.getX(), state.getY(), state.getZ()); + clipboard.setBlock(position, BukkitAdapter.adapt(state.getBlockData())); + } + } catch (Exception exception) { + throw new IOException("Could not convert NBT structure: " + file.getName(), exception); + } + + return clipboard; + } + + private static @NotNull BlockArrayClipboard getBlockArrayClipboard(File file, Structure structure) throws IOException { + if (structure.getPaletteCount() == 0) { + throw new IOException("Structure is empty: " + file.getName()); + } + + BlockVector size = structure.getSize(); + BlockVector3 min = BlockVector3.ZERO; + BlockVector3 max = BlockVector3.at( + size.getBlockX() - 1, + size.getBlockY() - 1, + size.getBlockZ() - 1 + ); + + BlockArrayClipboard clipboard = new BlockArrayClipboard(new CuboidRegion(min, max)); + clipboard.setOrigin(BlockVector3.ZERO); + return clipboard; + } + + private static byte[] serialize(Clipboard clipboard) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (ClipboardWriter writer = BACKUP_FORMAT.getWriter(output)) { + writer.write(clipboard); + } + return output.toByteArray(); + } + + private static Clipboard deserialize(byte[] data) throws IOException { + if (data == null || data.length == 0) { + throw new IOException("The placement backup is empty."); + } + + try (ByteArrayInputStream input = new ByteArrayInputStream(data); + ClipboardReader reader = BACKUP_FORMAT.getReader(input)) { + return reader.read(); + } + } + + private static void requireMainThread() { + if (!Bukkit.isPrimaryThread()) { + throw new IllegalStateException("CustomStructure methods must be called on the server main thread."); + } + } +} diff --git a/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java new file mode 100644 index 000000000..2d3559544 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java @@ -0,0 +1,39 @@ +package fr.openmc.core.registry.structures; + +import fr.openmc.core.bootstrap.features.types.LoadIfEnable; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; +import fr.openmc.core.bootstrap.registries.Registry; +import fr.openmc.core.hooks.WorldEditHook; + +import java.io.File; + +import static fr.openmc.core.registry.structures.model.CustomStructureManager.STRUCTURE_FOLDER; + +public class CustomStructureRegistry extends Registry + implements KeyedRegistry, LoadIfEnable { + + public static final String STRUCTURE_KEY = "omc_structure"; + + public final CustomStructure WITCH_SHOP = register("test", "pillar.nbt"); + public final CustomStructure TERROR_HOUSE = register("terror house", "Terrorhouse.schem"); + + @Override + public String key(CustomStructure structure) { + return structure.getId(); + } + + public CustomStructure register(String name, String fileName) { + return register(name, new File(STRUCTURE_FOLDER, fileName)); + } + + public CustomStructure register(String name, File file) { + if (name == null || file == null) { + throw new IllegalArgumentException("Structure name and file must not be null."); + } + if (!file.isFile()) { + throw new IllegalArgumentException("Structure file not found: " + file.getAbsolutePath()); + } + + return KeyedRegistry.super.register(new CustomStructure(STRUCTURE_KEY + name, file)); + } +} diff --git a/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java new file mode 100644 index 000000000..fb5d0b1fa --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java @@ -0,0 +1,85 @@ +package fr.openmc.core.registry.structures.model; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.features.Feature; +import fr.openmc.core.bootstrap.features.types.HasDatabase; +import fr.openmc.core.bootstrap.features.types.LoadIfEnable; +import fr.openmc.core.hooks.WorldEditHook; +import fr.openmc.core.utils.file.CustomCopyOption; +import fr.openmc.core.utils.file.FilesUtils; + +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +/** + * Provides simple synchronous database access for placed structures. + */ +public class CustomStructureManager extends Feature implements + LoadIfEnable, HasDatabase { + + private static Dao dao; + + public static final File STRUCTURE_FOLDER = + new File(OMCPlugin.getInstance().getDataFolder(), "data/omc_structure"); + + @Override + public void init() { + try { + FilesUtils.copyResourceFolder("data/omc_structure", STRUCTURE_FOLDER, CustomCopyOption.SKIP_EXISTING); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void initDB(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTableIfNotExists(connectionSource, DBPlacedStructure.class); + dao = DaoManager.createDao(connectionSource, DBPlacedStructure.class); + } + + public static void savePlacement(DBPlacedStructure placement) throws SQLException { + requireInitialized(); + dao.create(placement); + } + + public static DBPlacedStructure getPlacement(UUID id) throws SQLException { + requireInitialized(); + return dao.queryForId(id); + } + + public static boolean existsPlacement(UUID id) throws SQLException { + requireInitialized(); + return dao.idExists(id); + } + + public static List getPlacements(String structureId) throws SQLException { + requireInitialized(); + return dao.queryBuilder() + .orderBy("createdAt", false) + .where() + .eq("structureId", structureId) + .query(); + } + + public static void deletePlacement(UUID id) throws SQLException { + requireInitialized(); + dao.deleteById(id); + } + + public static boolean actionAllow() { + return WorldEditHook.isEnable(); + } + + private static void requireInitialized() { + if (dao == null) { + throw new IllegalStateException("CustomStructureManager database has not been initialized."); + } + } +} diff --git a/src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java b/src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java new file mode 100644 index 000000000..73814e403 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java @@ -0,0 +1,57 @@ +package fr.openmc.core.registry.structures.model; + +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; + +import java.util.UUID; + +/** + * Stores one placed structure and the blocks that were there before it was placed. + */ +@Getter +@DatabaseTable(tableName = "structures_placed") +public class DBPlacedStructure { + + @DatabaseField(id = true, dataType = DataType.UUID) + private UUID id; + + @DatabaseField(canBeNull = false) + private String structureId; + + @DatabaseField(canBeNull = false) + private String world; + + @DatabaseField + private int x; + + @DatabaseField + private int y; + + @DatabaseField + private int z; + + @DatabaseField(dataType = DataType.BYTE_ARRAY, canBeNull = false) + private byte[] backup; + + @DatabaseField + private long createdAt; + + public DBPlacedStructure() { + // Required by ORMLite. + } + + public DBPlacedStructure(UUID id, String structureId, String world, + int x, int y, int z, byte[] backup) { + this.id = id; + this.structureId = structureId; + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.backup = backup; + this.createdAt = System.currentTimeMillis(); + } + +} diff --git a/src/main/java/fr/openmc/core/utils/EnumUtils.java b/src/main/java/fr/openmc/core/utils/EnumUtils.java index 87bab40b3..ea8633a26 100644 --- a/src/main/java/fr/openmc/core/utils/EnumUtils.java +++ b/src/main/java/fr/openmc/core/utils/EnumUtils.java @@ -1,6 +1,10 @@ package fr.openmc.core.utils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; public class EnumUtils { /** @@ -32,4 +36,62 @@ public static > T match(String key, Class enumClass, T defa return defaultValue; } } + + /** + * Récupère toutes les valeurs de l'enum situées avant la valeur indiquée. + * + * @param value la valeur de référence de l'enum + * @param le type de l'enum + * @return une liste contenant les valeurs précédant la valeur indiquée + */ + public static > List getValuesBefore(T value, boolean withIt) { + return Arrays.stream(value.getDeclaringClass().getEnumConstants()) + .filter(e -> withIt + ? e.ordinal() <= value.ordinal() + : e.ordinal() < value.ordinal()) + .collect(Collectors.toCollection(ArrayList::new)); + } + + /** + * Récupère toutes les valeurs de l'enum situées après la valeur indiquée. + * + * @param value la valeur de référence de l'enum + * @param le type de l'enum + * @return une liste contenant les valeurs suivant la valeur indiquée + */ + public static > List getValuesAfter(T value, boolean withIt) { + return Arrays.stream(value.getDeclaringClass().getEnumConstants()) + .filter(e -> withIt + ? e.ordinal() >= value.ordinal() + : e.ordinal() > value.ordinal()) + .collect(Collectors.toCollection(ArrayList::new)); + } + + /** + * Récupère la valeur de l'enum située après la valeur indiquée. + * + * @param value la valeur de référence de l'enum + * @param le type de l'enum + * @return la valeur suivante, ou null si elle n'existe pas + */ + public static > T getValueAfter(T value) { + T[] values = value.getDeclaringClass().getEnumConstants(); + int index = value.ordinal() + 1; + + return index < values.length ? values[index] : null; + } + + /** + * Récupère la valeur de l'enum située avant la valeur indiquée. + * + * @param value la valeur de référence de l'enum + * @param le type de l'enum + * @return la valeur précédente, ou null si elle n'existe pas + */ + public static > T getValueBefore(T value) { + T[] values = value.getDeclaringClass().getEnumConstants(); + int index = value.ordinal() - 1; + + return index >= 0 ? values[index] : null; + } } diff --git a/src/main/java/fr/openmc/core/utils/RandomUtils.java b/src/main/java/fr/openmc/core/utils/RandomUtils.java index 38107091f..d99a311d4 100644 --- a/src/main/java/fr/openmc/core/utils/RandomUtils.java +++ b/src/main/java/fr/openmc/core/utils/RandomUtils.java @@ -1,6 +1,7 @@ package fr.openmc.core.utils; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.ThreadLocalRandom; @@ -48,4 +49,24 @@ public static List generateRandomOrder(List inital) { Collections.shuffle(shuffle); return shuffle; } + + /** + * Prends une liste initial et retourne une entrée de celle-ci. + * @param list la liste initial + * @return l'entrée aléatoirement choisie + */ + public static T getRandomObjectFromList(List list) { + return list.get(ThreadLocalRandom.current().nextInt(list.size())); + } + + /** + * Sélectionne et retourne un objet choisi aléatoirement parmi ceux fournis. + * + * @param objects les objets parmi lesquels effectuer la sélection + * @return un objet choisi aléatoirement + */ + @SafeVarargs + public static T getRandomObject(T... objects) { + return getRandomObjectFromList(Arrays.stream(objects).toList()); + } } \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/utils/file/CustomCopyOption.java b/src/main/java/fr/openmc/core/utils/file/CustomCopyOption.java new file mode 100644 index 000000000..471e2e5f5 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/file/CustomCopyOption.java @@ -0,0 +1,11 @@ +package fr.openmc.core.utils.file; + +import java.nio.file.CopyOption; + +public enum CustomCopyOption implements CopyOption { + /** + * Copy and paste a file if it not exists. + */ + SKIP_EXISTING, +} + diff --git a/src/main/java/fr/openmc/core/utils/FilesUtils.java b/src/main/java/fr/openmc/core/utils/file/FilesUtils.java similarity index 87% rename from src/main/java/fr/openmc/core/utils/FilesUtils.java rename to src/main/java/fr/openmc/core/utils/file/FilesUtils.java index 91196c17a..d43285d14 100644 --- a/src/main/java/fr/openmc/core/utils/FilesUtils.java +++ b/src/main/java/fr/openmc/core/utils/file/FilesUtils.java @@ -1,4 +1,4 @@ -package fr.openmc.core.utils; +package fr.openmc.core.utils.file; import fr.openmc.core.OMCBootstrap; import fr.openmc.core.bootstrap.integration.OMCLogger; @@ -9,10 +9,7 @@ import java.net.JarURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.nio.file.*; import java.util.*; import java.util.function.Function; import java.util.jar.JarEntry; @@ -240,7 +237,31 @@ public static List listFileNamesInResource(String resourcePath) { * @throws IOException Si une erreur survient lors de la copie */ public static void copyResourceFolder(String sourcePath, File destDir) throws IOException { - copyResourceFolder(sourcePath, destDir, null); + copyResourceFolder(sourcePath, destDir, null, java.nio.file.StandardCopyOption.REPLACE_EXISTING); + } + + /** + * Copie un dossier depuis les ressources vers le système de fichiers + * + * @param sourcePath Chemin dans les ressources (ex: "contents/omc_items") + * @param destDir Dossier destination + * @param copyOption L'option de copiage + * @throws IOException Si une erreur survient lors de la copie + */ + public static void copyResourceFolder(String sourcePath, File destDir, CopyOption copyOption) throws IOException { + copyResourceFolder(sourcePath, destDir, null, copyOption); + } + + /** + * Copie un dossier depuis les ressources vers le système de fichiers + * + * @param sourcePath Chemin dans les ressources (ex: "contents/omc_items") + * @param destDir Dossier destination + * @param textTransformer transformeur appliqué aux fichiers texte (peut être null). + * @throws IOException Si une erreur survient lors de la copie + */ + public static void copyResourceFolder(String sourcePath, File destDir, Function textTransformer) throws IOException { + copyResourceFolder(sourcePath, destDir, textTransformer, java.nio.file.StandardCopyOption.REPLACE_EXISTING); } /** @@ -249,10 +270,12 @@ public static void copyResourceFolder(String sourcePath, File destDir) throws IO * @param sourcePath Chemin dans les ressources (ex: "contents/omc_items"). * @param destDir Dossier destination. * @param textTransformer transformeur appliqué aux fichiers texte (peut être null). + * @param copyOption L'option de copiage * @throws IOException Si une erreur survient lors de la copie. */ public static void copyResourceFolder(String sourcePath, File destDir, - Function textTransformer) throws IOException { + Function textTransformer, + CopyOption copyOption) throws IOException { try { Enumeration resources = CLASS_LOADER.getResources(sourcePath); @@ -278,7 +301,14 @@ public static void copyResourceFolder(String sourcePath, File destDir, } } - Files.copy(sourceFile, destFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + if (copyOption == CustomCopyOption.SKIP_EXISTING + && Files.exists(destFile.toPath())) return; + + Files.copy(sourceFile, destFile.toPath(), + copyOption instanceof CustomCopyOption ? + java.nio.file.StandardCopyOption.REPLACE_EXISTING + : copyOption + ); if (textTransformer != null) { transformTextFile(destFile, textTransformer); } @@ -319,9 +349,17 @@ public static void copyResourceFolder(String sourcePath, File destDir, } } + if (copyOption == CustomCopyOption.SKIP_EXISTING + && Files.exists(destFile.toPath())) { + continue; + } + // * Copie le fichier try (InputStream in = jar.getInputStream(entry)) { - Files.copy(in, destFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING); + Files.copy(in, destFile.toPath(), copyOption instanceof CustomCopyOption ? + java.nio.file.StandardCopyOption.REPLACE_EXISTING + : copyOption + ); if (textTransformer != null) { transformTextFile(destFile, textTransformer); } diff --git a/src/main/java/fr/openmc/core/utils/text/messages/Prefix.java b/src/main/java/fr/openmc/core/utils/text/messages/Prefix.java index bf240ee3b..ee8651e4e 100644 --- a/src/main/java/fr/openmc/core/utils/text/messages/Prefix.java +++ b/src/main/java/fr/openmc/core/utils/text/messages/Prefix.java @@ -37,7 +37,8 @@ public enum Prefix { HALLOWEEN("halloween"), DIMOPENER("dimopener"), GOLDEN_HARVEST("golden harvest"), - MIRACULOUS_FISHING("miraculous fishing"); + MIRACULOUS_FISHING("miraculous fishing"), + LUCKYBLOCK("luckyblock"); @Getter private final Component prefix; diff --git a/src/main/java/fr/openmc/core/utils/types/MultiResourceBundle.java b/src/main/java/fr/openmc/core/utils/types/MultiResourceBundle.java index ef89fefe0..b40e5f325 100644 --- a/src/main/java/fr/openmc/core/utils/types/MultiResourceBundle.java +++ b/src/main/java/fr/openmc/core/utils/types/MultiResourceBundle.java @@ -1,6 +1,6 @@ package fr.openmc.core.utils.types; -import fr.openmc.core.utils.FilesUtils; +import fr.openmc.core.utils.file.FilesUtils; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/fr/openmc/core/utils/world/LocationUtils.java b/src/main/java/fr/openmc/core/utils/world/LocationUtils.java index e2d064931..2fee5b172 100644 --- a/src/main/java/fr/openmc/core/utils/world/LocationUtils.java +++ b/src/main/java/fr/openmc/core/utils/world/LocationUtils.java @@ -1,5 +1,6 @@ package fr.openmc.core.utils.world; +import com.sk89q.worldedit.math.BlockVector3; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -118,4 +119,8 @@ public static boolean isSameLocation(Location a, Location b) { && a.getBlockY() == b.getBlockY() && a.getBlockZ() == b.getBlockZ(); } + + public static Location fromVector(World world, BlockVector3 blockVector3) { + return new Location(world, blockVector3.x(), blockVector3.y(), blockVector3.z()); + } } diff --git a/src/main/resources/contents/omc_halloween/configs/fonts.yml b/src/main/resources/contents/omc_halloween/configs/fonts.yml new file mode 100644 index 000000000..e17c69365 --- /dev/null +++ b/src/main/resources/contents/omc_halloween/configs/fonts.yml @@ -0,0 +1,33 @@ +info: + namespace: omc_halloween +font_images: + candy_red: + permission: candy_red + show_in_gui: true + path: "candy/candy_red.png" + scale_ratio: 12 + y_position: 9 + candy_yellow: + permission: candy_yellow + show_in_gui: true + path: "candy/candy_yellow.png" + scale_ratio: 12 + y_position: 9 + candy_green: + permission: candy_green + show_in_gui: true + path: "candy/candy_green.png" + scale_ratio: 12 + y_position: 9 + candy_blue: + permission: candy_blue + show_in_gui: true + path: "candy/candy_blue.png" + scale_ratio: 12 + y_position: 9 + candy_brown: + permission: candy_brown + show_in_gui: true + path: "candy/candy_brown.png" + scale_ratio: 12 + y_position: 9 \ No newline at end of file diff --git a/src/main/resources/contents/omc_halloween/configs/items.yml b/src/main/resources/contents/omc_halloween/configs/items.yml new file mode 100644 index 000000000..7bde90dba --- /dev/null +++ b/src/main/resources/contents/omc_halloween/configs/items.yml @@ -0,0 +1,148 @@ +info: + namespace: omc_halloween + +items: + candy_red: + display_name: + resource: + generate: true + textures: + - candy/candy_red + material: PAPER + lore: + - + consumable: + nutrition: 1 + saturation: 0.6 + + candy_yellow: + display_name: + resource: + generate: true + textures: + - candy/candy_yellow + material: PAPER + lore: + - + consumable: + nutrition: 1 + saturation: 0.6 + + candy_green: + display_name: + resource: + generate: true + textures: + - candy/candy_green + material: PAPER + lore: + - + consumable: + nutrition: 1 + saturation: 0.6 + + candy_blue: + display_name: + resource: + generate: true + textures: + - candy/candy_blue + material: PAPER + lore: + - + consumable: + nutrition: 1 + saturation: 0.6 + + candy_brown: + display_name: + resource: + generate: true + textures: + - candy/candy_brown + material: PAPER + lore: + - + components_nbt_file: "nbt/candy_brown_nbt.json" # marche pas j'ai pas la volonté de chercher + consumable: + nutrition: 1 + saturation: 0.6 + + peluche_root_halloween_2026: + display_name: + resource: + material: PAPER + model_path: root_plush + behaviours: + furniture: + entity: item_display + display_transformation: + transform: HEAD + right_rotation: + axis_angle: + angle: 180 + axis: + x: 0 + y: 1 + z: 0 + translation: + x: 0 + y: -0.3 + z: 0 + scale: + x: 0.8 + y: 0.8 + z: 0.8 + +recipes: + crafting_table: + candy_red: + enabled: true + pattern: + - BRB + - RBR + - BRB + ingredients: + R: RED_DYE + B: omc_halloween:candy_blue + result: + item: omc_halloween:candy_red + amount: 1 + candy_blue: + enabled: true + pattern: + - GBG + - BGB + - GBG + ingredients: + G: omc_halloween:candy_green + B: BLUE_DYE + result: + item: omc_halloween:candy_blue + amount: 1 + candy_green: + enabled: true + pattern: + - MGM + - GMG + - MGM + ingredients: + M: omc_halloween:candy_brown + G: LIME_DYE + result: + item: omc_halloween:candy_green + amount: 1 + candy_brown: + enabled: true + pattern: + - BSR + - SES + - RSB + ingredients: + B: BONE + R: ROTTEN_FLESH + S: SUGAR + E: SPIDER_EYE + result: + item: omc_halloween:candy_brown + amount: 3 \ No newline at end of file diff --git a/src/main/resources/contents/omc_halloween/models/root_plush.json b/src/main/resources/contents/omc_halloween/models/root_plush.json new file mode 100644 index 000000000..3ed965538 --- /dev/null +++ b/src/main/resources/contents/omc_halloween/models/root_plush.json @@ -0,0 +1,327 @@ +{ + "format_version": "1.21.11", + "credit": "Made by Gex and rework by Nocolm", + "texture_size": [64, 64], + "textures": { + "2": "omc_halloween:models/root_halloween_plush_texture", + "particle": "omc_halloween:models/root_halloween_plush_texture" + }, + "elements": [ + { + "name": "body", + "from": [4.5, 1, 7], + "to": [11.5, 8, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [9.5, 4, 10]}, + "faces": { + "north": {"uv": [2.25, 4.5, 4, 6.25], "texture": "#2"}, + "east": {"uv": [4, 4.5, 5.25, 6.25], "texture": "#2"}, + "south": {"uv": [4.5, 2.25, 6.25, 4], "texture": "#2"}, + "west": {"uv": [5.25, 4, 6.5, 5.75], "texture": "#2"}, + "up": {"uv": [7, 7, 5.25, 5.75], "texture": "#2"}, + "down": {"uv": [4, 6.25, 2.25, 7.5], "texture": "#2"} + } + }, + { + "name": "head", + "from": [3.5, 8, 5], + "to": [4.5, 15, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [2, 0.5, 2.25, 2.25], "texture": "#2"}, + "east": {"uv": [0.25, 2.75, 2.25, 4.5], "texture": "#2"}, + "south": {"uv": [2.25, 0.5, 2.5, 2.25], "texture": "#2"}, + "west": {"uv": [2.25, 2.75, 4.25, 4.5], "texture": "#2"}, + "up": {"uv": [2.25, 6.75, 2, 4.75], "texture": "#2"}, + "down": {"uv": [6.75, 0.25, 6.5, 2.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [3.5, 15, 5], + "to": [4.5, 16, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [2, 0.25, 2.25, 0.5], "texture": "#2"}, + "east": {"uv": [0.5, 2.5, 2.25, 2.75], "texture": "#2"}, + "south": {"uv": [2.25, 0.25, 2.5, 0.5], "texture": "#2"}, + "west": {"uv": [2.25, 2.5, 4, 2.75], "texture": "#2"}, + "up": {"uv": [2.25, 6.75, 2, 5], "texture": "#2"}, + "down": {"uv": [6.75, 0.5, 6.5, 2.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [3.5, 16, 5], + "to": [4.5, 16, 12], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [2, 0.25, 2.25, 0.25], "texture": "#2"}, + "east": {"uv": [0.5, 2.5, 2.25, 2.5], "texture": "#2"}, + "south": {"uv": [2.25, 0.25, 2.5, 0.25], "texture": "#2"}, + "west": {"uv": [2.25, 2.5, 4, 2.5], "texture": "#2"}, + "up": {"uv": [2.25, 6.75, 2, 5], "texture": "#2"}, + "down": {"uv": [6.75, 0.5, 6.5, 2.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [3.5, 16, 5], + "to": [4.5, 17, 11], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [2, 0, 2.25, 0.25], "texture": "#2"}, + "east": {"uv": [0.75, 2.25, 2.25, 2.5], "texture": "#2"}, + "south": {"uv": [2.25, 0, 2.5, 0.25], "texture": "#2"}, + "west": {"uv": [2.25, 2.25, 3.75, 2.5], "texture": "#2"}, + "up": {"uv": [2.25, 6.75, 2, 5.25], "texture": "#2"}, + "down": {"uv": [6.75, 0.75, 6.5, 2.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [4.5, 8, 5], + "to": [12.5, 17, 13], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [0, 0, 2, 2.25], "texture": "#2"}, + "east": {"uv": [0.25, 2.25, 2.25, 4.5], "texture": "#2"}, + "south": {"uv": [2.5, 0, 4.5, 2.25], "texture": "#2"}, + "west": {"uv": [2.25, 2.25, 4.25, 4.5], "texture": "#2"}, + "up": {"uv": [2, 6.75, 0, 4.75], "texture": "#2"}, + "down": {"uv": [6.5, 0.25, 4.5, 2.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [3.5, 8, 13], + "to": [3.5, 15, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [2.25, 0.5, 2.25, 2.25], "texture": "#2"}, + "east": {"uv": [0, 2.75, 0.25, 4.5], "texture": "#2"}, + "south": {"uv": [2.25, 0.5, 2.25, 2.25], "texture": "#2"}, + "west": {"uv": [4.25, 2.75, 4.5, 4.5], "texture": "#2"}, + "up": {"uv": [2.25, 4.75, 2.25, 4.5], "texture": "#2"}, + "down": {"uv": [6.75, 0, 6.75, 0.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [3.5, 8, 13], + "to": [4.5, 15, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [2, 0.5, 2.25, 2.25], "texture": "#2"}, + "east": {"uv": [0, 2.75, 0.25, 4.5], "texture": "#2"}, + "south": {"uv": [2.25, 0.5, 2.5, 2.25], "texture": "#2"}, + "west": {"uv": [4.25, 2.75, 4.5, 4.5], "texture": "#2"}, + "up": {"uv": [2.25, 4.75, 2, 4.5], "texture": "#2"}, + "down": {"uv": [6.75, 0, 6.5, 0.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [4.5, 8, 13], + "to": [12.5, 16, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [0, 0.25, 2, 2.25], "texture": "#2"}, + "east": {"uv": [0, 2.5, 0.25, 4.5], "texture": "#2"}, + "south": {"uv": [2.5, 0.25, 4.5, 2.25], "texture": "#2"}, + "west": {"uv": [4.25, 2.5, 4.5, 4.5], "texture": "#2"}, + "up": {"uv": [2, 4.75, 0, 4.5], "texture": "#2"}, + "down": {"uv": [6.5, 0, 4.5, 0.25], "texture": "#2"} + } + }, + { + "name": "head", + "from": [5.5, 16, 13], + "to": [12.5, 17, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [12, 9, 8]}, + "faces": { + "north": {"uv": [0, 0, 1.75, 0.25], "texture": "#2"}, + "east": {"uv": [0, 2.25, 0.25, 2.5], "texture": "#2"}, + "south": {"uv": [2.75, 0, 4.5, 0.25], "texture": "#2"}, + "west": {"uv": [4.25, 2.25, 4.5, 2.5], "texture": "#2"}, + "up": {"uv": [1.75, 4.75, 0, 4.5], "texture": "#2"}, + "down": {"uv": [6.25, 0, 4.5, 0.25], "texture": "#2"} + } + }, + { + "name": "left eye", + "from": [4, 11.75, 4.75], + "to": [7.5, 15.25, 6.25], + "faces": { + "north": {"uv": [14, 1, 15, 2], "texture": "#2"}, + "east": {"uv": [13.5, 1, 14, 2], "texture": "#2"}, + "south": {"uv": [12.5, 1, 13.5, 2], "texture": "#2"}, + "west": {"uv": [15, 1, 15.5, 2], "texture": "#2"}, + "up": {"uv": [15, 1, 14, 0.5], "texture": "#2"}, + "down": {"uv": [15, 2, 14, 2.5], "texture": "#2"} + } + }, + { + "name": "right eye", + "from": [8.5, 11.75, 4.75], + "to": [12, 15.25, 6.25], + "faces": { + "north": {"uv": [10, 1, 11, 2], "texture": "#2"}, + "east": {"uv": [9.5, 1, 10, 2], "texture": "#2"}, + "south": {"uv": [11.5, 1, 12.5, 2], "texture": "#2"}, + "west": {"uv": [11, 1, 11.5, 2], "texture": "#2"}, + "up": {"uv": [11, 1, 10, 0.5], "texture": "#2"}, + "down": {"uv": [11, 2, 10, 2.5], "texture": "#2"} + } + }, + { + "from": [10.8, 5, 2.5], + "to": [13.8, 8, 9.5], + "rotation": {"angle": 2.5, "axis": "y", "origin": [12.3, 5, 9.5]}, + "faces": { + "north": {"uv": [0.75, 8.5, 0, 9.25], "rotation": 90, "texture": "#2"}, + "east": {"uv": [7, 5.25, 7.75, 7], "rotation": 270, "texture": "#2"}, + "south": {"uv": [8.5, 7, 7.75, 6.25], "rotation": 90, "texture": "#2"}, + "west": {"uv": [6.75, 7, 7.5, 8.75], "rotation": 90, "texture": "#2"}, + "up": {"uv": [6, 7, 6.75, 8.75], "rotation": 180, "texture": "#2"}, + "down": {"uv": [6, 7, 6.75, 8.75], "texture": "#2"} + } + }, + { + "from": [10.55, 4.75, 2.25], + "to": [14.05, 8.25, 5.75], + "rotation": {"angle": 2.5, "axis": "y", "origin": [12.3, 5, 9.5]}, + "faces": { + "north": {"uv": [9, 2, 8, 3], "rotation": 90, "texture": "#2"}, + "east": {"uv": [6.75, 1, 7.75, 2], "rotation": 270, "texture": "#2"}, + "south": {"uv": [8.75, 6.25, 7.75, 5.25], "rotation": 90, "texture": "#2"}, + "west": {"uv": [7.5, 7, 8.5, 8], "rotation": 90, "texture": "#2"}, + "up": {"uv": [7.75, 1, 8.75, 2], "rotation": 180, "texture": "#2"}, + "down": {"uv": [2.75, 7.5, 3.75, 8.5], "texture": "#2"} + } + }, + { + "from": [2.2, 5, 2.5], + "to": [5.2, 8, 9.5], + "rotation": {"angle": 0, "axis": "x", "origin": [3.7, 5, 9.5]}, + "faces": { + "north": {"uv": [0, 8.5, 0.75, 9.25], "rotation": 270, "texture": "#2"}, + "east": {"uv": [6.75, 7, 7.5, 8.75], "rotation": 270, "texture": "#2"}, + "south": {"uv": [7.75, 7, 8.5, 6.25], "rotation": 270, "texture": "#2"}, + "west": {"uv": [7.75, 5.25, 7, 7], "rotation": 90, "texture": "#2"}, + "up": {"uv": [6.75, 7, 6, 8.75], "rotation": 180, "texture": "#2"}, + "down": {"uv": [2, 7.5, 2.75, 9.25], "texture": "#2"} + } + }, + { + "from": [1.95, 4.75, 2.25], + "to": [5.45, 8.25, 5.75], + "rotation": {"angle": 0, "axis": "x", "origin": [3.7, 5, 9.5]}, + "faces": { + "north": {"uv": [8, 3, 9, 2], "rotation": 270, "texture": "#2"}, + "east": {"uv": [8.5, 7, 7.5, 8], "rotation": 270, "texture": "#2"}, + "south": {"uv": [7.75, 6.25, 8.75, 5.25], "rotation": 270, "texture": "#2"}, + "west": {"uv": [7.75, 1, 6.75, 2], "rotation": 90, "texture": "#2"}, + "up": {"uv": [8.75, 1, 7.75, 2], "rotation": 180, "texture": "#2"}, + "down": {"uv": [2.75, 7.5, 3.75, 8.5], "texture": "#2"} + } + }, + { + "name": "right leg", + "from": [4, 0, 3], + "to": [8, 4, 10], + "rotation": {"angle": 20, "axis": "y", "origin": [6, 2, 10]}, + "faces": { + "north": {"uv": [3.75, 8, 4.75, 9], "texture": "#2"}, + "east": {"uv": [6.25, 2.25, 8, 3.25], "texture": "#2"}, + "south": {"uv": [7.5, 8, 8.5, 9], "texture": "#2"}, + "west": {"uv": [6.5, 3.25, 8.25, 4.25], "texture": "#2"}, + "up": {"uv": [5, 8, 4, 6.25], "texture": "#2"}, + "down": {"uv": [1, 6.75, 0, 8.5], "texture": "#2"} + } + }, + { + "name": "left leg", + "from": [8, 0, 3], + "to": [12, 4, 10], + "rotation": {"angle": -20, "axis": "y", "origin": [10, 2, 10]}, + "faces": { + "north": {"uv": [8.25, 3, 9.25, 4], "texture": "#2"}, + "east": {"uv": [6.5, 4.25, 8.25, 5.25], "texture": "#2"}, + "south": {"uv": [8.25, 4, 9.25, 5], "texture": "#2"}, + "west": {"uv": [6.75, 0, 8.5, 1], "texture": "#2"}, + "up": {"uv": [2, 8.5, 1, 6.75], "texture": "#2"}, + "down": {"uv": [6, 7, 5, 8.75], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [-180, 45, -180], + "translation": [1, 3.5, 0], + "scale": [0.3, 0.3, 0.3] + }, + "thirdperson_lefthand": { + "rotation": [-180, 45, -180], + "translation": [1, 3.5, 0], + "scale": [0.3, 0.3, 0.3] + }, + "firstperson_righthand": { + "rotation": [-180, 45, -180], + "translation": [1, 3.5, 0], + "scale": [0.5, 0.5, 0.5] + }, + "firstperson_lefthand": { + "rotation": [-180, 45, -180], + "translation": [1, 3.5, 0], + "scale": [0.5, 0.5, 0.5] + }, + "ground": { + "rotation": [30, 0, 0], + "scale": [0.4, 0.4, 0.4] + }, + "gui": { + "rotation": [-150, 30, -180], + "translation": [0, -0.5, 0], + "scale": [0.68, 0.68, 0.68] + }, + "head": { + "translation": [0, 14, 0] + }, + "fixed": { + "scale": [0.9, 0.9, 0.9] + }, + "on_shelf": { + "rotation": [0, -180, 0] + } + }, + "groups": [ + { + "name": "plush", + "origin": [19, 7, 6.5], + "color": 0, + "children": [ + 0, + { + "name": "head", + "origin": [12, 9, 5], + "color": 0, + "children": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] + }, + { + "name": "left hand", + "origin": [19, 7, 6.5], + "color": 0, + "children": [12, 13] + }, + { + "name": "right hand", + "origin": [19, 7, 6.5], + "color": 0, + "children": [14, 15] + } + ] + }, + 16, + 17 + ] +} \ No newline at end of file diff --git a/src/main/resources/contents/omc_halloween/nbt/candy_brown_nbt.json b/src/main/resources/contents/omc_halloween/nbt/candy_brown_nbt.json new file mode 100644 index 000000000..67625a570 --- /dev/null +++ b/src/main/resources/contents/omc_halloween/nbt/candy_brown_nbt.json @@ -0,0 +1,24 @@ +{ + "components": { + "minecraft:consumable": { + "on_consume_effects": [ + { + "type": "apply_effects", + "effects": [ + { + "id": "minecraft:nausea", + "duration": 500 + } + ] + } + ], + "animation": "eat", + "sound": "minecraft:entity.generic.eat" + }, + "food": { + "saturation": 2, + "nutrition": 4, + "can_always_eat": true + } + } +} \ No newline at end of file diff --git a/src/main/resources/contents/omc_halloween/textures/candy/candy_blue.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_blue.png new file mode 100644 index 000000000..be6fd4e73 Binary files /dev/null and b/src/main/resources/contents/omc_halloween/textures/candy/candy_blue.png differ diff --git a/src/main/resources/contents/omc_halloween/textures/candy/candy_brown.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_brown.png new file mode 100644 index 000000000..fcfae29a3 Binary files /dev/null and b/src/main/resources/contents/omc_halloween/textures/candy/candy_brown.png differ diff --git a/src/main/resources/contents/omc_halloween/textures/candy/candy_green.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_green.png new file mode 100644 index 000000000..acac6625f Binary files /dev/null and b/src/main/resources/contents/omc_halloween/textures/candy/candy_green.png differ diff --git a/src/main/resources/contents/omc_halloween/textures/candy/candy_red.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_red.png new file mode 100644 index 000000000..8e564fb23 Binary files /dev/null and b/src/main/resources/contents/omc_halloween/textures/candy/candy_red.png differ diff --git a/src/main/resources/contents/omc_halloween/textures/candy/candy_yellow.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_yellow.png new file mode 100644 index 000000000..55ef12b3d Binary files /dev/null and b/src/main/resources/contents/omc_halloween/textures/candy/candy_yellow.png differ diff --git a/src/main/resources/contents/omc_halloween/textures/models/root_halloween_plush_texture.png b/src/main/resources/contents/omc_halloween/textures/models/root_halloween_plush_texture.png new file mode 100644 index 000000000..ff5e91570 Binary files /dev/null and b/src/main/resources/contents/omc_halloween/textures/models/root_halloween_plush_texture.png differ diff --git a/src/main/resources/contents/omc_icons/configs/fonts.yml b/src/main/resources/contents/omc_icons/configs/fonts.yml index d72d0d785..bb30f604a 100644 --- a/src/main/resources/contents/omc_icons/configs/fonts.yml +++ b/src/main/resources/contents/omc_icons/configs/fonts.yml @@ -30,4 +30,10 @@ font_images: show_in_gui: true path: "font/bits.png" scale_ratio: 12 - y_position: 9 \ No newline at end of file + y_position: 9 + halloween_point: + permission: halloween_point + show_in_gui: true + path: "font/halloween_point.png" + scale_ratio: 12 + y_position: 9 diff --git a/src/main/resources/contents/omc_icons/textures/font/halloween_point.png b/src/main/resources/contents/omc_icons/textures/font/halloween_point.png new file mode 100644 index 000000000..6bc95b3ab Binary files /dev/null and b/src/main/resources/contents/omc_icons/textures/font/halloween_point.png differ diff --git a/src/main/resources/contents/omc_menus/configs/menus.yml b/src/main/resources/contents/omc_menus/configs/menus.yml index 6732011ac..559334752 100644 --- a/src/main/resources/contents/omc_menus/configs/menus.yml +++ b/src/main/resources/contents/omc_menus/configs/menus.yml @@ -61,6 +61,72 @@ font_images: suggestion_in_command: false path: "city_template6x9.png" y_position: 30 + halloween_event_main_menu: + permission: halloween.event_main_menu + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_festival_main_menu.png" + y_position: 30 + halloween_candy_jar_0: + permission: halloween.halloween_candy_jar_0 + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_candy_jar_0.png" + y_position: 30 + halloween_candy_jar_1: + permission: halloween.halloween_candy_jar_1 + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_candy_jar_1.png" + y_position: 30 + halloween_candy_jar_2: + permission: halloween.halloween_candy_jar_2 + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_candy_jar_2.png" + y_position: 30 + halloween_candy_jar_3: + permission: halloween.halloween_candy_jar_3 + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_candy_jar_3.png" + y_position: 30 + halloween_candy_jar_4: + permission: halloween.halloween_candy_jar_4 + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_candy_jar_4.png" + y_position: 30 + halloween_reward_menu: + permission: halloween.halloween_reward_menu + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_reward_menu.png" + y_position: 30 + halloween_deposit_menu: + permission: halloween.halloween_deposit_menu + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_deposit_menu.png" + y_position: 30 + halloween_purchase_confirm_menu: + permission: halloween.halloween_purchase_confirm_menu + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_purchase_confirm_menu.png" + y_position: 30 + halloween_store_menu: + permission: halloween.halloween_store_menu + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_store_menu.png" + y_position: 30 + halloween_choice_menu: + permission: halloween.halloween_choice_menu + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_choice_menu.png" + y_position: 30 home_mailbox: permission: mailbox.home show_in_gui: true diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_0.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_0.png new file mode 100644 index 000000000..146c75b21 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_0.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_1.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_1.png new file mode 100644 index 000000000..389b6f335 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_1.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_2.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_2.png new file mode 100644 index 000000000..8a7abd0a5 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_2.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_3.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_3.png new file mode 100644 index 000000000..538a478dd Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_3.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_4.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_4.png new file mode 100644 index 000000000..8bc59f537 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_4.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_choice_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_choice_menu.png new file mode 100644 index 000000000..016f176f6 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_choice_menu.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_deposit_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_deposit_menu.png new file mode 100644 index 000000000..7285a72f6 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_deposit_menu.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_festival_main_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_festival_main_menu.png new file mode 100644 index 000000000..dbf83e2ba Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_festival_main_menu.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_purchase_confirm_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_purchase_confirm_menu.png new file mode 100644 index 000000000..b49cdc4a5 Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_purchase_confirm_menu.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_reward_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_reward_menu.png new file mode 100644 index 000000000..703aa01df Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_reward_menu.png differ diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_store_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_store_menu.png new file mode 100644 index 000000000..ec80d9c2b Binary files /dev/null and b/src/main/resources/contents/omc_menus/textures/halloween/halloween_store_menu.png differ diff --git a/src/main/resources/data/omc_structure/TerrorHouse.schem b/src/main/resources/data/omc_structure/TerrorHouse.schem new file mode 100644 index 000000000..ed549e5bc Binary files /dev/null and b/src/main/resources/data/omc_structure/TerrorHouse.schem differ diff --git a/src/main/resources/data/omc_structure/pillar.nbt b/src/main/resources/data/omc_structure/pillar.nbt new file mode 100644 index 000000000..5d8513b7b Binary files /dev/null and b/src/main/resources/data/omc_structure/pillar.nbt differ diff --git a/src/main/resources/datapacks/omc_halloween/data/omc_halloween/dimension/witch_house.json b/src/main/resources/datapacks/omc_halloween/data/omc_halloween/dimension/witch_house.json new file mode 100644 index 000000000..25b5d79f6 --- /dev/null +++ b/src/main/resources/datapacks/omc_halloween/data/omc_halloween/dimension/witch_house.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:overworld", + "generator": { + "type": "minecraft:flat", + "settings": { + "biome": "draft:draft", + "lakes": false, + "features": false, + "layers": [] + } + } +} \ No newline at end of file diff --git a/src/main/resources/datapacks/omc_halloween/pack.mcmeta b/src/main/resources/datapacks/omc_halloween/pack.mcmeta new file mode 100644 index 000000000..a409a42ca --- /dev/null +++ b/src/main/resources/datapacks/omc_halloween/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "Le Pack de données de la Witch House d'OpenMC", + "pack_format": 107.1, + "min_format": 107.1, + "max_format": 107.1 + } +} \ No newline at end of file diff --git a/src/main/resources/translations/default/events.properties b/src/main/resources/translations/default/events.properties index 1e2b1f2a0..dc6351b63 100644 --- a/src/main/resources/translations/default/events.properties +++ b/src/main/resources/translations/default/events.properties @@ -52,3 +52,84 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>L'événement Halloween 20
<#ff6b25>Vous pouvez retrouver vos récompenses dans votre<#ff6b25> boîte aux lettres<#ff6b25>.\
<#ffd580>Merci à tous pour votre participation ! +feature.events.halloween.festival.start_message=<#ff6b25>L'événement Halloween %1$s<#ff6b25> vient de COMMENCER !\ +
<#ff6b25>La Sorcière vous attend. Elle a peut-être des choses intéressantes nyahahaha !\ +
\ +
<#ffd580>Chassez les Bonbons et décorez votre Ville avant la fin de l'événement ! + +feature.events.halloween.festival.end_message=<#ff6b25>L'événement Halloween %1$s<#ff6b25> est maintenant FINI !\ +
<#ff6b25>La Sorcière vous remercie pour tout les bonbons que vous lui avez apporté nyahahaha !\ +
\ +
<#ffd580>Merci à tous pour votre participation ! + +feature.events.halloween.festival.sb.info.0=Points : %1$s +feature.events.halloween.festival.sb.info.1=Récompense : %1$s / %2$s +feature.events.halloween.festival.sb.info.2=Étage Finale Atteint +feature.events.halloween.festival.sb.info.3=But %1$s : %2$s / %3$s %4$s + +feature.events.halloween.festival.menu.reward=Exposition de la Récompense +feature.events.halloween.festival.menu.candy_choice=Selection du Bonbon +feature.events.halloween.festival.menu.candy_choice.candy_point=Valeur : %1$s %2$s +feature.events.halloween.festival.menu.advancement=Avancement des Points +feature.events.halloween.festival.menu.advancement.item_name=Avancement +feature.events.halloween.festival.menu.advancement.item_lore=Points Totales : %1$s %2$s +feature.events.halloween.festival.menu.store.name=Boutique de la Sorcière - Page %1$s +feature.events.halloween.festival.menu.main.name=Ou veux-tu aller +feature.events.halloween.festival.menu.choice.name=Que veux-tu faire +feature.events.halloween.festival.button.store.name=Boutique de la Sorcière +feature.events.halloween.festival.button.store.lore=Achetez des items pour décorer votre Ville +feature.events.halloween.festival.button.house.name=Maison et Avancement +feature.events.halloween.festival.button.house.lore=Accédez à la Maison de la Terreur et vérifiez l'Avancement +feature.events.halloween.festival.button.terror_house.name=Maison de la Terreur +feature.events.halloween.festival.button.terror_house.lore=Visitez la Maison de la terreur et atteignez le sommet ! +feature.events.halloween.festival.button.deposit.name=Avancement +feature.events.halloween.festival.button.deposit.lore=Augmentez l'avancement en achetant des bonbons ! + +feature.events.halloween.festival.shop.player_buy_item=Vous avez acheté %1$s %2$s pour %3$s %4$s +feature.events.halloween.festival.shop.lore_item.buy=Achetez : %1$s +feature.events.halloween.festival.shop.lore_item.point=Obtener : %1$s %2$s par unitée +feature.events.halloween.festival.shop.lore_item.lock=Atteignez le %1$s pour dévérouiller cet item ! +feature.events.halloween.festival.deposit.add_point=Vous avez ajouté %1$s %2$s pour %3$s %4$s +feature.events.halloween.festival.deposit.broadcast_add_point=%1$s a ajouté %2$s %3$s pour %4$s %5$s ! +feature.events.halloween.festival.player_not_enough_item=Vous n'avez pas assez de %1$s dans votre inventaire ! +feature.events.halloween.festival.shop.confirm_lore=■ Quantité : %1$s (%2$s stack%3$s)\ +
■ Prix à l'unité: %4$s%5$s pour %6$s%7$s \ +
■ Prix totale: %8$s%9$s pour %10$s%11$s \ +
■ Cliquez sur la molette pour définir manuellement la quantité + +feature.events.halloween.festival.new_floor_unlock=Déblocage d'un nouvel étage !\ +
Collectez %1$s %3$s pour débloquer l'étage suivant\ +
Collecté : %2$s / %1$s %3$s\ +
\ +
De nouveaux objets sont disponibles dans la boutique, venez les découvrir ! + +feature.events.halloween.festival.last_floor_unlock=Déblocage du dernier étage !\ +
Collectez %1$s %3$s pour débloquer une récompense exclusive\ +
Collecté : %2$s / %1$s %3$s\ +
\ +
De nouveaux objets sont disponibles dans la boutique, venez les découvrir ! + +feature.events.halloween.festival.player_not_allow=Vous ne pouvez pas faire cela ! +feature.events.halloween.festival.floor_lock=Cet étage est verrouillé ! + +feature.events.halloween.festival.chest_lootbox=Butin du coffre +feature.events.halloween.festival.chest_lootbox.menu.name=Coffre +feature.events.halloween.festival.chest_lootbox.menu.button.name=Recharger +feature.events.halloween.festival.chest_lootbox.menu.button.lore=Cela supprimera le butin actuel. Attendez pour en obtenir un nouveau. +feature.events.halloween.festival.chest_lootbox.prevention=Vous avez fermé le coffre. Le butin est en cours de renouvellement. Revenez la prochaine fois pour récupérer tout ce dont vous avez besoin ! + +feature.events.halloween.festival.npc.name.0=Sorciere Suspecte + +feature.events.halloween.festival.mob.zombie.name.0=Réceptionniste +feature.events.halloween.festival.mob.skeleton.name.0=Squelette +feature.events.halloween.festival.mob.spider.name.0=Araignée + +feature.events.halloween.festival.mob.zombie.name.1=Zombie en armure +feature.events.halloween.festival.mob.skeleton.name.1=Squelette en armure +feature.events.halloween.festival.mob.spider.name.1=Araignée venimeuse +feature.events.halloween.festival.mob.blaze.name.1=Blaze +feature.events.halloween.festival.mob.wither_skeleton.name.1=Squelette Wither en armure + +feature.events.halloween.festival.mob.zombie.name.2=Zombie d'élite +feature.events.halloween.festival.mob.witch.name.2=Sorcière d'élite +feature.events.halloween.festival.mob.brute.name.2=Brute d'élite \ No newline at end of file diff --git a/src/main/resources/translations/default/itemsadder.properties b/src/main/resources/translations/default/itemsadder.properties index 32c2e1ddc..6ce6a55c3 100644 --- a/src/main/resources/translations/default/itemsadder.properties +++ b/src/main/resources/translations/default/itemsadder.properties @@ -187,6 +187,15 @@ itemsadder.omc_foods.the_mixture.name=The Mixture itemsadder.omc_foods.the_mixture.lore.0=un mystérieux mélange... itemsadder.omc_foods.the_mixture.lore.1=Aucun Effet Secondaire! itemsadder.omc_foods.tomate.name=Tomate +itemsadder.omc_halloween.candy_red.name=Bonbon Rouge +itemsadder.omc_halloween.candy_yellow.name=Bonbon Jaune +itemsadder.omc_halloween.candy_green.name=Bonbon Vert +itemsadder.omc_halloween.candy_blue.name=Bonbon Bleu +itemsadder.omc_halloween.candy_brown.name=Bonbon Monstre +itemsadder.omc_halloween.candy.lore.0=N'en mange pas trop +itemsadder.omc_halloween.candy.lore.1=N'en mange surtout pas, c'est infecte ! +itemsadder.omc_halloween.root_plush.name=FrankenRoot + itemsadder.omc_homes.omc_homes_icon_axenq.name=Pourquoi faire ? itemsadder.omc_homes.omc_homes_icon_bank.name=Pourquoi faire ? itemsadder.omc_homes.omc_homes_icon_chateau.name=Pourquoi faire ? diff --git a/src/main/resources/translations/en_GB/events.properties b/src/main/resources/translations/en_GB/events.properties index ef66704a6..bfb4a6e89 100644 --- a/src/main/resources/translations/en_GB/events.properties +++ b/src/main/resources/translations/en_GB/events.properties @@ -52,3 +52,83 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>The Halloween 2026 event i
<#ff6b25>You can find your rewards in your<#ff6b25> mailbox<#ff6b25>.\
<#ffd580>Thank you everyone for your participation! +feature.events.halloween.festival.start_message=<#ff6b25>The Halloween %1$s<#ff6b25> event has START !\ +
<#ff6b25>The Witch is waiting for you. She has some things that might interest you nyahahaha !\ +
\ +
<#ffd580>Hunt for Candy and decorate your City before the end of the Event ! + +feature.events.halloween.festival.end_message=<#ff6b25>The Halloween %1$s<#ff6b25> event is now over!\ +
<#ff6b25>The Witch thanks you for all the candy you bought her nyahahaha !\ +
\ +
<#ffd580>Thank you everyone for your participation ! + +feature.events.halloween.festival.sb.info.0=Points : %1$s +feature.events.halloween.festival.sb.info.1=Reward : %1$s / %2$s +feature.events.halloween.festival.sb.info.2=Last Floor Reached +feature.events.halloween.festival.sb.info.3=Goal %1$s : %2$s / %3$s %4$s + +feature.events.halloween.festival.menu.reward=Reward Exposition +feature.events.halloween.festival.menu.candy_choice=Candy Selection +feature.events.halloween.festival.menu.candy_choice.candy_point=Value : %1$s %2$s +feature.events.halloween.festival.menu.advancement=Point Advancement +feature.events.halloween.festival.menu.advancement.item_name=Advancement +feature.events.halloween.festival.menu.advancement.item_lore=Total points : %1$s %2$s +feature.events.halloween.festival.menu.store.name=Witch shop - Page %1$s +feature.events.halloween.festival.menu.main.name=Where do you want to go +feature.events.halloween.festival.menu.choice.name=What do you want to do +feature.events.halloween.festival.button.store.name=Witch Store +feature.events.halloween.festival.button.store.lore=Buy items to decorate your city +feature.events.halloween.festival.button.house.name=House and Advancement +feature.events.halloween.festival.button.house.lore=Access to the Terror House and check the Advancement +feature.events.halloween.festival.button.terror_house.name=Terror House +feature.events.halloween.festival.button.terror_house.lore=Visit the Terror House and reach the top ! +feature.events.halloween.festival.button.deposit.name=Advancement +feature.events.halloween.festival.button.deposit.lore=Increase the advancement by deposing candy ! + +feature.events.halloween.festival.shop.player_buy_item=You bought %1$s %2$s for %3$s %4$s +feature.events.halloween.festival.shop.lore_item.buy=Buy : %1$s +feature.events.halloween.festival.shop.lore_item.point=Earn : %1$s %2$s per unit +feature.events.halloween.festival.shop.lore_item.lock=Reach the %1$s to unlock this item ! +feature.events.halloween.festival.deposit.add_point=You added %1$s %2$s for %3$s %4$s +feature.events.halloween.festival.deposit.broadcast_add_point=%1$s added %2$s %3$s for %4$s %5$s ! +feature.events.halloween.festival.player_not_enough_item=You don't have enough of %1$s in your inventory ! +feature.events.halloween.festival.shop.confirm_lore=■ Quantity : %1$s (%2$s stack%3$s)\ +
■ Unit price: %4$s%5$s for %6$s%7$s \ +
■ Total price: %8$s%9$s for %10$s%11$s \ +
■ Click the wheel to define the quantity manually + +feature.events.halloween.festival.new_floor_unlock=New Floor Unlock !\ +
Collect %1$s %3$s to unlock the next floor\ +
Collected : %2$s / %1$s %3$s\ +
\ +
New items in the shop, come and check them out! +feature.events.halloween.festival.last_floor_unlock=Last Floor Unlock !\ +
Collect %1$s %3$s to unlock an exclusive reward\ +
Collected : %2$s / %1$s %3$s\ +
\ +
New items in the shop, come and check them out! + +feature.events.halloween.festival.player_not_allow=You are not allowed to do this ! +feature.events.halloween.festival.floor_lock=This floor is lock ! + +feature.events.halloween.festival.chest_lootbox=Loot Chest Loots +feature.events.halloween.festival.chest_lootbox.menu.name=Chest +feature.events.halloween.festival.chest_lootbox.menu.button.name=Reload +feature.events.halloween.festival.chest_lootbox.menu.button.lore=This will delete the current loot, wait to get new one +feature.events.halloween.festival.chest_lootbox.prevention=You have close the chest, the loot is reloading, take everything you need the next time ! + +feature.events.halloween.festival.npc.name.0=Suspicious Witch + +feature.events.halloween.festival.mob.zombie.name.0=Receptionist +feature.events.halloween.festival.mob.skeleton.name.0=Skeleton +feature.events.halloween.festival.mob.spider.name.0=Spider + +feature.events.halloween.festival.mob.zombie.name.1=Armored Zombie +feature.events.halloween.festival.mob.skeleton.name.1=Armored Skeleton +feature.events.halloween.festival.mob.spider.name.1=Cave Spider +feature.events.halloween.festival.mob.blaze.name.1=Blaze +feature.events.halloween.festival.mob.wither_skeleton.name.1=Armored Wither Skeleton + +feature.events.halloween.festival.mob.zombie.name.2=Elite Zombie +feature.events.halloween.festival.mob.witch.name.2=Elite Witch +feature.events.halloween.festival.mob.brute.name.2=Elite Brute \ No newline at end of file diff --git a/src/main/resources/translations/en_GB/itemsadder.properties b/src/main/resources/translations/en_GB/itemsadder.properties index f55538a4b..14f67dda1 100644 --- a/src/main/resources/translations/en_GB/itemsadder.properties +++ b/src/main/resources/translations/en_GB/itemsadder.properties @@ -168,6 +168,16 @@ itemsadder.omc_foods.the_mixture.name=The Mixture itemsadder.omc_foods.the_mixture.lore.0=a mysterious mixture... itemsadder.omc_foods.the_mixture.lore.1=No Side Effect! itemsadder.omc_foods.tomate.name=Tomato +itemsadder.omc_halloween.candy_red.name=Red Candy +itemsadder.omc_halloween.candy_yellow.name=Yellow Candy +itemsadder.omc_halloween.candy_green.name=Green Candy +itemsadder.omc_halloween.candy_blue.name=Blue Candy +itemsadder.omc_halloween.candy_brown.name=Monster Candy +itemsadder.omc_halloween.candy.lore.0=Don't eat too much of it. +itemsadder.omc_halloween.candy.lore.1=Don't eat it, it's disgusting ! +itemsadder.omc_halloween.root_plush.name=FrankenRoot +itemsadder.omc_halloween.root_plush.lore.0=Distributed during the 2026 OpenMC Halloween event ! + itemsadder.omc_homes.omc_homes_icon_axenq.name=Why bother itemsadder.omc_homes.omc_homes_icon_bank.name=Why bother itemsadder.omc_homes.omc_homes_icon_chateau.name=Why bother diff --git a/src/main/resources/translations/en_US/events.properties b/src/main/resources/translations/en_US/events.properties index ef66704a6..bfb4a6e89 100644 --- a/src/main/resources/translations/en_US/events.properties +++ b/src/main/resources/translations/en_US/events.properties @@ -52,3 +52,83 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>The Halloween 2026 event i
<#ff6b25>You can find your rewards in your<#ff6b25> mailbox<#ff6b25>.\
<#ffd580>Thank you everyone for your participation! +feature.events.halloween.festival.start_message=<#ff6b25>The Halloween %1$s<#ff6b25> event has START !\ +
<#ff6b25>The Witch is waiting for you. She has some things that might interest you nyahahaha !\ +
\ +
<#ffd580>Hunt for Candy and decorate your City before the end of the Event ! + +feature.events.halloween.festival.end_message=<#ff6b25>The Halloween %1$s<#ff6b25> event is now over!\ +
<#ff6b25>The Witch thanks you for all the candy you bought her nyahahaha !\ +
\ +
<#ffd580>Thank you everyone for your participation ! + +feature.events.halloween.festival.sb.info.0=Points : %1$s +feature.events.halloween.festival.sb.info.1=Reward : %1$s / %2$s +feature.events.halloween.festival.sb.info.2=Last Floor Reached +feature.events.halloween.festival.sb.info.3=Goal %1$s : %2$s / %3$s %4$s + +feature.events.halloween.festival.menu.reward=Reward Exposition +feature.events.halloween.festival.menu.candy_choice=Candy Selection +feature.events.halloween.festival.menu.candy_choice.candy_point=Value : %1$s %2$s +feature.events.halloween.festival.menu.advancement=Point Advancement +feature.events.halloween.festival.menu.advancement.item_name=Advancement +feature.events.halloween.festival.menu.advancement.item_lore=Total points : %1$s %2$s +feature.events.halloween.festival.menu.store.name=Witch shop - Page %1$s +feature.events.halloween.festival.menu.main.name=Where do you want to go +feature.events.halloween.festival.menu.choice.name=What do you want to do +feature.events.halloween.festival.button.store.name=Witch Store +feature.events.halloween.festival.button.store.lore=Buy items to decorate your city +feature.events.halloween.festival.button.house.name=House and Advancement +feature.events.halloween.festival.button.house.lore=Access to the Terror House and check the Advancement +feature.events.halloween.festival.button.terror_house.name=Terror House +feature.events.halloween.festival.button.terror_house.lore=Visit the Terror House and reach the top ! +feature.events.halloween.festival.button.deposit.name=Advancement +feature.events.halloween.festival.button.deposit.lore=Increase the advancement by deposing candy ! + +feature.events.halloween.festival.shop.player_buy_item=You bought %1$s %2$s for %3$s %4$s +feature.events.halloween.festival.shop.lore_item.buy=Buy : %1$s +feature.events.halloween.festival.shop.lore_item.point=Earn : %1$s %2$s per unit +feature.events.halloween.festival.shop.lore_item.lock=Reach the %1$s to unlock this item ! +feature.events.halloween.festival.deposit.add_point=You added %1$s %2$s for %3$s %4$s +feature.events.halloween.festival.deposit.broadcast_add_point=%1$s added %2$s %3$s for %4$s %5$s ! +feature.events.halloween.festival.player_not_enough_item=You don't have enough of %1$s in your inventory ! +feature.events.halloween.festival.shop.confirm_lore=■ Quantity : %1$s (%2$s stack%3$s)\ +
■ Unit price: %4$s%5$s for %6$s%7$s \ +
■ Total price: %8$s%9$s for %10$s%11$s \ +
■ Click the wheel to define the quantity manually + +feature.events.halloween.festival.new_floor_unlock=New Floor Unlock !\ +
Collect %1$s %3$s to unlock the next floor\ +
Collected : %2$s / %1$s %3$s\ +
\ +
New items in the shop, come and check them out! +feature.events.halloween.festival.last_floor_unlock=Last Floor Unlock !\ +
Collect %1$s %3$s to unlock an exclusive reward\ +
Collected : %2$s / %1$s %3$s\ +
\ +
New items in the shop, come and check them out! + +feature.events.halloween.festival.player_not_allow=You are not allowed to do this ! +feature.events.halloween.festival.floor_lock=This floor is lock ! + +feature.events.halloween.festival.chest_lootbox=Loot Chest Loots +feature.events.halloween.festival.chest_lootbox.menu.name=Chest +feature.events.halloween.festival.chest_lootbox.menu.button.name=Reload +feature.events.halloween.festival.chest_lootbox.menu.button.lore=This will delete the current loot, wait to get new one +feature.events.halloween.festival.chest_lootbox.prevention=You have close the chest, the loot is reloading, take everything you need the next time ! + +feature.events.halloween.festival.npc.name.0=Suspicious Witch + +feature.events.halloween.festival.mob.zombie.name.0=Receptionist +feature.events.halloween.festival.mob.skeleton.name.0=Skeleton +feature.events.halloween.festival.mob.spider.name.0=Spider + +feature.events.halloween.festival.mob.zombie.name.1=Armored Zombie +feature.events.halloween.festival.mob.skeleton.name.1=Armored Skeleton +feature.events.halloween.festival.mob.spider.name.1=Cave Spider +feature.events.halloween.festival.mob.blaze.name.1=Blaze +feature.events.halloween.festival.mob.wither_skeleton.name.1=Armored Wither Skeleton + +feature.events.halloween.festival.mob.zombie.name.2=Elite Zombie +feature.events.halloween.festival.mob.witch.name.2=Elite Witch +feature.events.halloween.festival.mob.brute.name.2=Elite Brute \ No newline at end of file diff --git a/src/main/resources/translations/en_US/itemsadder.properties b/src/main/resources/translations/en_US/itemsadder.properties index 5258127a3..0d75087d2 100644 --- a/src/main/resources/translations/en_US/itemsadder.properties +++ b/src/main/resources/translations/en_US/itemsadder.properties @@ -169,6 +169,16 @@ itemsadder.omc_foods.the_mixture.name=The Mixture itemsadder.omc_foods.the_mixture.lore.0=a mysterious mixture... itemsadder.omc_foods.the_mixture.lore.1=No Side Effect! itemsadder.omc_foods.tomate.name=Tomato +itemsadder.omc_halloween.candy_red.name=Red Candy +itemsadder.omc_halloween.candy_yellow.name=Yellow Candy +itemsadder.omc_halloween.candy_green.name=Green Candy +itemsadder.omc_halloween.candy_blue.name=Blue Candy +itemsadder.omc_halloween.candy_brown.name=Monster Candy +itemsadder.omc_halloween.candy.lore.0=Don't eat too much of it. +itemsadder.omc_halloween.candy.lore.1=Don't eat it, it's disgusting ! +itemsadder.omc_halloween.root_plush.name=FrankenRoot +itemsadder.omc_halloween.root_plush.lore.0=Distributed during the 2026 OpenMC Halloween event ! + itemsadder.omc_homes.omc_homes_icon_axenq.name=Why bother itemsadder.omc_homes.omc_homes_icon_bank.name=Why bother itemsadder.omc_homes.omc_homes_icon_chateau.name=Why bother