From 830b4008604ead99425a9471f1bc322a601f93ba Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sun, 13 Sep 2026 16:55:39 +0200 Subject: [PATCH 01/44] ajout de la ""base"" --- .../halloween/SEHalloweenManager.java | 29 +++++++++++ .../dimension/advancement/Advancements.java | 15 ++++++ .../halloween/model/SEHalloweenEventData.java | 51 +++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java new file mode 100644 index 000000000..2b9d2545e --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java @@ -0,0 +1,29 @@ +package fr.openmc.core.features.events.contents.seasonevents.halloween; + +import com.j256.ormlite.support.ConnectionSource; +import fr.openmc.core.bootstrap.features.Feature; +import fr.openmc.core.bootstrap.features.types.HasCommands; +import fr.openmc.core.bootstrap.features.types.HasDatabase; +import fr.openmc.core.bootstrap.features.types.HasListeners; +import fr.openmc.core.bootstrap.listeners.ListenerFactory; + +import java.sql.SQLException; +import java.util.Set; + +public class SEHalloweenManager extends Feature implements HasDatabase, HasListeners, HasCommands { + + @Override + public void initDB(ConnectionSource connectionSource) throws SQLException { + + } + + @Override + public Set getListeners() { + return Set.of(); + } + + @Override + public Set getCommands() { + return Set.of(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java new file mode 100644 index 000000000..631e5f81d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java @@ -0,0 +1,15 @@ +package fr.openmc.core.features.events.contents.seasonevents.halloween.dimension.advancement; + +import lombok.Getter; + +@Getter +public enum Advancements { + ROOM_1(1000) + ; + + private final int require; + + Advancements(int require) { + this.require = require; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java new file mode 100644 index 000000000..c68faab23 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java @@ -0,0 +1,51 @@ +package fr.openmc.core.features.events.contents.seasonevents.halloween.model; + +import com.google.gson.Gson; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEvent; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; +import lombok.Getter; +import lombok.Setter; + +@Getter +@DatabaseTable(tableName = "halloween_season_event_data") +public class SEHalloweenEventData { + + @DatabaseField(id = true, columnName = "id") + private int id = 1; + + @Setter + @DatabaseField(columnName = "advancement") + private String currentAdvencement; + + @Setter + @DatabaseField(columnName = "unlocked_room") + private String currentUnlocked; + + @Setter + @DatabaseField(columnName = "is_active") + private boolean active; + + public SEHalloweenEventData() {} + + public SEHalloweenEventData(WeeklyEvent currentEvent, WeeklyEventPhase currentPhase) { + this.currentEvent = currentEvent.getId(); + if (currentPhase == null) + this.currentPhase = null; + else + this.currentPhase = currentPhase.getId(); + } + + private static final Gson GSON = new Gson(); + + public void setContent(String[] array) { + currentUnlocked = GSON.toJson(array); + } + + public String[] getContent() { + if (currentUnlocked == null) return new String[0]; + return GSON.fromJson(currentUnlocked, String[].class); + } + +} From 3d5f3ce97c5c1a265aa368dedaba25fbd68f9b09 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Mon, 14 Sep 2026 22:14:14 +0200 Subject: [PATCH 02/44] =?UTF-8?q?update=201=20pc=20<->=20pc=20lyc=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../halloween/SEHalloweenManager.java | 72 +++++++++++++++++++ .../halloween/dimension/DimensionManager.java | 60 ++++++++++++++++ .../dimension/advancement/Advancements.java | 15 ++++ .../halloween/model/HalloweenDB.java | 46 ++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java new file mode 100644 index 000000000..0299ed740 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java @@ -0,0 +1,72 @@ +package fr.openmc.core.features.events.contents.halloween.halloween; + +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.bootstrap.features.Feature; +import fr.openmc.core.bootstrap.features.types.HasCommands; +import fr.openmc.core.bootstrap.features.types.HasDatabase; +import fr.openmc.core.bootstrap.features.types.HasListeners; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.bootstrap.listeners.ListenerFactory; +import fr.openmc.core.features.corpse.npc.CorpseNPCManager; +import fr.openmc.core.features.events.contents.halloween.halloween.model.HalloweenDB; +import lombok.Getter; + +import java.sql.SQLException; +import java.util.*; + +public class SEHalloweenManager extends Feature implements HasDatabase, HasListeners, HasCommands { + + @Getter + private static HalloweenDB halloweenDB; + + private static Dao halloweenDao; + + public static String[] unlockedRooms; + + @Override + public void init() { + CorpseNPCManager.init(); + halloweenDB = loadEvent(); + unlockedRooms = halloweenDB.getContent(); + } + + @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 { + return halloweenDao.queryForFirst(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void saveEvent() { + try { + halloweenDao.createOrUpdate(halloweenDB); + } catch (Exception e) { + OMCLogger.error("Impossible de sauvegarder les corpses pendant l'arret.", e); + } + } + + @Override + public Set getListeners() { + return Set.of(); + } + + @Override + public Set getCommands() { + return Set.of(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java new file mode 100644 index 000000000..07b3ca096 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java @@ -0,0 +1,60 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.dimension; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.features.dream.DreamDimensionManager; +import org.bukkit.Bukkit; +import org.bukkit.GameRules; +import org.bukkit.World; +import org.bukkit.entity.SpawnCategory; + +import java.io.File; + +public class DimensionManager { + + public static final String DIMENSION_NAME = "world_omc_halloween_witch_house"; + public static World HALLOWEEN_WORLD; + + public static void init() { +// seedFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data/dream", "seed.yml"); +// loadSeed(); + HALLOWEEN_WORLD = Bukkit.getWorld(DIMENSION_NAME); + + setupDimension(); + } + + //TODO setup la dimension : + // - monde vide + ajout de la structure de Mcross + // - ambiant custom + + private static void setupDimension() { + if (!HALLOWEEN_WORLD.getName().equals(DreamDimensionManager.DIMENSION_NAME)) return; + + // ** SPAWNING RULES ** + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.MONSTER, 10); + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.AMBIENT, 10); + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.ANIMAL, 6); + + 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); + + // ** SET WORLD BORDER AND TIME ** + HALLOWEEN_WORLD.getWorldBorder().setSize(10000); + HALLOWEEN_WORLD.setTime(18000); + + OMCLogger.infoFormatted("Dimension des rêves setup (gamerules, worldborder, time)"); + } + +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java new file mode 100644 index 000000000..88c2ab606 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java @@ -0,0 +1,15 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement; + +import lombok.Getter; + +@Getter +public enum Advancements { + ROOM_1(1000) + ; + + private final int require; + + Advancements(int require) { + this.require = require; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java new file mode 100644 index 000000000..b40d67d40 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java @@ -0,0 +1,46 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.model; + +import com.google.gson.Gson; +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; +import lombok.Setter; + +@Getter +@DatabaseTable(tableName = "halloween_season_event_data") +public class HalloweenDB { + + @Setter + @DatabaseField(columnName = "advancement") + private String currentAdvancement; + + @Setter + @DatabaseField(columnName = "unlocked_room") + private String unlockedRooms; + + @Setter + @DatabaseField(columnName = "is_active") + private boolean active; + + private static final Gson GSON = new Gson(); + + public HalloweenDB() { + + } + + public HalloweenDB(String currentAdvancement, String currentUnlocked, boolean active) { + this.currentAdvancement = currentAdvancement; + this.unlockedRooms = currentUnlocked; + this.active = active; + } + + public void setContent(String[] array) { + unlockedRooms = GSON.toJson(array); + } + + public String[] getContent() { + if (unlockedRooms == null) return new String[0]; + return GSON.fromJson(unlockedRooms, String[].class); + } + +} From 635ca6d7bd11b3a882cd4899ef1a9699683076a0 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 19 Sep 2026 12:54:08 +0200 Subject: [PATCH 03/44] add Managers, base Dimension, start of the menus --- src/main/java/fr/openmc/core/OMCRegistry.java | 4 + ...weenManager.java => HalloweenManager.java} | 2 +- .../halloween/dimension/DimensionManager.java | 26 ++- .../dimension/WitchHouseManager.java | 4 + .../halloween/halloween/shop/ShopMoney.java | 15 ++ .../halloween/shop/WitchShopItem.java | 37 ++++ .../halloween/shop/WitchShopManager.java | 144 ++++++++++++ .../halloween/shop/menu/ConfirmMenu.java | 209 ++++++++++++++++++ .../shop/menu/WitchShopMainMenu.java | 76 +++++++ .../shop/menu/WitchShopStoreMenu.java | 170 ++++++++++++++ .../shop/menu/buttons/WitchHouseButton.java | 34 +++ .../shop/menu/buttons/WitchStoreButton.java | 42 ++++ .../halloween/model/SEHalloweenEventData.java | 10 +- .../registry/structures/CustomStructure.java | 69 ++++++ .../structures/CustomStructureRegistry.java | 36 +++ .../contents/omc_menus/configs/menus.yml | 6 + .../textures/halloween_event_main_menu.png | Bin 0 -> 6468 bytes .../omc_halloween/dimension/witch_house.json | 12 + .../datapacks/omc_halloween/pack.mcmeta | 8 + 19 files changed, 888 insertions(+), 16 deletions(-) rename src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/{SEHalloweenManager.java => HalloweenManager.java} (95%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java create mode 100644 src/main/java/fr/openmc/core/registry/structures/CustomStructure.java create mode 100644 src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java create mode 100644 src/main/resources/contents/omc_menus/textures/halloween_event_main_menu.png create mode 100644 src/main/resources/datapacks/omc_halloween/data/omc_halloween/dimension/witch_house.json create mode 100644 src/main/resources/datapacks/omc_halloween/pack.mcmeta diff --git a/src/main/java/fr/openmc/core/OMCRegistry.java b/src/main/java/fr/openmc/core/OMCRegistry.java index 1681ea3ef..b2d410890 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 io.papermc.paper.plugin.bootstrap.BootstrapContext; import java.io.IOException; @@ -30,6 +31,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; // * Registre des features @@ -56,6 +58,8 @@ public final class OMCRegistry { RegistryLoadingType.AFTER_IA), new RegistryContext(() -> CUSTOM_MOBS = new CustomMobRegistry(), RegistryLoadingType.AFTER_IA), + new RegistryContext(() -> CUSTOM_STRUCTURES = new CustomStructureRegistry(), + RegistryLoadingType.RUNTIME), new RegistryContext(() -> WEEKLY_EVENTS = new WeeklyEventsRegistry(), RegistryLoadingType.AFTER_IA), new RegistryContext(() -> DAILY_EVENTS = new DailyEventsRegistry(), diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java similarity index 95% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java index 0299ed740..fea3ad91a 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/SEHalloweenManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java @@ -17,7 +17,7 @@ import java.sql.SQLException; import java.util.*; -public class SEHalloweenManager extends Feature implements HasDatabase, HasListeners, HasCommands { +public class HalloweenManager extends Feature implements HasDatabase, HasListeners, HasCommands { @Getter private static HalloweenDB halloweenDB; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java index 07b3ca096..ac7c714df 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java @@ -1,26 +1,21 @@ package fr.openmc.core.features.events.contents.halloween.halloween.dimension; -import fr.openmc.core.OMCPlugin; import fr.openmc.core.bootstrap.integration.OMCLogger; -import fr.openmc.core.features.dream.DreamDimensionManager; import org.bukkit.Bukkit; import org.bukkit.GameRules; import org.bukkit.World; import org.bukkit.entity.SpawnCategory; -import java.io.File; - public class DimensionManager { public static final String DIMENSION_NAME = "world_omc_halloween_witch_house"; public static World HALLOWEEN_WORLD; public static void init() { -// seedFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data/dream", "seed.yml"); -// loadSeed(); HALLOWEEN_WORLD = Bukkit.getWorld(DIMENSION_NAME); setupDimension(); +// loadRegions(); } //TODO setup la dimension : @@ -28,7 +23,7 @@ public static void init() { // - ambiant custom private static void setupDimension() { - if (!HALLOWEEN_WORLD.getName().equals(DreamDimensionManager.DIMENSION_NAME)) return; + if (!HALLOWEEN_WORLD.getName().equals(DIMENSION_NAME)) return; // ** SPAWNING RULES ** HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.MONSTER, 10); @@ -51,10 +46,21 @@ private static void setupDimension() { HALLOWEEN_WORLD.setGameRule(GameRules.ALLOW_ENTERING_NETHER_USING_PORTALS, false); // ** SET WORLD BORDER AND TIME ** - HALLOWEEN_WORLD.getWorldBorder().setSize(10000); - HALLOWEEN_WORLD.setTime(18000); + HALLOWEEN_WORLD.getWorldBorder().setSize(500); + HALLOWEEN_WORLD.setTime(14000); - OMCLogger.infoFormatted("Dimension des rêves setup (gamerules, worldborder, time)"); + OMCLogger.infoFormatted("Dimension de la Maison de la Sorcière setup (gamerules, worldborder, time)"); } + //TODO modifier avec les region de bibi +// private static void loadRegions() { +// MultiRegion multiRegion = new MultiRegion( +// HALLOWEEN_WORLD, +// new SquareRegion(0.0, 60.0, 0.0, 6.0, 70.0, 3.0, HALLOWEEN_WORLD), +// new SquareRegion(0.0, 60.0, 6.0, 3.0, 70.0, 3.0, HALLOWEEN_WORLD) +// ); +// +// multiRegion.addDetection(); +// } + } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java new file mode 100644 index 000000000..3b0e0e870 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java @@ -0,0 +1,4 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.dimension; + +public class WitchHouseManager { +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java new file mode 100644 index 000000000..cf3e688ba --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java @@ -0,0 +1,15 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.shop; + +import lombok.Getter; + +@Getter +public enum ShopMoney { + MONSTER_CANDY(WitchShopManager.getMoneyItemIcon("")), + ; + + private final String icon; + + ShopMoney(String icon) { + this.icon = icon; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java new file mode 100644 index 000000000..810b75715 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java @@ -0,0 +1,37 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.shop; + +import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; +import fr.openmc.core.registry.items.CustomItem; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextDecoration; + +public class WitchShopItem { + + @Getter public final Advancements advancements; + @Getter public final CustomItem item; + public final Component name; + @Getter public final ShopMoney shopMoney; + @Getter public final int price; + + + public WitchShopItem(Advancements 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(Advancements advancements, CustomItem item, Component name, int price) { + this.advancements = advancements; + this.item = item; + this.name = name; + this.shopMoney = ShopMoney.MONSTER_CANDY; + this.price = price; + } + + public Component getName() { + // TODO get current advancement + return Component.text("aaaaaaaaaa").decoration(TextDecoration.OBFUSCATED, false); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java new file mode 100644 index 000000000..56957ff40 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java @@ -0,0 +1,144 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.shop; + +import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.core.features.adminshop.AdminShopUtils; +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 { + + //TODO idée : + // bruit de sorcière quand on buy un item + + public static Set 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; + + public void init() { + witchStoreItems = getWitchStoreItems(); + paginateWitchStoreItems = getPaginateWitchStoreItems(); + maxPage = getWitchStorePages(); + } + + private static Set getWitchStoreItems() { + return Set.of( + new WitchShopItem() + ); + } + + 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) { + + List subList = list.subList(i, Math.min(i + SLOT_FACTOR, list.size())); + + paginateItems.put(page++, new HashSet<>(subList)); + } + + 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 witchStoreItems.size() / SLOT_FACTOR; + } + + 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; + } + + if (item.getPrice() <= 0) { + sendError(player, TranslationManager.translation("feature.adminshop.item_not_sellable")); + return; + } + + int totalPrice = item.getPrice() * amount; + if (ItemUtils.hasEnoughItems(player, item.getItem().getBest(), totalPrice)) { + + ItemUtils.giveItem(player, item.getItem().getBest(), amount); + + sendInfo(player, TranslationManager.translation("feature.adminshop.player_buy_item", + Component.text(amount), item.getName(), Component.text(AdminShopUtils.formatPrice(totalPrice)) + )); + + player.playSound(player, BUY_SOUND, 1f, 1f); //TODO random pitch + } else { + sendError(player, TranslationManager.translation("feature.adminshop.have_enough_money")); //TODO + } + } + + private static void sendError(Player player, Component message) { + MessagesManager.sendMessage(player, message, Prefix.ADMINSHOP, MessageType.ERROR, true); //TODO prefix + } + + private static void sendInfo(Player player, Component message) { + MessagesManager.sendMessage(player, message, Prefix.ADMINSHOP, MessageType.INFO, true); //TODO prefix + } + + public static List extractLoreForItem(WitchShopItem item) { + List lore = new ArrayList<>(); + + if (true) { + lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO dire a qu'elle room on le débloque + Component.text(item.getAdvancements().name()) + ).color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); + } // TODO check the item advancement and compare with the currents + else { + lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO + Component.text(getPrice(item)) + ).color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); + } + + return lore; + } + + public static String getPrice(WitchShopItem item) { + return item.getPrice() + " " + item.getShopMoney(); + } + + public static String getMoneyItemIcon(String icon) { + if (ItemsAdderHook.isEnable()) { + return FontImageWrapper.replaceFontImages("§f:"+icon+":"); //TODO omc_icons + } else { + return "Ⓐ"; + } + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java new file mode 100644 index 000000000..e2bda17a3 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java @@ -0,0 +1,209 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu; + +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.adminshop.ShopItem; +import fr.openmc.core.features.economy.EconomyManager; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopItem; +import fr.openmc.core.features.events.contents.halloween.halloween.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.Material; +import org.bukkit.Sound; +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 ConfirmMenu extends Menu { + + private final WitchShopItem shopItem; + private int quantity; + private final int maxQuantity; + + public ConfirmMenu(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_-11::adminshop:"); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.NORMAL; + } + + @Override + public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + int pricePerUnit = shopItem.getPrice(); + int totalPrice = pricePerUnit * quantity; + int quantityToStack = Math.max(0, quantity / 64); + + 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(pricePerUnit), NamedTextColor.GREEN), + Component.text(shopItem.getShopMoney().getIcon(), NamedTextColor.GREEN), + Component.text(AdminShopManager.priceFormat.format(totalPrice), NamedTextColor.GREEN), + Component.text(shopItem.getShopMoney().getIcon(), NamedTextColor.GREEN) + + ); + + 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 -> { + 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.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/halloween/shop/menu/WitchShopMainMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java new file mode 100644 index 000000000..d31fb770e --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java @@ -0,0 +1,76 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu; + +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.city.City; +import fr.openmc.core.features.city.CityManager; +import fr.openmc.core.features.city.menu.main.buttons.*; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.buttons.WitchHouseButton; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.buttons.WitchStoreButton; +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 WitchShopMainMenu extends Menu { + + private static final int[] WITCH_HOUSE_SLOTS = {8, 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}; + + public WitchShopMainMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.city.menus.main.name"); //TODO + } + + @Override + public String getTexture() { + return "§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<>(); + Player player = getOwner(); + + City city = CityManager.getPlayerCity(player.getUniqueId()); + assert city != null; + + // ** Witch House Button + WitchHouseButton.init(this, inventory, WITCH_HOUSE_SLOTS); + + // ** Witch Store Button + WitchStoreButton.init(this, inventory, WITCH_SHOP_SLOTS); + + return inventory; + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + @Override + public void onClose(InventoryCloseEvent event) { + //TODO bruit de sorcière + } + + @Override + public void onInventoryClick(InventoryClickEvent click) { + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java new file mode 100644 index 000000000..470ca207d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java @@ -0,0 +1,170 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu; + +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.MenuUtils; +import fr.openmc.api.menulib.utils.StaticSlots; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.commands.utils.Restart; +import fr.openmc.core.features.city.City; +import fr.openmc.core.features.city.CityManager; +import fr.openmc.core.features.city.CityPermission; +import fr.openmc.core.features.city.actions.CityChestAction; +import fr.openmc.core.features.city.menu.CityChestMenu; +import fr.openmc.core.features.city.sub.milestone.rewards.ChestPageLimitRewards; +import fr.openmc.core.features.economy.EconomyManager; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopItem; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopManager; +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.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.*; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static fr.openmc.core.features.city.conditions.CityChestConditions.*; + +public class WitchShopStoreMenu extends PaginatedMenu { + + @Getter + private final int page; + + private final Column.Range line = new Column.Range(10, 16); + private final int column = 4; + + 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.getBottomSlots(getInventorySize()); + } + + @Override + public List getItems() { + return List.of(); + } + + @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")); + }).setPreviousPageButton()); + } + + map.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.close")); + }).setOnClick(event -> { + //TODO open the WitchShopMainMenu + })); + + if (hasNextPage()) { + map.put(53, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_NEXT_ORANGE, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); + }).setNextPageButton()); + } + + Iterator contents = WitchShopManager.getStoreContent(this.page).iterator(); + + for (int c = 0; c < column; c++) { + for (int l = line.floor(); l <= line.ceiling(); l++) { + + if (!contents.hasNext()) break; + + WitchShopItem item = contents.next(); + + map.put(l + (9 * c), new ItemMenuBuilder(this, item.getItem(), itemMeta -> { + itemMeta.displayName(item.getName()); + itemMeta.lore(WitchShopManager.extractLoreForItem(item)); + }).setOnClick(event -> { + //TODO open confirm menu if has enough moneyItem + })); + } + } + + return map; + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.city.menus.chest.name", + Component.text(""), Component.text(this.page)); //TODO + } + + @Override + public String getTexture() { + return "§r§f:offset_-48::city_template6x9:"; //TODO + } + + @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/halloween/shop/menu/buttons/WitchHouseButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java new file mode 100644 index 000000000..d53ef41f4 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java @@ -0,0 +1,34 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.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.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 org.bukkit.entity.Player; + +import java.util.Map; + +public class WitchHouseButton { + 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.city.menus.main.ranks.title"));//TODO + itemMeta.lore(TranslationManager.translationLore( + "feature.city.menus.main.ranks.lore.unlocked", //TODO + Component.text("").color(NamedTextColor.LIGHT_PURPLE) + )); + itemMeta.setItemModel(NamespacedKey.minecraft("air")); + }).setOnClick(inventoryClickEvent -> { //TODO tp dans la dimension + + }) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java new file mode 100644 index 000000000..0266329a2 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java @@ -0,0 +1,42 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.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.city.City; +import fr.openmc.core.features.city.sub.milestone.rewards.FeaturesRewards; +import fr.openmc.core.features.city.sub.rank.menus.CityRanksMenu; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.WitchShopStoreMenu; +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 org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; + +import java.util.List; +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.city.menus.main.ranks.title")); //TODO + itemMeta.lore(TranslationManager.translationLore( + "feature.city.menus.main.ranks.lore.unlocked", //TODO + Component.text("").color(NamedTextColor.LIGHT_PURPLE) + )); + itemMeta.setItemModel(NamespacedKey.minecraft("air")); + }).setOnClick(inventoryClickEvent -> { + new WitchShopStoreMenu(player, 1).open(); + }) + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java index c68faab23..43b427fa6 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java +++ b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java @@ -30,11 +30,11 @@ public class SEHalloweenEventData { public SEHalloweenEventData() {} public SEHalloweenEventData(WeeklyEvent currentEvent, WeeklyEventPhase currentPhase) { - this.currentEvent = currentEvent.getId(); - if (currentPhase == null) - this.currentPhase = null; - else - this.currentPhase = currentPhase.getId(); +// this.currentEvent = currentEvent.getId(); +// if (currentPhase == null) +// this.currentPhase = null; +// else +// this.currentPhase = currentPhase.getId(); } private static final Gson GSON = new Gson(); 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..9c5741f0d --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java @@ -0,0 +1,69 @@ +package fr.openmc.core.registry.structures; + +import lombok.Getter; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftWorld; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +public class CustomStructure { + + @Getter + String id; + File file; + + public CustomStructure(String id, File file) { + this.id = id; + this.file = file; + } + + public void placeStructure(Location origin, boolean mirrorX, boolean mirrorZ) { + ServerLevel level = ((CraftWorld) origin.getWorld()).getHandle(); + + try (InputStream in = new FileInputStream(file)) { + + CompoundTag tag = NbtIo.readCompressed(in, NbtAccounter.unlimitedHeap()); + + StructureTemplate template = new StructureTemplate(); + + template.load( + level.registryAccess().lookupOrThrow(Registries.BLOCK), + tag + ); + + StructurePlaceSettings settings = new StructurePlaceSettings(); + + if (mirrorX) settings.setMirror(Mirror.FRONT_BACK); + if (mirrorZ) settings.setMirror(Mirror.LEFT_RIGHT); + + settings.setRotation(Rotation.NONE); + + BlockPos pos = new BlockPos(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ()); + + template.placeInWorld( + level, + pos, + pos, + settings, + level.getRandom(), + 2 + ); + + } catch (Exception e) { + e.printStackTrace(); + } + } +} + 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..002f6a35b --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java @@ -0,0 +1,36 @@ +package fr.openmc.core.registry.structures; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.registries.KeyedRegistry; +import fr.openmc.core.bootstrap.registries.Registry; +import fr.openmc.core.utils.FilesUtils; + +import java.io.File; + +public class CustomStructureRegistry extends Registry + implements KeyedRegistry { + + private static final File structureFolder = new File(OMCPlugin.getInstance().getDataFolder(), "data/omc_structure"); + + // ** REGISTER STRUCTURES ** + public final CustomStructure TEST = register("omc_structure:test","pillar.nbt"); + + public CustomStructureRegistry() { + FilesUtils.createDirectoryIfNotExists(structureFolder); + } + + @Override + public String key(CustomStructure registryObject) { + return registryObject.getId(); + } + + public CustomStructure register(String name, String fileName) { + return register(name, new File(structureFolder, fileName)); + } + + public CustomStructure register(String name, File file) { + if (file == null || name == null) return null; + if (!file.exists()) return null; + return KeyedRegistry.super.register(new CustomStructure(name, file)); + } +} \ No newline at end of file diff --git a/src/main/resources/contents/omc_menus/configs/menus.yml b/src/main/resources/contents/omc_menus/configs/menus.yml index 6732011ac..dff153e67 100644 --- a/src/main/resources/contents/omc_menus/configs/menus.yml +++ b/src/main/resources/contents/omc_menus/configs/menus.yml @@ -61,6 +61,12 @@ 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.event_main_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_event_main_menu.png b/src/main/resources/contents/omc_menus/textures/halloween_event_main_menu.png new file mode 100644 index 0000000000000000000000000000000000000000..18ce06fbdabe3bb1a83cca69e0da4b1af49bda77 GIT binary patch literal 6468 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 O&EMBE1J~*}$NdkYG!B9Q literal 0 HcmV?d00001 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 From 06f3e1c6c1b41285138c56beb0916d54500c1299 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sun, 20 Sep 2026 22:54:02 +0200 Subject: [PATCH 04/44] grosse update, ajout menu shop, bcp de Todo, DB... --- src/main/java/fr/openmc/core/OMCPlugin.java | 1 + .../halloween/halloween/HalloweenManager.java | 29 +++++-- .../dimension/advancement/Advancements.java | 3 +- .../halloween/model/HalloweenDB.java | 31 ++++---- .../halloween/halloween/shop/ShopMoney.java | 3 +- .../halloween/shop/WitchShopItem.java | 7 +- .../halloween/shop/WitchShopManager.java | 73 +++++++++++------- .../shop/menu/WitchShopMainMenu.java | 6 +- .../shop/menu/WitchShopStoreMenu.java | 52 ++++++++----- .../halloween/SEHalloweenManager.java | 29 ------- .../dimension/advancement/Advancements.java | 15 ---- .../halloween/model/SEHalloweenEventData.java | 51 ------------ .../contents/omc_icons/configs/fonts.yml | 30 +++++++ .../textures/font/candy/candy_blue.png | Bin 0 -> 352 bytes .../textures/font/candy/candy_brown.png | Bin 0 -> 454 bytes .../textures/font/candy/candy_green.png | Bin 0 -> 349 bytes .../textures/font/candy/candy_red.png | Bin 0 -> 312 bytes .../textures/font/candy/candy_yellow.png | Bin 0 -> 335 bytes .../textures/items/candy/candy_blue.png | Bin 0 -> 352 bytes .../textures/items/candy/candy_brown.png | Bin 0 -> 454 bytes .../textures/items/candy/candy_green.png | Bin 0 -> 349 bytes .../textures/items/candy/candy_red.png | Bin 0 -> 312 bytes .../textures/items/candy/candy_yellow.png | Bin 0 -> 335 bytes .../contents/omc_menus/configs/menus.yml | 2 +- 24 files changed, 160 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java create mode 100644 src/main/resources/contents/omc_icons/textures/font/candy/candy_blue.png create mode 100644 src/main/resources/contents/omc_icons/textures/font/candy/candy_brown.png create mode 100644 src/main/resources/contents/omc_icons/textures/font/candy/candy_green.png create mode 100644 src/main/resources/contents/omc_icons/textures/font/candy/candy_red.png create mode 100644 src/main/resources/contents/omc_icons/textures/font/candy/candy_yellow.png create mode 100644 src/main/resources/contents/omc_items/textures/items/candy/candy_blue.png create mode 100644 src/main/resources/contents/omc_items/textures/items/candy/candy_brown.png create mode 100644 src/main/resources/contents/omc_items/textures/items/candy/candy_green.png create mode 100644 src/main/resources/contents/omc_items/textures/items/candy/candy_red.png create mode 100644 src/main/resources/contents/omc_items/textures/items/candy/candy_yellow.png diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 4c3fee7c0..68cf59f5a 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -118,6 +118,7 @@ public class OMCPlugin extends JavaPlugin { MailboxManager::new, DiscordLinkManager::new, ProfileManager::new, + () -> new fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager(), () -> new ElevatorManager(), () -> new CorpseManager(), QuestsManager::new, diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java index fea3ad91a..b331c4c97 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java @@ -8,29 +8,31 @@ import fr.openmc.core.bootstrap.features.types.HasCommands; import fr.openmc.core.bootstrap.features.types.HasDatabase; import fr.openmc.core.bootstrap.features.types.HasListeners; +import fr.openmc.core.bootstrap.features.types.LoadAfterItemsAdder; import fr.openmc.core.bootstrap.integration.OMCLogger; import fr.openmc.core.bootstrap.listeners.ListenerFactory; -import fr.openmc.core.features.corpse.npc.CorpseNPCManager; +import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; import fr.openmc.core.features.events.contents.halloween.halloween.model.HalloweenDB; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopManager; import lombok.Getter; import java.sql.SQLException; import java.util.*; -public class HalloweenManager extends Feature implements HasDatabase, HasListeners, HasCommands { +public class HalloweenManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { @Getter private static HalloweenDB halloweenDB; private static Dao halloweenDao; - public static String[] unlockedRooms; + public static List unlockedRooms; @Override public void init() { - CorpseNPCManager.init(); halloweenDB = loadEvent(); - unlockedRooms = halloweenDB.getContent(); + unlockedRooms = halloweenDB.getUnlockedRooms(); + WitchShopManager.init(); } @Override @@ -46,7 +48,10 @@ protected void save() { public static HalloweenDB loadEvent() { try { - return halloweenDao.queryForFirst(); + HalloweenDB halloweenDB = halloweenDao.queryForFirst(); + if (halloweenDB == null) + halloweenDB = new HalloweenDB(0, List.of(Advancements.ROOM_1.name()), false); + return halloweenDB; } catch (SQLException e) { throw new RuntimeException(e); } @@ -60,6 +65,14 @@ private static void saveEvent() { } } + public static boolean hasUnlock(Advancements advancements) { + return unlockedRooms.contains(advancements.name()); + } + + public static boolean unlockNewRoom(Advancements advancements) { + return unlockedRooms.add(advancements.name()); + } + @Override public Set getListeners() { return Set.of(); @@ -67,6 +80,8 @@ public Set getListeners() { @Override public Set getCommands() { - return Set.of(); + return Set.of( + + ); } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java index 88c2ab606..8c47fa78d 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java @@ -4,7 +4,8 @@ @Getter public enum Advancements { - ROOM_1(1000) + ROOM_1(0), + ROOM_2(1000) ; private final int require; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java index b40d67d40..a80866c35 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java @@ -1,46 +1,51 @@ package fr.openmc.core.features.events.contents.halloween.halloween.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.util.ArrayList; +import java.util.List; + @Getter @DatabaseTable(tableName = "halloween_season_event_data") public class HalloweenDB { - @Setter @DatabaseField(columnName = "advancement") - private String currentAdvancement; + private int currentAdvancement; - @Setter @DatabaseField(columnName = "unlocked_room") private String unlockedRooms; - @Setter @DatabaseField(columnName = "is_active") private boolean active; private static final Gson GSON = new Gson(); public HalloweenDB() { - } - public HalloweenDB(String currentAdvancement, String currentUnlocked, boolean active) { + public HalloweenDB(int currentAdvancement, List unlockedRooms, boolean active) { this.currentAdvancement = currentAdvancement; - this.unlockedRooms = currentUnlocked; + this.unlockedRooms = GSON.toJson(unlockedRooms); this.active = active; } - public void setContent(String[] array) { - unlockedRooms = GSON.toJson(array); + public void setUnlockedRooms(List unlockedRooms) { + this.unlockedRooms = GSON.toJson(unlockedRooms); } - public String[] getContent() { - if (unlockedRooms == null) return new String[0]; - return GSON.fromJson(unlockedRooms, String[].class); - } + public List getUnlockedRooms() { + if (unlockedRooms == null || unlockedRooms.isBlank()) { + return new ArrayList<>(); + } + return GSON.fromJson( + unlockedRooms, + new TypeToken>() {}.getType() + ); + } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java index cf3e688ba..3b3853323 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java @@ -4,7 +4,8 @@ @Getter public enum ShopMoney { - MONSTER_CANDY(WitchShopManager.getMoneyItemIcon("")), + //TODO rajouter les crafts des bonbons et les autre dans le shopMoney + MONSTER_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown")), ; private final String icon; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java index 810b75715..1b9ce1ed4 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java @@ -1,7 +1,9 @@ package fr.openmc.core.features.events.contents.halloween.halloween.shop; +import fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager; import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; import fr.openmc.core.registry.items.CustomItem; +import fr.openmc.core.utils.text.messages.TranslationManager; import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextDecoration; @@ -31,7 +33,8 @@ public WitchShopItem(Advancements advancements, CustomItem item, Component name, } public Component getName() { - // TODO get current advancement - return Component.text("aaaaaaaaaa").decoration(TextDecoration.OBFUSCATED, false); + if (HalloweenManager.hasUnlock(advancements)) + return name; + return Component.text("§knotunlockyet"); } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java index 56957ff40..36b6731ac 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java @@ -1,7 +1,10 @@ package fr.openmc.core.features.events.contents.halloween.halloween.shop; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; +import fr.openmc.core.OMCRegistry; import fr.openmc.core.features.adminshop.AdminShopUtils; +import fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; import fr.openmc.core.utils.bukkit.ItemUtils; import fr.openmc.core.utils.text.messages.MessageType; @@ -29,18 +32,12 @@ public class WitchShopManager { public static int SLOT_FACTOR = 28; private static final Sound BUY_SOUND = Sound.ENTITY_WITCH_CELEBRATE; - public void init() { + public static void init() { witchStoreItems = getWitchStoreItems(); paginateWitchStoreItems = getPaginateWitchStoreItems(); maxPage = getWitchStorePages(); } - private static Set getWitchStoreItems() { - return Set.of( - new WitchShopItem() - ); - } - private static Map> getPaginateWitchStoreItems() { Map> paginateItems = new HashMap<>(); @@ -69,24 +66,24 @@ public static Set getStoreContent(int page) { } private static int getWitchStorePages() { - return witchStoreItems.size() / SLOT_FACTOR; + return (int) Math.ceil((double) witchStoreItems.size() / SLOT_FACTOR); } 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")); + sendError(player, TranslationManager.translation("feature.adminshop.amount_sup")); //TODO return; } if (!ItemUtils.hasEnoughSpace(player, item.getItem().getBest(), amount)) { - sendError(player, TranslationManager.translation("feature.adminshop.inventory_full")); + sendError(player, TranslationManager.translation("feature.adminshop.inventory_full")); //TODO return; } if (item.getPrice() <= 0) { - sendError(player, TranslationManager.translation("feature.adminshop.item_not_sellable")); + sendError(player, TranslationManager.translation("feature.adminshop.item_not_sellable")); //TODO return; } @@ -95,50 +92,74 @@ public static void buyItem(Player player, WitchShopItem item, int amount) { ItemUtils.giveItem(player, item.getItem().getBest(), amount); - sendInfo(player, TranslationManager.translation("feature.adminshop.player_buy_item", + sendInfo(player, TranslationManager.translation("feature.adminshop.player_buy_item", //TODO Component.text(amount), item.getName(), Component.text(AdminShopUtils.formatPrice(totalPrice)) )); - player.playSound(player, BUY_SOUND, 1f, 1f); //TODO random pitch + player.playSound(player, BUY_SOUND, 1f, new Random().nextFloat(0.6f, 1.4f)); } else { sendError(player, TranslationManager.translation("feature.adminshop.have_enough_money")); //TODO } } private static void sendError(Player player, Component message) { - MessagesManager.sendMessage(player, message, Prefix.ADMINSHOP, MessageType.ERROR, true); //TODO prefix + MessagesManager.sendMessage(player, message, Prefix.HALLOWEEN, MessageType.ERROR, true); } private static void sendInfo(Player player, Component message) { - MessagesManager.sendMessage(player, message, Prefix.ADMINSHOP, MessageType.INFO, true); //TODO prefix + MessagesManager.sendMessage(player, message, Prefix.HALLOWEEN, MessageType.INFO, true); } public static List extractLoreForItem(WitchShopItem item) { List lore = new ArrayList<>(); - if (true) { - lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO dire a qu'elle room on le débloque - Component.text(item.getAdvancements().name()) - ).color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); - } // TODO check the item advancement and compare with the currents - else { + if (HalloweenManager.hasUnlock(item.getAdvancements())) { lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO - Component.text(getPrice(item)) + getPrice(item) ).color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); + + } + else { + lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy." + item.getAdvancements().name().toLowerCase()) //TODO change key + .color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); } return lore; } - public static String getPrice(WitchShopItem item) { - return item.getPrice() + " " + item.getShopMoney(); + public static Component getPrice(WitchShopItem item) { + return Component.text(item.getPrice() + " " + item.getShopMoney().getIcon()); } public static String getMoneyItemIcon(String icon) { if (ItemsAdderHook.isEnable()) { - return FontImageWrapper.replaceFontImages("§f:"+icon+":"); //TODO omc_icons + return FontImageWrapper.replaceFontImages("§f:"+icon+":"); } else { - return "Ⓐ"; + return "Ⓐ"; //TODO Translationmanager.translate("<...>." + icon) } } + + //TODO mettre les vrais items + private static LinkedHashSet getWitchStoreItems() { + return new LinkedHashSet<>(List.of( + new WitchShopItem( + Advancements.ROOM_1, + OMCRegistry.CUSTOM_ITEMS.AYWENITE, + OMCRegistry.CUSTOM_ITEMS.AYWENITE.getBest().displayName(), + 10 + ), + new WitchShopItem( + Advancements.ROOM_2, + OMCRegistry.CUSTOM_ITEMS.KEBAB, + OMCRegistry.CUSTOM_ITEMS.KEBAB.getBest().displayName(), + 10 + ), + new WitchShopItem( + Advancements.ROOM_2, + OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER, + OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER.getBest().displayName(), + 1000 + ) + )); + } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java index d31fb770e..26ecb5952 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java @@ -35,7 +35,7 @@ public WitchShopMainMenu(Player owner) { @Override public String getTexture() { - return "§r§f:offset_-48::halloween.event_main_menu:"; + return "§r§f:offset_-48::halloween_event_main_menu:"; } @Override @@ -46,10 +46,6 @@ public String getTexture() { @Override public @NotNull Map getContent() { Map inventory = new HashMap<>(); - Player player = getOwner(); - - City city = CityManager.getPlayerCity(player.getUniqueId()); - assert city != null; // ** Witch House Button WitchHouseButton.init(this, inventory, WITCH_HOUSE_SLOTS); diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java index 470ca207d..a6e92ac56 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java @@ -8,6 +8,7 @@ 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.City; import fr.openmc.core.features.city.CityManager; @@ -68,12 +69,33 @@ public WitchShopStoreMenu(Player owner, int page) { @Override public @NotNull List getStaticSlots() { - return StaticSlots.getBottomSlots(getInventorySize()); + return StaticSlots.getStandardSlots(getInventorySize()); } @Override public List getItems() { - return List.of(); + + List items = new ArrayList<>(); + + Iterator contents = WitchShopManager.getStoreContent(this.page).iterator(); + + for (int c = 0; c < column; c++) { + for (int l = line.floor(); l <= line.ceiling(); l++) { + + if (!contents.hasNext()) break; + + WitchShopItem item = contents.next(); + + items.add(new ItemMenuBuilder(this, item.getItem(), itemMeta -> { + itemMeta.displayName(item.getName()); + itemMeta.lore(WitchShopManager.extractLoreForItem(item)); + }).setOnClick(event -> { + //TODO open confirm menu if has enough moneyItem + })); + } + } + + return items; } @Override @@ -91,33 +113,21 @@ public Map getButtons() { map.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.close")); }).setOnClick(event -> { - //TODO open the WitchShopMainMenu + new WitchShopMainMenu(getOwner()).open(); })); + //TODO filter : + // - room + // - unlocked + // - lower cost + // - highest cost + if (hasNextPage()) { map.put(53, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_NEXT_ORANGE, itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); }).setNextPageButton()); } - Iterator contents = WitchShopManager.getStoreContent(this.page).iterator(); - - for (int c = 0; c < column; c++) { - for (int l = line.floor(); l <= line.ceiling(); l++) { - - if (!contents.hasNext()) break; - - WitchShopItem item = contents.next(); - - map.put(l + (9 * c), new ItemMenuBuilder(this, item.getItem(), itemMeta -> { - itemMeta.displayName(item.getName()); - itemMeta.lore(WitchShopManager.extractLoreForItem(item)); - }).setOnClick(event -> { - //TODO open confirm menu if has enough moneyItem - })); - } - } - return map; } diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java deleted file mode 100644 index 2b9d2545e..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/SEHalloweenManager.java +++ /dev/null @@ -1,29 +0,0 @@ -package fr.openmc.core.features.events.contents.seasonevents.halloween; - -import com.j256.ormlite.support.ConnectionSource; -import fr.openmc.core.bootstrap.features.Feature; -import fr.openmc.core.bootstrap.features.types.HasCommands; -import fr.openmc.core.bootstrap.features.types.HasDatabase; -import fr.openmc.core.bootstrap.features.types.HasListeners; -import fr.openmc.core.bootstrap.listeners.ListenerFactory; - -import java.sql.SQLException; -import java.util.Set; - -public class SEHalloweenManager extends Feature implements HasDatabase, HasListeners, HasCommands { - - @Override - public void initDB(ConnectionSource connectionSource) throws SQLException { - - } - - @Override - public Set getListeners() { - return Set.of(); - } - - @Override - public Set getCommands() { - return Set.of(); - } -} diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java deleted file mode 100644 index 631e5f81d..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/dimension/advancement/Advancements.java +++ /dev/null @@ -1,15 +0,0 @@ -package fr.openmc.core.features.events.contents.seasonevents.halloween.dimension.advancement; - -import lombok.Getter; - -@Getter -public enum Advancements { - ROOM_1(1000) - ; - - private final int require; - - Advancements(int require) { - this.require = require; - } -} diff --git a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java b/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java deleted file mode 100644 index 43b427fa6..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/seasonevents/halloween/model/SEHalloweenEventData.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.openmc.core.features.events.contents.seasonevents.halloween.model; - -import com.google.gson.Gson; -import com.j256.ormlite.field.DatabaseField; -import com.j256.ormlite.table.DatabaseTable; -import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEvent; -import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; -import lombok.Getter; -import lombok.Setter; - -@Getter -@DatabaseTable(tableName = "halloween_season_event_data") -public class SEHalloweenEventData { - - @DatabaseField(id = true, columnName = "id") - private int id = 1; - - @Setter - @DatabaseField(columnName = "advancement") - private String currentAdvencement; - - @Setter - @DatabaseField(columnName = "unlocked_room") - private String currentUnlocked; - - @Setter - @DatabaseField(columnName = "is_active") - private boolean active; - - public SEHalloweenEventData() {} - - public SEHalloweenEventData(WeeklyEvent currentEvent, WeeklyEventPhase currentPhase) { -// this.currentEvent = currentEvent.getId(); -// if (currentPhase == null) -// this.currentPhase = null; -// else -// this.currentPhase = currentPhase.getId(); - } - - private static final Gson GSON = new Gson(); - - public void setContent(String[] array) { - currentUnlocked = GSON.toJson(array); - } - - public String[] getContent() { - if (currentUnlocked == null) return new String[0]; - return GSON.fromJson(currentUnlocked, String[].class); - } - -} diff --git a/src/main/resources/contents/omc_icons/configs/fonts.yml b/src/main/resources/contents/omc_icons/configs/fonts.yml index d72d0d785..81299e65e 100644 --- a/src/main/resources/contents/omc_icons/configs/fonts.yml +++ b/src/main/resources/contents/omc_icons/configs/fonts.yml @@ -30,4 +30,34 @@ font_images: show_in_gui: true path: "font/bits.png" scale_ratio: 12 + y_position: 9 + candy_red: + permission: candy_red + show_in_gui: true + path: "font/candy/candy_red.png" + scale_ratio: 12 + y_position: 9 + candy_yellow: + permission: candy_yellow + show_in_gui: true + path: "font/candy/candy_yellow.png" + scale_ratio: 12 + y_position: 9 + candy_green: + permission: candy_green + show_in_gui: true + path: "font/candy/candy_green.png" + scale_ratio: 12 + y_position: 9 + candy_blue: + permission: candy_blue + show_in_gui: true + path: "font/candy/candy_blue.png" + scale_ratio: 12 + y_position: 9 + candy_brown: + permission: candy_brown + show_in_gui: true + path: "font/candy/candy_brown.png" + scale_ratio: 12 y_position: 9 \ No newline at end of file diff --git a/src/main/resources/contents/omc_icons/textures/font/candy/candy_blue.png b/src/main/resources/contents/omc_icons/textures/font/candy/candy_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..be6fd4e7363c4a12451bd79e7724904683e3d650 GIT binary patch literal 352 zcmV-m0iXVfP)Px$8c9S!R5*=|Q%i2bFc5t~Ea;Bh0D1)H0H}0R#mC?ZtSX^^dX65Wh)sgHfNucd z1SGq3H(glcU+jvJBH1r~Z=Pp784@8xN$y^$V-`C%O%c_{kB>vre?o>#MATe~@acb5 zO+-W#IvbHWLUMDp|3)GqIds9<-C&Uki|iZVeADax7g**t!D^u~4n79}nGhv$!K!yl zSmwa|1<1dEcB}EW1J>V;^ON+uaH!+OWuaJ1;xN$d>^emTBJZHtX#4$Oh5A9;zuXf} zg($r?b%Wo9_MtKEPE|*`@b>E5d1kW#I{SQP&+XSi4U{@&MIjC7wh8bn4**3W&673` yT#?Itd`}j2$pA1KjN~w#q)FuB$;oPx$fJsC_R5*=wld)^UKorKmgc_8B1SdC3Cnuqqf`c83Q0!tCp@Z}<=-92cATFhU zLc5egTb!~eLZ@~paf#q04yA4qL?lJbouD1`j?0<6>F(qGzI*rHoq~ukjM7@%J5E~( z%iD_rZ_k!g)a%&jvXLsowr$bQ`&|GAfYmrxA#dj;n8M(zxm`6ynHzRKN2l;9P2|bOa zKj%hEe~!g$jOnN^Rk{tsD6QRLmrzOxrIh&Igt)^lv1&zP)r#cL9TDG~5K1X=hg~xG zcqBVh5XYp(ll(Mb(>yhvPx$7fD1xR5*>LlRr+wFcijrsn{x{bjz9xAY=}Jpj#Gh&{MFd>|CN17wFP46$hZL zdV!2|OQg2*#{jls$3aLu$&&s2zVH1{7!YF$b>G|VI*Hl!lomMoSbO^BuK1P6fhB3D zN>kyTg-S_M7+DW&B?RwOxxXGs2o9sL-n(K+MwVpBoIM)=F0^Fi&cO}$Txi|f+5sfS z6tV@IQ93|I&NV4dOn9RP;7H9gk6vM~x~VLAiPpyw#bgxK0xKGK9|8k@1OTs8WaONF za$eDJqUA`Px#@<~KNR5*>Llg(|zFbsu12OYo}!7Hc(1j*4$$yq8#1sR}TK_e&|um^>5D9J&A z5->o~e2@PFJL23d@9%ZJ4L!fcsKB4~X6)Z?{zz27A|euk2-wei5fP~~Yr!ftIE3=6 zA!)#M7O&{SQAZA4D?mz{z5@oT3;;sN>1)j?Wj#iCJo=eBH=8j@N_Gk{W}8mO`_2^3 zXIryIgB*PvH@{_RYcadPx$2}wjjR5*>LQ#%gAFbsVK1~$q8Kw@VKNQ?-^9)>FvuE1d!i;!3t=)_(D2Ow-n zfXt94sgo2TVX12B`aM5?5~0R~NT~Xq=bI=L=Q%a-xZW`TXpwv+GGHPik{Qt+{5hvY zMC2;-!P;D~%*-#3!~?r3%IsCsBn`uISpxU1I=>{)9@q?>sq$&laR4GA5;6_zr54a0 z0L>UUbb)c9{Eq@S%~@kxtd{Gld^-)&L;-6Ay#O$|*>epTfTI8ahMAK8mX_!(mHhjT zE7c}M!p20;8=u0XP(D4Ka~haJXI9Y_+iZZ!-imEpf9co4cA?C|mMO3U^&~EM4^yHG h{`)f3-mG7*^9N_eC7BywT|)o>002ovPDHLkV1m>piCO>v literal 0 HcmV?d00001 diff --git a/src/main/resources/contents/omc_items/textures/items/candy/candy_blue.png b/src/main/resources/contents/omc_items/textures/items/candy/candy_blue.png new file mode 100644 index 0000000000000000000000000000000000000000..be6fd4e7363c4a12451bd79e7724904683e3d650 GIT binary patch literal 352 zcmV-m0iXVfP)Px$8c9S!R5*=|Q%i2bFc5t~Ea;Bh0D1)H0H}0R#mC?ZtSX^^dX65Wh)sgHfNucd z1SGq3H(glcU+jvJBH1r~Z=Pp784@8xN$y^$V-`C%O%c_{kB>vre?o>#MATe~@acb5 zO+-W#IvbHWLUMDp|3)GqIds9<-C&Uki|iZVeADax7g**t!D^u~4n79}nGhv$!K!yl zSmwa|1<1dEcB}EW1J>V;^ON+uaH!+OWuaJ1;xN$d>^emTBJZHtX#4$Oh5A9;zuXf} zg($r?b%Wo9_MtKEPE|*`@b>E5d1kW#I{SQP&+XSi4U{@&MIjC7wh8bn4**3W&673` yT#?Itd`}j2$pA1KjN~w#q)FuB$;oPx$fJsC_R5*=wld)^UKorKmgc_8B1SdC3Cnuqqf`c83Q0!tCp@Z}<=-92cATFhU zLc5egTb!~eLZ@~paf#q04yA4qL?lJbouD1`j?0<6>F(qGzI*rHoq~ukjM7@%J5E~( z%iD_rZ_k!g)a%&jvXLsowr$bQ`&|GAfYmrxA#dj;n8M(zxm`6ynHzRKN2l;9P2|bOa zKj%hEe~!g$jOnN^Rk{tsD6QRLmrzOxrIh&Igt)^lv1&zP)r#cL9TDG~5K1X=hg~xG zcqBVh5XYp(ll(Mb(>yhvPx$7fD1xR5*>LlRr+wFcijrsn{x{bjz9xAY=}Jpj#Gh&{MFd>|CN17wFP46$hZL zdV!2|OQg2*#{jls$3aLu$&&s2zVH1{7!YF$b>G|VI*Hl!lomMoSbO^BuK1P6fhB3D zN>kyTg-S_M7+DW&B?RwOxxXGs2o9sL-n(K+MwVpBoIM)=F0^Fi&cO}$Txi|f+5sfS z6tV@IQ93|I&NV4dOn9RP;7H9gk6vM~x~VLAiPpyw#bgxK0xKGK9|8k@1OTs8WaONF za$eDJqUA`Px#@<~KNR5*>Llg(|zFbsu12OYo}!7Hc(1j*4$$yq8#1sR}TK_e&|um^>5D9J&A z5->o~e2@PFJL23d@9%ZJ4L!fcsKB4~X6)Z?{zz27A|euk2-wei5fP~~Yr!ftIE3=6 zA!)#M7O&{SQAZA4D?mz{z5@oT3;;sN>1)j?Wj#iCJo=eBH=8j@N_Gk{W}8mO`_2^3 zXIryIgB*PvH@{_RYcadPx$2}wjjR5*>LQ#%gAFbsVK1~$q8Kw@VKNQ?-^9)>FvuE1d!i;!3t=)_(D2Ow-n zfXt94sgo2TVX12B`aM5?5~0R~NT~Xq=bI=L=Q%a-xZW`TXpwv+GGHPik{Qt+{5hvY zMC2;-!P;D~%*-#3!~?r3%IsCsBn`uISpxU1I=>{)9@q?>sq$&laR4GA5;6_zr54a0 z0L>UUbb)c9{Eq@S%~@kxtd{Gld^-)&L;-6Ay#O$|*>epTfTI8ahMAK8mX_!(mHhjT zE7c}M!p20;8=u0XP(D4Ka~haJXI9Y_+iZZ!-imEpf9co4cA?C|mMO3U^&~EM4^yHG h{`)f3-mG7*^9N_eC7BywT|)o>002ovPDHLkV1m>piCO>v literal 0 HcmV?d00001 diff --git a/src/main/resources/contents/omc_menus/configs/menus.yml b/src/main/resources/contents/omc_menus/configs/menus.yml index dff153e67..411ed932c 100644 --- a/src/main/resources/contents/omc_menus/configs/menus.yml +++ b/src/main/resources/contents/omc_menus/configs/menus.yml @@ -65,7 +65,7 @@ font_images: permission: halloween.event_main_menu show_in_gui: true suggestion_in_command: false - path: "halloween.event_main_menu.png" + path: "halloween_event_main_menu.png" y_position: 30 home_mailbox: permission: mailbox.home From 38bf0e49c9bb04a22d981d888686b575061d42b3 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 22 Sep 2026 12:32:29 +0200 Subject: [PATCH 05/44] move items and font to omc_halloween + SquareRegion --- .../halloween/commands/HalloweenCommands.java | 7 ++ .../halloween/halloween/CandyItem.java | 37 ++++++ .../dimension/WitchHouseManager.java | 3 + .../dimension/advancement/HouseRoom.java | 11 ++ .../halloween/listeners/CandyListener.java | 46 ++++++++ .../halloween/halloween/shop/ShopMoney.java | 12 +- .../halloween/shop/WitchShopItem.java | 12 +- .../halloween/shop/WitchShopManager.java | 39 +++---- .../shop/menu/WitchShopMainMenu.java | 10 +- .../shop/menu/buttons/WitchHouseButton.java | 6 +- .../registry/items/CustomItemRegistry.java | 8 ++ .../registry/regions/preset/SquareRegion.java | 59 ++++++++++ .../core/utils/text/messages/Prefix.java | 3 +- .../contents/omc_daily_events/items.yml | 65 +++++++++++ .../textures}/candy/candy_blue.png | Bin .../textures}/candy/candy_brown.png | Bin .../textures}/candy/candy_green.png | Bin .../textures}/candy/candy_red.png | Bin .../textures}/candy/candy_yellow.png | Bin .../contents/omc_halloween/configs/fonts.yml | 33 ++++++ .../contents/omc_halloween/configs/items.yml | 110 ++++++++++++++++++ .../textures}/candy/candy_blue.png | Bin .../textures}/candy/candy_brown.png | Bin .../textures}/candy/candy_green.png | Bin .../textures}/candy/candy_red.png | Bin .../textures}/candy/candy_yellow.png | Bin .../contents/omc_icons/configs/fonts.yml | 30 ----- .../textures/halloween_event_main_menu.png | Bin 6468 -> 7203 bytes 28 files changed, 419 insertions(+), 72 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java create mode 100644 src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java rename src/main/resources/contents/{omc_icons/textures/font => omc_daily_events/textures}/candy/candy_blue.png (100%) rename src/main/resources/contents/{omc_icons/textures/font => omc_daily_events/textures}/candy/candy_brown.png (100%) rename src/main/resources/contents/{omc_icons/textures/font => omc_daily_events/textures}/candy/candy_green.png (100%) rename src/main/resources/contents/{omc_icons/textures/font => omc_daily_events/textures}/candy/candy_red.png (100%) rename src/main/resources/contents/{omc_icons/textures/font => omc_daily_events/textures}/candy/candy_yellow.png (100%) create mode 100644 src/main/resources/contents/omc_halloween/configs/fonts.yml create mode 100644 src/main/resources/contents/omc_halloween/configs/items.yml rename src/main/resources/contents/{omc_items/textures/items => omc_halloween/textures}/candy/candy_blue.png (100%) rename src/main/resources/contents/{omc_items/textures/items => omc_halloween/textures}/candy/candy_brown.png (100%) rename src/main/resources/contents/{omc_items/textures/items => omc_halloween/textures}/candy/candy_green.png (100%) rename src/main/resources/contents/{omc_items/textures/items => omc_halloween/textures}/candy/candy_red.png (100%) rename src/main/resources/contents/{omc_items/textures/items => omc_halloween/textures}/candy/candy_yellow.png (100%) 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/commands/HalloweenCommands.java index 11bde75c0..4bc8a71b3 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/commands/HalloweenCommands.java @@ -1,6 +1,8 @@ package fr.openmc.core.features.events.contents.halloween.commands; +import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.WitchShopMainMenu; import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import org.bukkit.entity.Player; import revxrsal.commands.annotation.Command; import revxrsal.commands.annotation.Subcommand; import revxrsal.commands.bukkit.annotation.CommandPermission; @@ -12,4 +14,9 @@ public class HalloweenCommands { public void endHalloweenCommand() { HalloweenManager.endEvent(); } + + @Subcommand("test") + public void tst(Player player) { + new WitchShopMainMenu(player).open(); + } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java new file mode 100644 index 000000000..ea0698f7e --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java @@ -0,0 +1,37 @@ +package fr.openmc.core.features.events.contents.halloween.halloween; + +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("feature." + super.getId().replace(":", ".") + ".name") + )); + return item; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java index 3b0e0e870..e96a767fc 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java @@ -1,4 +1,7 @@ package fr.openmc.core.features.events.contents.halloween.halloween.dimension; public class WitchHouseManager { + + + } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java new file mode 100644 index 000000000..653e97276 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java @@ -0,0 +1,11 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement; + +import fr.openmc.core.registry.regions.types.Region; + +public class HouseRoom { + + public Region region; + + + +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java new file mode 100644 index 000000000..0170731a1 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java @@ -0,0 +1,46 @@ +package fr.openmc.core.features.events.contents.halloween.halloween.listeners; + +import dev.lone.itemsadder.api.CustomStack; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.features.events.contents.halloween.halloween.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 java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class CandyListener implements Listener { + + private final Map diabetes = 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 diabete = diabetes.computeIfAbsent(uuid, key -> 0); + + diabete += candy.getDiabetesIndex(); + + if (diabete >= 20) { + //TODO faire un truc + diabetes.put(uuid, 0); + } else + diabetes.put(uuid, diabete); + } + +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java index 3b3853323..e16e67881 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java @@ -1,16 +1,24 @@ package fr.openmc.core.features.events.contents.halloween.halloween.shop; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.registry.items.CustomItem; import lombok.Getter; @Getter public enum ShopMoney { //TODO rajouter les crafts des bonbons et les autre dans le shopMoney - MONSTER_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown")), + RED_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_RED), + YELLOW_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW), + GREEN_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN), + BLUE_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE), + MONSTER_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN), ; private final String icon; + private final CustomItem item; - ShopMoney(String icon) { + ShopMoney(String icon, CustomItem item) { this.icon = icon; + this.item = item; } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java index 1b9ce1ed4..31e1ecbd7 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java @@ -3,10 +3,8 @@ import fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager; import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; import fr.openmc.core.registry.items.CustomItem; -import fr.openmc.core.utils.text.messages.TranslationManager; import lombok.Getter; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.TextDecoration; public class WitchShopItem { @@ -25,11 +23,11 @@ public WitchShopItem(Advancements advancements, CustomItem item, Component name, this.price = price; } public WitchShopItem(Advancements advancements, CustomItem item, Component name, int price) { - this.advancements = advancements; - this.item = item; - this.name = name; - this.shopMoney = ShopMoney.MONSTER_CANDY; - this.price = price; + this(advancements, item, name, ShopMoney.MONSTER_CANDY, price); + } + + public WitchShopItem(Advancements advancements, CustomItem item, int price) { + this(advancements, item, item.getBest().displayName(), price); } public Component getName() { diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java index 36b6731ac..64573ea10 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java @@ -21,16 +21,14 @@ public class WitchShopManager { - //TODO idée : - // bruit de sorcière quand on buy un item - - public static Set witchStoreItems; + 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(); @@ -104,6 +102,7 @@ public static void buyItem(Player player, WitchShopItem item, int amount) { 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) { @@ -141,25 +140,17 @@ public static String getMoneyItemIcon(String icon) { //TODO mettre les vrais items private static LinkedHashSet getWitchStoreItems() { - return new LinkedHashSet<>(List.of( - new WitchShopItem( - Advancements.ROOM_1, - OMCRegistry.CUSTOM_ITEMS.AYWENITE, - OMCRegistry.CUSTOM_ITEMS.AYWENITE.getBest().displayName(), - 10 - ), - new WitchShopItem( - Advancements.ROOM_2, - OMCRegistry.CUSTOM_ITEMS.KEBAB, - OMCRegistry.CUSTOM_ITEMS.KEBAB.getBest().displayName(), - 10 - ), - new WitchShopItem( - Advancements.ROOM_2, - OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER, - OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER.getBest().displayName(), - 1000 - ) - )); + LinkedHashSet items = new LinkedHashSet<>(); + + items.add(new WitchShopItem( + Advancements.ROOM_1, OMCRegistry.CUSTOM_ITEMS.AYWENITE, 10)); + + items.add(new WitchShopItem( + Advancements.ROOM_2, OMCRegistry.CUSTOM_ITEMS.KEBAB, 10)); + + items.add(new WitchShopItem( + Advancements.ROOM_2, OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER, 1000)); + + return items; } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java index 26ecb5952..3b0b700be 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java @@ -3,13 +3,11 @@ 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.city.City; -import fr.openmc.core.features.city.CityManager; -import fr.openmc.core.features.city.menu.main.buttons.*; import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.buttons.WitchHouseButton; import fr.openmc.core.features.events.contents.halloween.halloween.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; @@ -21,8 +19,9 @@ public class WitchShopMainMenu extends Menu { - private static final int[] WITCH_HOUSE_SLOTS = {8, 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_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); @@ -63,7 +62,8 @@ public List getTakableSlot() { @Override public void onClose(InventoryCloseEvent event) { - //TODO bruit de sorcière + Player player = getOwner(); + player.playSound(player, WITCH_MENU_CLOSE, 1f, 1f); } @Override diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java index d53ef41f4..73d49c62f 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java @@ -26,9 +26,9 @@ public static void init(Menu menu, Map contents, int[] Component.text("").color(NamedTextColor.LIGHT_PURPLE) )); itemMeta.setItemModel(NamespacedKey.minecraft("air")); - }).setOnClick(inventoryClickEvent -> { //TODO tp dans la dimension - - }) + }).setCloseButton()//.setOnClick(inventoryClickEvent -> { //TODO tp dans la dimension +// inventoryClickEvent.getClickedInventory().close(); +// }) ); } } 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 597c02ab5..d44d5d2f4 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.halloween.CandyItem; import fr.openmc.core.features.itemsadder.elevator.ElevatorBlock; import fr.openmc.core.features.itemsadder.elevator.ElevatorColor; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; @@ -194,6 +195,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); 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..ab809e99b --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java @@ -0,0 +1,59 @@ +package fr.openmc.core.registry.regions.preset; + +import com.sk89q.worldedit.math.BlockVector3; +import fr.openmc.core.registry.regions.CustomRegion; +import net.kyori.adventure.key.Key; +import org.bukkit.World; + +public class SquareRegion extends CustomRegion { + + public World world; + public BlockVector3 min; + public BlockVector3 max; + public Key key; + + public SquareRegion(World world, BlockVector3 min, BlockVector3 max) { + this(world, min, max, null); + } + + public SquareRegion(World world, BlockVector3 min, BlockVector3 max, Key key) { + this.world = world; + this.min = min; + this.max = max; + this.key = key; + } + + @Override + public Key getKey() { + return key; + } + + @Override + public World getWorld() { + return world; + } + + @Override + public boolean contains(BlockVector3 pos) { + double x = pos.x(); + double y = pos.y(); + double z = pos.z(); + + return x >= Math.min(getMin().x(), getMax().x()) && + x <= Math.max(getMin().x(), getMax().x()) && + y >= Math.min(getMin().y(), getMax().y()) && + y <= Math.max(getMin().y(), getMax().y()) && + z >= Math.min(getMin().z(), getMax().z()) && + z <= Math.max(getMin().z(), getMax().z()); + } + + @Override + public BlockVector3 getMin() { + return min; + } + + @Override + public BlockVector3 getMax() { + return max; + } +} 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/resources/contents/omc_daily_events/items.yml b/src/main/resources/contents/omc_daily_events/items.yml index 8bd96d2aa..f96c925bf 100644 --- a/src/main/resources/contents/omc_daily_events/items.yml +++ b/src/main/resources/contents/omc_daily_events/items.yml @@ -66,6 +66,71 @@ 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: + - + consumable: + nutrition: 1 + saturation: 0.6 + recipes: iaa_crafting_table: fermentum: diff --git a/src/main/resources/contents/omc_icons/textures/font/candy/candy_blue.png b/src/main/resources/contents/omc_daily_events/textures/candy/candy_blue.png similarity index 100% rename from src/main/resources/contents/omc_icons/textures/font/candy/candy_blue.png rename to src/main/resources/contents/omc_daily_events/textures/candy/candy_blue.png diff --git a/src/main/resources/contents/omc_icons/textures/font/candy/candy_brown.png b/src/main/resources/contents/omc_daily_events/textures/candy/candy_brown.png similarity index 100% rename from src/main/resources/contents/omc_icons/textures/font/candy/candy_brown.png rename to src/main/resources/contents/omc_daily_events/textures/candy/candy_brown.png diff --git a/src/main/resources/contents/omc_icons/textures/font/candy/candy_green.png b/src/main/resources/contents/omc_daily_events/textures/candy/candy_green.png similarity index 100% rename from src/main/resources/contents/omc_icons/textures/font/candy/candy_green.png rename to src/main/resources/contents/omc_daily_events/textures/candy/candy_green.png diff --git a/src/main/resources/contents/omc_icons/textures/font/candy/candy_red.png b/src/main/resources/contents/omc_daily_events/textures/candy/candy_red.png similarity index 100% rename from src/main/resources/contents/omc_icons/textures/font/candy/candy_red.png rename to src/main/resources/contents/omc_daily_events/textures/candy/candy_red.png diff --git a/src/main/resources/contents/omc_icons/textures/font/candy/candy_yellow.png b/src/main/resources/contents/omc_daily_events/textures/candy/candy_yellow.png similarity index 100% rename from src/main/resources/contents/omc_icons/textures/font/candy/candy_yellow.png rename to src/main/resources/contents/omc_daily_events/textures/candy/candy_yellow.png 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..040fa93ed --- /dev/null +++ b/src/main/resources/contents/omc_halloween/configs/items.yml @@ -0,0 +1,110 @@ +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: + - + consumable: + nutrition: 1 + saturation: 0.6 + +recipes: + iaa_crafting_table: + fermentum: + shapeless: true + ingredients: + - item: omc_daily_events:golden_wheat + amount: 5 + - item: omc_daily_events:golden_beetroot + amount: 5 + - item: omc_daily_events:really_golden_carrot + amount: 5 + - item: omc_daily_events:golden_potato + amount: 5 + - item: omc_daily_events:golden_melon + amount: 5 + - item: omc_daily_events:golden_pumpkin + amount: 5 + result: + item: omc_daily_events:fermentum + + blessed_bread: + enabled: true + pattern: + - FFF + - XXX + - XXX + pattern_2: + - XXX + - FFF + - XXX + pattern_3: + - XXX + - XXX + - FFF + ingredients: + F: + item: omc_daily_events:golden_wheat + amount: 192 + result: + item: omc_daily_events:blessed_bread + amount: 1 \ No newline at end of file diff --git a/src/main/resources/contents/omc_items/textures/items/candy/candy_blue.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_blue.png similarity index 100% rename from src/main/resources/contents/omc_items/textures/items/candy/candy_blue.png rename to src/main/resources/contents/omc_halloween/textures/candy/candy_blue.png diff --git a/src/main/resources/contents/omc_items/textures/items/candy/candy_brown.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_brown.png similarity index 100% rename from src/main/resources/contents/omc_items/textures/items/candy/candy_brown.png rename to src/main/resources/contents/omc_halloween/textures/candy/candy_brown.png diff --git a/src/main/resources/contents/omc_items/textures/items/candy/candy_green.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_green.png similarity index 100% rename from src/main/resources/contents/omc_items/textures/items/candy/candy_green.png rename to src/main/resources/contents/omc_halloween/textures/candy/candy_green.png diff --git a/src/main/resources/contents/omc_items/textures/items/candy/candy_red.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_red.png similarity index 100% rename from src/main/resources/contents/omc_items/textures/items/candy/candy_red.png rename to src/main/resources/contents/omc_halloween/textures/candy/candy_red.png diff --git a/src/main/resources/contents/omc_items/textures/items/candy/candy_yellow.png b/src/main/resources/contents/omc_halloween/textures/candy/candy_yellow.png similarity index 100% rename from src/main/resources/contents/omc_items/textures/items/candy/candy_yellow.png rename to src/main/resources/contents/omc_halloween/textures/candy/candy_yellow.png diff --git a/src/main/resources/contents/omc_icons/configs/fonts.yml b/src/main/resources/contents/omc_icons/configs/fonts.yml index 81299e65e..2a214f727 100644 --- a/src/main/resources/contents/omc_icons/configs/fonts.yml +++ b/src/main/resources/contents/omc_icons/configs/fonts.yml @@ -31,33 +31,3 @@ font_images: path: "font/bits.png" scale_ratio: 12 y_position: 9 - candy_red: - permission: candy_red - show_in_gui: true - path: "font/candy/candy_red.png" - scale_ratio: 12 - y_position: 9 - candy_yellow: - permission: candy_yellow - show_in_gui: true - path: "font/candy/candy_yellow.png" - scale_ratio: 12 - y_position: 9 - candy_green: - permission: candy_green - show_in_gui: true - path: "font/candy/candy_green.png" - scale_ratio: 12 - y_position: 9 - candy_blue: - permission: candy_blue - show_in_gui: true - path: "font/candy/candy_blue.png" - scale_ratio: 12 - y_position: 9 - candy_brown: - permission: candy_brown - show_in_gui: true - path: "font/candy/candy_brown.png" - scale_ratio: 12 - y_position: 9 \ No newline at end of file diff --git a/src/main/resources/contents/omc_menus/textures/halloween_event_main_menu.png b/src/main/resources/contents/omc_menus/textures/halloween_event_main_menu.png index 18ce06fbdabe3bb1a83cca69e0da4b1af49bda77..dbf83e2ba8813b03f1533842b3b37645910c99a0 100644 GIT binary patch literal 7203 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 delta 6174 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 From c0195857ae2644ebabaf183b13a0b902b05516fa Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 22 Sep 2026 12:34:43 +0200 Subject: [PATCH 06/44] remove doublon --- .../textures/candy/candy_blue.png | Bin 352 -> 0 bytes .../textures/candy/candy_brown.png | Bin 454 -> 0 bytes .../textures/candy/candy_green.png | Bin 349 -> 0 bytes .../omc_daily_events/textures/candy/candy_red.png | Bin 312 -> 0 bytes .../textures/candy/candy_yellow.png | Bin 335 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/resources/contents/omc_daily_events/textures/candy/candy_blue.png delete mode 100644 src/main/resources/contents/omc_daily_events/textures/candy/candy_brown.png delete mode 100644 src/main/resources/contents/omc_daily_events/textures/candy/candy_green.png delete mode 100644 src/main/resources/contents/omc_daily_events/textures/candy/candy_red.png delete mode 100644 src/main/resources/contents/omc_daily_events/textures/candy/candy_yellow.png diff --git a/src/main/resources/contents/omc_daily_events/textures/candy/candy_blue.png b/src/main/resources/contents/omc_daily_events/textures/candy/candy_blue.png deleted file mode 100644 index be6fd4e7363c4a12451bd79e7724904683e3d650..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 352 zcmV-m0iXVfP)Px$8c9S!R5*=|Q%i2bFc5t~Ea;Bh0D1)H0H}0R#mC?ZtSX^^dX65Wh)sgHfNucd z1SGq3H(glcU+jvJBH1r~Z=Pp784@8xN$y^$V-`C%O%c_{kB>vre?o>#MATe~@acb5 zO+-W#IvbHWLUMDp|3)GqIds9<-C&Uki|iZVeADax7g**t!D^u~4n79}nGhv$!K!yl zSmwa|1<1dEcB}EW1J>V;^ON+uaH!+OWuaJ1;xN$d>^emTBJZHtX#4$Oh5A9;zuXf} zg($r?b%Wo9_MtKEPE|*`@b>E5d1kW#I{SQP&+XSi4U{@&MIjC7wh8bn4**3W&673` yT#?Itd`}j2$pA1KjN~w#q)FuB$;oPx$fJsC_R5*=wld)^UKorKmgc_8B1SdC3Cnuqqf`c83Q0!tCp@Z}<=-92cATFhU zLc5egTb!~eLZ@~paf#q04yA4qL?lJbouD1`j?0<6>F(qGzI*rHoq~ukjM7@%J5E~( z%iD_rZ_k!g)a%&jvXLsowr$bQ`&|GAfYmrxA#dj;n8M(zxm`6ynHzRKN2l;9P2|bOa zKj%hEe~!g$jOnN^Rk{tsD6QRLmrzOxrIh&Igt)^lv1&zP)r#cL9TDG~5K1X=hg~xG zcqBVh5XYp(ll(Mb(>yhvPx$7fD1xR5*>LlRr+wFcijrsn{x{bjz9xAY=}Jpj#Gh&{MFd>|CN17wFP46$hZL zdV!2|OQg2*#{jls$3aLu$&&s2zVH1{7!YF$b>G|VI*Hl!lomMoSbO^BuK1P6fhB3D zN>kyTg-S_M7+DW&B?RwOxxXGs2o9sL-n(K+MwVpBoIM)=F0^Fi&cO}$Txi|f+5sfS z6tV@IQ93|I&NV4dOn9RP;7H9gk6vM~x~VLAiPpyw#bgxK0xKGK9|8k@1OTs8WaONF za$eDJqUA`Px#@<~KNR5*>Llg(|zFbsu12OYo}!7Hc(1j*4$$yq8#1sR}TK_e&|um^>5D9J&A z5->o~e2@PFJL23d@9%ZJ4L!fcsKB4~X6)Z?{zz27A|euk2-wei5fP~~Yr!ftIE3=6 zA!)#M7O&{SQAZA4D?mz{z5@oT3;;sN>1)j?Wj#iCJo=eBH=8j@N_Gk{W}8mO`_2^3 zXIryIgB*PvH@{_RYcadPx$2}wjjR5*>LQ#%gAFbsVK1~$q8Kw@VKNQ?-^9)>FvuE1d!i;!3t=)_(D2Ow-n zfXt94sgo2TVX12B`aM5?5~0R~NT~Xq=bI=L=Q%a-xZW`TXpwv+GGHPik{Qt+{5hvY zMC2;-!P;D~%*-#3!~?r3%IsCsBn`uISpxU1I=>{)9@q?>sq$&laR4GA5;6_zr54a0 z0L>UUbb)c9{Eq@S%~@kxtd{Gld^-)&L;-6Ay#O$|*>epTfTI8ahMAK8mX_!(mHhjT zE7c}M!p20;8=u0XP(D4Ka~haJXI9Y_+iZZ!-imEpf9co4cA?C|mMO3U^&~EM4^yHG h{`)f3-mG7*^9N_eC7BywT|)o>002ovPDHLkV1m>piCO>v From aa660011b397bb031b54672d16573e666e585fdc Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 13 Oct 2026 22:34:14 +0200 Subject: [PATCH 07/44] add getRandom for list --- .../fr/openmc/core/utils/RandomUtils.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 From f51c89fd4027f11e2c1231664c0420d9f626649f Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 13 Oct 2026 22:34:42 +0200 Subject: [PATCH 08/44] little change to Region --- .../regions/content/ExampleRegion.java | 5 +++++ .../registry/regions/preset/SquareRegion.java | 20 ++++++++++++++----- .../regions/types/SphericalRegion.java | 2 -- 3 files changed, 20 insertions(+), 7 deletions(-) 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 83db314d4..ccc55591d 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 getMin() { public BlockVector3 getMax() { 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 index ab809e99b..921aa00ed 100644 --- a/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java @@ -2,6 +2,7 @@ import com.sk89q.worldedit.math.BlockVector3; import fr.openmc.core.registry.regions.CustomRegion; +import fr.openmc.core.utils.MathUtils; import net.kyori.adventure.key.Key; import org.bukkit.World; @@ -12,14 +13,14 @@ public class SquareRegion extends CustomRegion { public BlockVector3 max; public Key key; - public SquareRegion(World world, BlockVector3 min, BlockVector3 max) { - this(world, min, max, null); + public SquareRegion(World world, BlockVector3 corner1, BlockVector3 corner2) { + this(world, corner1, corner2, null); } - public SquareRegion(World world, BlockVector3 min, BlockVector3 max, Key key) { + public SquareRegion(World world, BlockVector3 corner1, BlockVector3 corner2, Key key) { this.world = world; - this.min = min; - this.max = max; + min = corner1.getMinimum(corner2); + max = corner1.getMaximum(corner2); this.key = key; } @@ -56,4 +57,13 @@ public BlockVector3 getMin() { public BlockVector3 getMax() { return max; } + + @Override + public BlockVector3 getCenter() { + return new BlockVector3( + (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 2a9a6a97c..d886ef907 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 From 92bddc17ed5038fc81008122a8eb8cac083056da Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 13 Oct 2026 22:35:39 +0200 Subject: [PATCH 09/44] little change to Region 2 --- src/main/java/fr/openmc/core/registry/regions/CustomRegion.java | 1 + 1 file changed, 1 insertion(+) 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 ce85d7a4a..491ae4fdc 100644 --- a/src/main/java/fr/openmc/core/registry/regions/CustomRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/CustomRegion.java @@ -12,6 +12,7 @@ public abstract class CustomRegion { public abstract boolean contains(BlockVector3 pos); public abstract BlockVector3 getMin(); public abstract BlockVector3 getMax(); + public abstract BlockVector3 getCenter(); public final boolean contains(Location loc) { if (loc == null || loc.getWorld() == null) return false; From 99fb67d69effb867aa7576d08cbb2e9a223e88ae Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 13 Oct 2026 22:36:59 +0200 Subject: [PATCH 10/44] implementation of better structure with WEHook --- .../fr/openmc/core/hooks/WorldEditHook.java | 32 ++ .../registry/structures/CustomStructure.java | 327 ++++++++++++++++-- .../structures/CustomStructureRegistry.java | 10 +- .../model/CustomStructureManager.java | 79 +++++ .../structures/model/DBPlacedStructure.java | 48 +++ 5 files changed, 455 insertions(+), 41 deletions(-) create mode 100644 src/main/java/fr/openmc/core/hooks/WorldEditHook.java create mode 100644 src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java create mode 100644 src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java 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/registry/structures/CustomStructure.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java index 9c5741f0d..4bc9e05f7 100644 --- a/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java @@ -1,69 +1,320 @@ 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.regions.Region; +import com.sk89q.worldedit.session.ClipboardHolder; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.registry.structures.model.CustomStructureManager; +import fr.openmc.core.registry.structures.model.DBPlacedStructure; import lombok.Getter; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtAccounter; -import net.minecraft.nbt.NbtIo; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Mirror; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; -import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; +import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.World; +import org.bukkit.structure.Structure; +import org.bukkit.util.BlockVector; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.InputStream; +import java.io.IOException; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +/** + * Une structure réutilisable (ex: "maison"). Elle peut être posée autant de fois qu'on veut, + * chaque placement étant identifié par son propre UUID. + */ public class CustomStructure { + // Format utilisé pour stocker les undos en DB + private static final ClipboardFormat BACKUP_FORMAT = BuiltInClipboardFormat.SPONGE_V3_SCHEMATIC; + + private final OMCPlugin plugin = OMCPlugin.getInstance(); @Getter - String id; - File file; + private final String id; + private final File file; // .schem / .schematic / .nbt public CustomStructure(String id, File file) { this.id = id; this.file = file; } - public void placeStructure(Location origin, boolean mirrorX, boolean mirrorZ) { - ServerLevel level = ((CraftWorld) origin.getWorld()).getHandle(); + // ------------------------------------------------------------------ PLACE + + /** Pose la structure avec un UUID de placement généré. */ + public CompletableFuture place(Location location) { + + if (!CustomStructureManager.actionAllow()) return null; + + return place(UUID.randomUUID(), location); + } + + /** + * Pose la structure en lui donnant un identifiant UUID. + * Échoue si cet UUID est déjà utilisé par un placement existant. + * Peut être appelé depuis n'importe quel thread. + * + * @return le même UUID, une fois la structure posée et l'undo sauvegardé + */ + public CompletableFuture place(UUID placementId, Location location) { + + if (!CustomStructureManager.actionAllow()) return null; + + CompletableFuture future = new CompletableFuture<>(); + final Location loc = location.clone(); + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + try { + if (CustomStructureManager.existsPlacement(placementId)) { + future.completeExceptionally(new IllegalStateException( + "Le placement " + placementId + " existe déjà")); + return; + } + } catch (Exception e) { + future.completeExceptionally(e); + return; + } + + Bukkit.getScheduler().runTask(plugin, () -> { + final DBPlacedStructure entry; + try { + entry = pasteWithBackup(placementId, loc); + } catch (Exception e) { + future.completeExceptionally(e); + return; + } + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + try { + CustomStructureManager.savePlacement(entry); + future.complete(placementId); + } catch (Exception e) { + OMCLogger.error("Structure posée mais undo non sauvegardé !", e); + future.completeExceptionally(e); + } + }); + }); + }); + return future; + } + + private DBPlacedStructure pasteWithBackup(UUID placementId, Location loc) throws Exception { + + if (!CustomStructureManager.actionAllow()) return null; + + Clipboard structure = readFile(file); + com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(loc.getWorld()); + + // Zone du monde qui sera écrasée + BlockVector3 to = BukkitAdapter.asBlockVector(loc); + BlockVector3 offset = to.subtract(structure.getOrigin()); + + Region r = structure.getRegion(); + + BlockVector3 min = r.getMinimumPoint().add(offset); + BlockVector3 max = r.getMaximumPoint().add(offset); + + CuboidRegion area = new CuboidRegion(weWorld, min, max); + + try (EditSession session = WorldEdit.getInstance().newEditSession(weWorld)) { + // 1) sauvegarde de l'existant + BlockArrayClipboard backup = new BlockArrayClipboard(area); + ForwardExtentCopy copy = new ForwardExtentCopy(session, area, backup, min); + copy.setCopyingEntities(false); + Operations.complete(copy); + + // 2) collage + Operations.complete(new ClipboardHolder(structure) + .createPaste(session) + .to(to) + .ignoreAirBlocks(false) + .build()); + + return new DBPlacedStructure(placementId, id, loc.getWorld().getUID().toString(), + min.x(), min.y(), min.z(), serialize(backup)); + } + } + + /** Retire UN placement précis grâce à son UUID. + * @return false si introuvable. + */ + public CompletableFuture remove(UUID placementId) { - try (InputStream in = new FileInputStream(file)) { + if (!CustomStructureManager.actionAllow()) return null; + + return removeInternal(() -> CustomStructureManager.getPlacement(placementId)); + } - CompoundTag tag = NbtIo.readCompressed(in, NbtAccounter.unlimitedHeap()); + /** Retire le placement le plus récent de cette structure. */ + public CompletableFuture removeLast() { + return removeInternal(() -> CustomStructureManager.getLatestPlacement(id)); + } - StructureTemplate template = new StructureTemplate(); + /** Retire TOUS les placements de cette structure (du plus récent au plus ancien). @return le nombre retiré */ + public CompletableFuture removeAll() { - template.load( - level.registryAccess().lookupOrThrow(Registries.BLOCK), - tag - ); + if (!CustomStructureManager.actionAllow()) return null; - StructurePlaceSettings settings = new StructurePlaceSettings(); + return list().thenCompose(placements -> { + CompletableFuture chain = CompletableFuture.completedFuture(0); + for (DBPlacedStructure p : placements) { + chain = chain.thenCompose(count -> + remove(p.getId()).thenApply(ok -> ok ? count + 1 : count)); + } + return chain; + }); + } - if (mirrorX) settings.setMirror(Mirror.FRONT_BACK); - if (mirrorZ) settings.setMirror(Mirror.LEFT_RIGHT); + /** Tous les placements de cette structure, du plus récent au plus ancien. */ + public CompletableFuture> list() { + CompletableFuture> f = new CompletableFuture<>(); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + try { f.complete(CustomStructureManager.getPlacements(id)); } + catch (Exception e) { f.completeExceptionally(e); } + }); + return f; + } - settings.setRotation(Rotation.NONE); + public CompletableFuture exists(UUID placementId) { + CompletableFuture f = new CompletableFuture<>(); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + try { f.complete(CustomStructureManager.existsPlacement(placementId)); } + catch (Exception e) { f.completeExceptionally(e); } + }); + return f; + } - BlockPos pos = new BlockPos(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ()); + private interface Lookup { DBPlacedStructure get() throws Exception; } - template.placeInWorld( - level, - pos, - pos, - settings, - level.getRandom(), - 2 - ); + private CompletableFuture removeInternal(Lookup lookup) { + if (!CustomStructureManager.actionAllow()) return null; + + CompletableFuture future = new CompletableFuture<>(); + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + // 1) lecture DB + final DBPlacedStructure placed; + try { + placed = lookup.get(); + } catch (Exception e) { future.completeExceptionally(e); return; } + if (placed == null) { future.complete(false); return; } + + Bukkit.getScheduler().runTask(plugin, () -> { + // 2) restauration (main thread) + try { + World world = Bukkit.getWorld(UUID.fromString(placed.getWorld())); + if (world == null) throw new IllegalStateException("Monde introuvable"); + restore(placed, world); + } catch (Exception e) { future.completeExceptionally(e); return; } + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + // 3) suppression de la ligne + try { + CustomStructureManager.deletePlacement(placed.getId()); + future.complete(true); + } catch (Exception e) { future.completeExceptionally(e); } + }); + }); + }); + return future; + } + + private void restore(DBPlacedStructure placed, World world) throws Exception { + + if (!CustomStructureManager.actionAllow()) return; + + Clipboard backup = deserialize(placed.getBackup()); + backup.setOrigin(backup.getRegion().getMinimumPoint()); + BlockVector3 min = BlockVector3.at(placed.getX(), placed.getY(), placed.getZ()); + + try (EditSession session = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) { + Operations.complete(new ClipboardHolder(backup) + .createPaste(session) + .to(min) + .ignoreAirBlocks(false) // remet aussi l'air + .build()); + } + } + + /** Lit un .schem / .schematic via WorldEdit, ou un .nbt vanilla converti en clipboard WorldEdit. */ + private static Clipboard readFile(File file) throws IOException { + + if (!CustomStructureManager.actionAllow()) return null; + + if (file.getName().toLowerCase().endsWith(".nbt")) { + return readNbt(file); + } + ClipboardFormat format = ClipboardFormats.findByFile(file); + if (format == null) throw new IOException("Format de schematic inconnu : " + file.getName()); + try (ClipboardReader reader = format.getReader(new FileInputStream(file))) { + return reader.read(); + } + } + + /** + * Convertit un .nbt (structure block) en clipboard WorldEdit, sans rien placer dans le monde. + * Limites : le contenu des tile entities (coffres, panneaux...) et les entités ne sont pas conservés. + */ + private static Clipboard readNbt(File file) throws IOException { + + if (!CustomStructureManager.actionAllow()) return null; + + Structure structure = Bukkit.getStructureManager().loadStructure(file); + if (structure.getPaletteCount() == 0) throw new IOException("Structure vide : " + file.getName()); + + BlockVector size = structure.getSize(); + CuboidRegion region = new CuboidRegion( + BlockVector3.ZERO, + BlockVector3.at(size.getBlockX() - 1, size.getBlockY() - 1, size.getBlockZ() - 1)); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(BlockVector3.ZERO); + + try { + for (org.bukkit.block.BlockState state : structure.getPalettes().get(0).getBlocks()) { + BlockVector3 pos = BlockVector3.at(state.getX(), state.getY(), state.getZ()); + clipboard.setBlock(pos, BukkitAdapter.adapt(state.getBlockData())); + } } catch (Exception e) { - e.printStackTrace(); + throw new IOException("Conversion du .nbt impossible : " + file.getName(), e); } + return clipboard; } -} + private static byte[] serialize(Clipboard clipboard) throws IOException { + + if (!CustomStructureManager.actionAllow()) return null; + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try (ClipboardWriter writer = BACKUP_FORMAT.getWriter(out)) { + writer.write(clipboard); + } + return out.toByteArray(); + } + + private static Clipboard deserialize(byte[] data) throws IOException { + + if (!CustomStructureManager.actionAllow()) return null; + + try (ClipboardReader reader = BACKUP_FORMAT.getReader(new ByteArrayInputStream(data))) { + return reader.read(); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java index 002f6a35b..5487afe73 100644 --- a/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java @@ -1,19 +1,23 @@ package fr.openmc.core.registry.structures; import fr.openmc.core.OMCPlugin; +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 fr.openmc.core.utils.FilesUtils; import java.io.File; public class CustomStructureRegistry extends Registry - implements KeyedRegistry { + implements KeyedRegistry, LoadIfEnable { private static final File structureFolder = new File(OMCPlugin.getInstance().getDataFolder(), "data/omc_structure"); + public static final String structureKey = "omc_structure"; + // ** REGISTER STRUCTURES ** - public final CustomStructure TEST = register("omc_structure:test","pillar.nbt"); + public final CustomStructure WITCH_SHOP = register("test","pillar.nbt"); public CustomStructureRegistry() { FilesUtils.createDirectoryIfNotExists(structureFolder); @@ -31,6 +35,6 @@ public CustomStructure register(String name, String fileName) { public CustomStructure register(String name, File file) { if (file == null || name == null) return null; if (!file.exists()) return null; - return KeyedRegistry.super.register(new CustomStructure(name, file)); + return KeyedRegistry.super.register(new CustomStructure((structureKey + name), file)); } } \ No newline at end of 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..992a7fb98 --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java @@ -0,0 +1,79 @@ +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.bootstrap.features.Feature; +import fr.openmc.core.bootstrap.features.types.HasDatabase; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.hooks.WorldEditHook; + +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +/** + * Feature qui porte uniquement la table des undos de structures. + * Les accès DB sont synchrones : à appeler hors du thread principal (voir CustomStructure). + */ +public class CustomStructureManager extends Feature implements HasDatabase { + + private static Dao dao; + + public static boolean WELoaded = false; + + @Override + public void init() { + WELoaded = WorldEditHook.isEnable(); + } + + @Override + public void initDB(ConnectionSource connectionSource) throws SQLException { + TableUtils.createTableIfNotExists(connectionSource, DBPlacedStructure.class); + dao = DaoManager.createDao(connectionSource, DBPlacedStructure.class); + } + +// @Override +// protected void save() { +// +// } + + public static void savePlacement(DBPlacedStructure p) throws SQLException { + dao.create(p); + } + + public static DBPlacedStructure getPlacement(UUID id) throws SQLException { + return dao.queryForId(id); + } + + public static boolean existsPlacement(UUID id) throws SQLException { + return dao.idExists(id); + } + + public static DBPlacedStructure getLatestPlacement(String structureId) throws SQLException { + return dao.queryBuilder() + .orderBy("createdAt", false) + .where().eq("structureId", structureId) + .queryForFirst(); + } + + /** Du plus récent au plus ancien. */ + public static List getPlacements(String structureId) throws SQLException { + return dao.queryBuilder() + .orderBy("createdAt", false) + .where().eq("structureId", structureId) + .query(); + } + + public static void deletePlacement(UUID id) throws SQLException { + dao.deleteById(id); + } + + public static boolean actionAllow() { + if (!WELoaded) + OMCLogger.warn("Action prevent from use because WE or FAWE not enable"); + return WELoaded; + } +} + 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..96c1c21db --- /dev/null +++ b/src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java @@ -0,0 +1,48 @@ +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; + +/** Une instance de structure posée dans le monde + la sauvegarde de ce qu'il y avait avant (undo). */ +@Getter +@DatabaseTable(tableName = "structures_placed") +public class DBPlacedStructure { + + /** Identifiant unique de CE placement (pas de la structure). */ + @DatabaseField(id = true, dataType = DataType.UUID) + private UUID id; + + /** Id de la CustomStructure (ex: "maison"). Plusieurs placements peuvent avoir le même. */ + @DatabaseField(canBeNull = false, index = true) + private String structureId; + + @DatabaseField(canBeNull = false) + private String world; // UUID du monde + + // Coin minimum de la zone sauvegardée + @DatabaseField private int x; + @DatabaseField private int y; + @DatabaseField private int z; + + @DatabaseField(dataType = DataType.BYTE_ARRAY, canBeNull = false) + private byte[] backup; // schematic WorldEdit de la zone AVANT placement + + @DatabaseField private long createdAt; + + public DBPlacedStructure() {} // requis par 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(); + } + +} From d5594524ae1c41f942344fd1f4a0d14a800655fb Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 13 Oct 2026 22:37:55 +0200 Subject: [PATCH 11/44] move package --- .../features/displays/scoreboards/sb/MainScoreboard.java | 2 +- .../{ => pumpkin}/commands/HalloweenCommands.java | 6 +++--- .../{ => pumpkin}/listeners/HalloweenNPCListener.java | 4 ++-- .../{ => pumpkin}/managers/HalloweenManager.java | 8 ++++---- .../{ => pumpkin}/menus/HalloweenPumpkinDepositMenu.java | 4 ++-- .../halloween/{ => pumpkin}/models/HalloweenData.java | 2 +- .../leaderboards/PumpkinCountLeaderBoard.java | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{ => pumpkin}/commands/HalloweenCommands.java (66%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{ => pumpkin}/listeners/HalloweenNPCListener.java (81%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{ => pumpkin}/managers/HalloweenManager.java (96%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{ => pumpkin}/menus/HalloweenPumpkinDepositMenu.java (95%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{ => pumpkin}/models/HalloweenData.java (89%) 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 f953efcde..f876cad0c 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,7 +12,7 @@ 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.contents.weeklyevents.WeeklyEventsManager; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.Contest; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; 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 66% 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 4bc8a71b3..9d931fb51 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,7 +1,7 @@ -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.halloween.shop.menu.WitchShopMainMenu; -import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopMainMenu; +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; 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/leaderboards/leaderboards/PumpkinCountLeaderBoard.java b/src/main/java/fr/openmc/core/features/leaderboards/leaderboards/PumpkinCountLeaderBoard.java index 9e05cf110..543564f56 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 @@ -1,8 +1,8 @@ package fr.openmc.core.features.leaderboards.leaderboards; 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; From c88abcbc9092ee6d92ee2c3fdcc4b34fd94d88f6 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Tue, 13 Oct 2026 22:39:39 +0200 Subject: [PATCH 12/44] big update for the events, add menus, floor and mob management... --- src/main/java/fr/openmc/core/OMCPlugin.java | 4 +- .../{halloween => festival}/CandyItem.java | 2 +- .../halloween/festival/HalloweenManager.java | 140 ++++++++++++++++++ .../listeners/CandyListener.java | 17 +-- .../listeners/WitchHouseListener.java | 56 +++++++ .../model/HalloweenDB.java | 3 +- .../shop/ShopMoney.java | 2 +- .../shop/WitchShopItem.java | 14 +- .../shop/WitchShopManager.java | 12 +- .../shop/menu/ConfirmMenu.java | 10 +- .../shop/menu/WitchShopMainMenu.java | 6 +- .../shop/menu/WitchShopStoreMenu.java | 21 +-- .../shop/menu/buttons/WitchHouseButton.java | 2 +- .../shop/menu/buttons/WitchStoreButton.java | 11 +- .../witchhouse/DimensionGenerator.java} | 23 +-- .../witchhouse/WitchHouseManager.java | 114 ++++++++++++++ .../witchhouse/advancement/Floor.java | 110 ++++++++++++++ .../witchhouse/advancement/Floors.java | 31 ++++ .../advancement/menu/AdvancementMenu.java | 63 ++++++++ .../advancement/menu/RewardsMenu.java | 63 ++++++++ .../witchhouse/ambient/WitchHouseAmbient.java | 60 ++++++++ .../mobs/floor1_3/HouseZombieLV1.java | 65 ++++++++ .../halloween/halloween/HalloweenManager.java | 87 ----------- .../dimension/WitchHouseManager.java | 7 - .../dimension/advancement/Advancements.java | 16 -- .../dimension/advancement/HouseRoom.java | 11 -- .../ambient/CustomAmbientRegistry.java | 2 + src/main/resources/data/witch_house_spawn.yml | 5 + 28 files changed, 751 insertions(+), 206 deletions(-) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/CandyItem.java (93%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/listeners/CandyListener.java (64%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/model/HalloweenDB.java (93%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/ShopMoney.java (92%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/WitchShopItem.java (56%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/WitchShopManager.java (91%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/menu/ConfirmMenu.java (95%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/menu/WitchShopMainMenu.java (88%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/menu/WitchShopStoreMenu.java (83%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/menu/buttons/WitchHouseButton.java (94%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween => festival}/shop/menu/buttons/WitchStoreButton.java (70%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/{halloween/dimension/DimensionManager.java => festival/witchhouse/DimensionGenerator.java} (74%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floor.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/AdvancementMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardsMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/WitchHouseAmbient.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java create mode 100644 src/main/resources/data/witch_house_spawn.yml diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 3a10bd5e4..1ed3cf097 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -35,7 +35,7 @@ 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.pumpkin.managers.HalloweenManager; import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestParticlesUtils; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; @@ -118,7 +118,7 @@ public class OMCPlugin extends JavaPlugin { MailboxManager::new, DiscordLinkManager::new, ProfileManager::new, - () -> new fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager(), + () -> new fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager(), () -> new ElevatorManager(), () -> new CorpseManager(), QuestsManager::new, diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/CandyItem.java similarity index 93% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/CandyItem.java index ea0698f7e..341a7d473 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/CandyItem.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/CandyItem.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.halloween; +package fr.openmc.core.features.events.contents.halloween.festival; import fr.openmc.core.registry.items.CustomItem; import fr.openmc.core.registry.items.CustomItemMeta; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java new file mode 100644 index 000000000..844ce2b2d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java @@ -0,0 +1,140 @@ +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.core.OMCPlugin; +import fr.openmc.core.OMCRegistry; +import fr.openmc.core.bootstrap.features.Feature; +import fr.openmc.core.bootstrap.features.types.HasCommands; +import fr.openmc.core.bootstrap.features.types.HasDatabase; +import fr.openmc.core.bootstrap.features.types.HasListeners; +import fr.openmc.core.bootstrap.features.types.LoadAfterItemsAdder; +import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.bootstrap.listeners.ListenerFactory; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.Floors; +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 lombok.Getter; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.sql.SQLException; +import java.util.*; + +public class HalloweenManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { + + //TODO quand acheter truc dans shop, augmenté avancement bonbons pour débloqué les étages, quand tous les étages débloqué, faire obtenir des récompenses a tous les joueurs ayant contribué + + @Getter + private static HalloweenDB halloweenDB; + + private static Dao halloweenDao; + + public static List unlockedFloors; + + private static File witchHouseSpawnFile; + private static FileConfiguration witchHouseSpawnConfig; + private static Location pasteLocation; + + @Override + public void init() { + witchHouseSpawnFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "witch_house_spawn.yml"); + loadWitchHouseSpawnConfig(); + + halloweenDB = loadEvent(); + unlockedFloors = halloweenDB.getUnlockedRooms(); + WitchShopManager.init(); + } + + @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, List.of(Floors.FLOOR_1.name()), false); + return halloweenDB; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + private static void loadWitchHouseSpawnConfig() { + if(!witchHouseSpawnFile.exists()) { + witchHouseSpawnFile.getParentFile().mkdirs(); + OMCPlugin.getInstance().saveResource("data/witch_house_spawn.yml", false); + } + + witchHouseSpawnConfig = YamlConfiguration.loadConfiguration(witchHouseSpawnFile); + loadPasteLocation(); + } + + private static void loadPasteLocation() { + if (witchHouseSpawnConfig.contains("spawn")) { + World world = OMCPlugin.getInstance().getServer().getWorld(witchHouseSpawnConfig.getString("spawn.world", "world")); + double x = witchHouseSpawnConfig.getDouble("spawn.x", 0.0); + double y = witchHouseSpawnConfig.getDouble("spawn.Y", 0.0); + double z = witchHouseSpawnConfig.getDouble("spawn.z", 0.0); + + pasteLocation = new Location( + world, + x, + y, + z + ); + } + } + + private static void saveEvent() { + try { + halloweenDao.createOrUpdate(halloweenDB); + } catch (Exception e) { + OMCLogger.error("Impossible de sauvegarder l'event d'halloween pendant l'arret.", e); + } + } + + public static boolean hasUnlock(Floors floor) { + return unlockedFloors.contains(floor.name()); + } + + public static boolean unlockNewRoom(Floors floor) { + return unlockedFloors.add(floor.name()); + } + + public static void placeWitchShop() { + OMCRegistry.CUSTOM_STRUCTURES.WITCH_SHOP.place(pasteLocation); + } + + public static void removeWitchShop() { + OMCRegistry.CUSTOM_STRUCTURES.WITCH_SHOP.removeAll(); + } + + @Override + public Set getListeners() { + return Set.of( + CandyListener::new + ); + } + + @Override + public Set getCommands() { + return Set.of( + + ); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/CandyListener.java similarity index 64% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/CandyListener.java index 0170731a1..74e12212b 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/listeners/CandyListener.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/CandyListener.java @@ -1,8 +1,7 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.listeners; +package fr.openmc.core.features.events.contents.halloween.festival.listeners; import dev.lone.itemsadder.api.CustomStack; -import fr.openmc.core.OMCRegistry; -import fr.openmc.core.features.events.contents.halloween.halloween.CandyItem; +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; @@ -15,7 +14,7 @@ public class CandyListener implements Listener { - private final Map diabetes = new HashMap<>(); + private final Map sugarIndex = new HashMap<>(); @EventHandler public void onCandyEat(PlayerItemConsumeEvent event) { @@ -32,15 +31,15 @@ public void onCandyEat(PlayerItemConsumeEvent event) { UUID uuid = player.getUniqueId(); - int diabete = diabetes.computeIfAbsent(uuid, key -> 0); + int sugarIdx = sugarIndex.computeIfAbsent(uuid, key -> 0); - diabete += candy.getDiabetesIndex(); + sugarIdx += candy.getDiabetesIndex(); - if (diabete >= 20) { + if (sugarIdx >= 20) { //TODO faire un truc - diabetes.put(uuid, 0); + sugarIndex.put(uuid, 0); } else - diabetes.put(uuid, diabete); + sugarIndex.put(uuid, sugarIdx); } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java new file mode 100644 index 000000000..66921e57a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java @@ -0,0 +1,56 @@ +package fr.openmc.core.features.events.contents.halloween.festival.listeners; + +import fr.openmc.core.commands.utils.SpawnManager; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.WitchHouseManager; +import fr.openmc.core.registry.regions.CustomRegion; +import fr.openmc.core.registry.regions.events.EntityCustomRegionEnterEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; + +public class WitchHouseListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + if (!player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) return; + + player.teleport(SpawnManager.getSpawnLocation()); + // TODO message + } + + @EventHandler + public void onWorldChange(PlayerChangedWorldEvent event) { + Player player = event.getPlayer(); + + if (HalloweenManager.getHalloweenDB().isActive()) { + if (event.getFrom().equals(DimensionGenerator.HALLOWEEN_WORLD)) + WitchHouseManager.getWitchHouseAmbient().reset(player); + + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + WitchHouseManager.getWitchHouseAmbient().apply(player); + } else { + if (player.isOp()) return; + + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) { + player.teleport(SpawnManager.getSpawnLocation()); + // TODO message + } + } + } + + @EventHandler + public void onHouseRegionEnter(EntityCustomRegionEnterEvent event) { + CustomRegion region = event.getRegion(); + + if (!WitchHouseManager.enabledRegions.contains(region)) return; + + if (event.getEntity() instanceof Player player) + WitchHouseManager.repulsePlayer(region, player, 0.3); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/model/HalloweenDB.java similarity index 93% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/model/HalloweenDB.java index a80866c35..f4af72b57 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/model/HalloweenDB.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/model/HalloweenDB.java @@ -1,11 +1,10 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.model; +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.util.ArrayList; import java.util.List; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java similarity index 92% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java index e16e67881..11a18206e 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/ShopMoney.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop; +package fr.openmc.core.features.events.contents.halloween.festival.shop; import fr.openmc.core.OMCRegistry; import fr.openmc.core.registry.items.CustomItem; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopItem.java similarity index 56% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopItem.java index 31e1ecbd7..a56308d15 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopItem.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopItem.java @@ -1,32 +1,32 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop; +package fr.openmc.core.features.events.contents.halloween.festival.shop; -import fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager; -import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.Floors; import fr.openmc.core.registry.items.CustomItem; import lombok.Getter; import net.kyori.adventure.text.Component; public class WitchShopItem { - @Getter public final Advancements advancements; + @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(Advancements advancements, CustomItem item, Component name, ShopMoney moneyItem, 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(Advancements advancements, CustomItem item, Component name, int price) { + public WitchShopItem(Floors advancements, CustomItem item, Component name, int price) { this(advancements, item, name, ShopMoney.MONSTER_CANDY, price); } - public WitchShopItem(Advancements advancements, CustomItem item, int price) { + public WitchShopItem(Floors advancements, CustomItem item, int price) { this(advancements, item, item.getBest().displayName(), price); } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopManager.java similarity index 91% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopManager.java index 64573ea10..6277c97cb 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/WitchShopManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/WitchShopManager.java @@ -1,10 +1,10 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop; +package fr.openmc.core.features.events.contents.halloween.festival.shop; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; import fr.openmc.core.OMCRegistry; import fr.openmc.core.features.adminshop.AdminShopUtils; -import fr.openmc.core.features.events.contents.halloween.halloween.HalloweenManager; -import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; +import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.Floors; import fr.openmc.core.hooks.itemsadder.ItemsAdderHook; import fr.openmc.core.utils.bukkit.ItemUtils; import fr.openmc.core.utils.text.messages.MessageType; @@ -143,13 +143,13 @@ private static LinkedHashSet getWitchStoreItems() { LinkedHashSet items = new LinkedHashSet<>(); items.add(new WitchShopItem( - Advancements.ROOM_1, OMCRegistry.CUSTOM_ITEMS.AYWENITE, 10)); + Floors.FLOOR_1, OMCRegistry.CUSTOM_ITEMS.AYWENITE, 10)); items.add(new WitchShopItem( - Advancements.ROOM_2, OMCRegistry.CUSTOM_ITEMS.KEBAB, 10)); + Floors.FLOOR_2, OMCRegistry.CUSTOM_ITEMS.KEBAB, 10)); items.add(new WitchShopItem( - Advancements.ROOM_2, OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER, 1000)); + Floors.FLOOR_2, OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER, 1000)); return items; } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmMenu.java similarity index 95% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmMenu.java index e2bda17a3..97837946a 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/ConfirmMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmMenu.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu; +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; import fr.openmc.api.input.dialog.DialogInput; @@ -7,18 +7,14 @@ import fr.openmc.api.menulib.utils.ItemMenuBuilder; import fr.openmc.core.OMCRegistry; import fr.openmc.core.features.adminshop.AdminShopManager; -import fr.openmc.core.features.adminshop.ShopItem; -import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopItem; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopManager; +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.Material; -import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopMainMenu.java similarity index 88% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopMainMenu.java index 3b0b700be..f4a4a4a52 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopMainMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopMainMenu.java @@ -1,10 +1,10 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu; +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; 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.halloween.shop.menu.buttons.WitchHouseButton; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.buttons.WitchStoreButton; +import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons.WitchHouseButton; +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; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopStoreMenu.java similarity index 83% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopStoreMenu.java index a6e92ac56..99efe1557 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/WitchShopStoreMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchShopStoreMenu.java @@ -1,28 +1,18 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu; +package fr.openmc.core.features.events.contents.halloween.festival.shop.menu; 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.MenuUtils; 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.City; -import fr.openmc.core.features.city.CityManager; -import fr.openmc.core.features.city.CityPermission; -import fr.openmc.core.features.city.actions.CityChestAction; -import fr.openmc.core.features.city.menu.CityChestMenu; -import fr.openmc.core.features.city.sub.milestone.rewards.ChestPageLimitRewards; -import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopItem; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopManager; +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.utils.text.messages.TranslationManager; import lombok.Getter; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.world.level.levelgen.Column; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -30,16 +20,11 @@ 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.*; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static fr.openmc.core.features.city.conditions.CityChestConditions.*; public class WitchShopStoreMenu extends PaginatedMenu { diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchHouseButton.java similarity index 94% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchHouseButton.java index 73d49c62f..64b45c17e 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchHouseButton.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchHouseButton.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.buttons; +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; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchStoreButton.java similarity index 70% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchStoreButton.java index 0266329a2..b9e3c8ba1 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/shop/menu/buttons/WitchStoreButton.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchStoreButton.java @@ -1,15 +1,9 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.buttons; +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.city.City; -import fr.openmc.core.features.city.sub.milestone.rewards.FeaturesRewards; -import fr.openmc.core.features.city.sub.rank.menus.CityRanksMenu; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.menu.WitchShopStoreMenu; -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.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; @@ -17,7 +11,6 @@ import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; -import java.util.List; import java.util.Map; public class WitchStoreButton { diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/DimensionGenerator.java similarity index 74% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/DimensionGenerator.java index ac7c714df..6c078369e 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/DimensionManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/DimensionGenerator.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.dimension; +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse; import fr.openmc.core.bootstrap.integration.OMCLogger; import org.bukkit.Bukkit; @@ -6,7 +6,7 @@ import org.bukkit.World; import org.bukkit.entity.SpawnCategory; -public class DimensionManager { +public class DimensionGenerator { public static final String DIMENSION_NAME = "world_omc_halloween_witch_house"; public static World HALLOWEEN_WORLD; @@ -15,13 +15,8 @@ public static void init() { HALLOWEEN_WORLD = Bukkit.getWorld(DIMENSION_NAME); setupDimension(); -// loadRegions(); } - //TODO setup la dimension : - // - monde vide + ajout de la structure de Mcross - // - ambiant custom - private static void setupDimension() { if (!HALLOWEEN_WORLD.getName().equals(DIMENSION_NAME)) return; @@ -48,19 +43,9 @@ private static void setupDimension() { // ** SET WORLD BORDER AND TIME ** HALLOWEEN_WORLD.getWorldBorder().setSize(500); HALLOWEEN_WORLD.setTime(14000); + HALLOWEEN_WORLD.setThundering(true); + HALLOWEEN_WORLD.setStorm(true); OMCLogger.infoFormatted("Dimension de la Maison de la Sorcière setup (gamerules, worldborder, time)"); } - - //TODO modifier avec les region de bibi -// private static void loadRegions() { -// MultiRegion multiRegion = new MultiRegion( -// HALLOWEEN_WORLD, -// new SquareRegion(0.0, 60.0, 0.0, 6.0, 70.0, 3.0, HALLOWEEN_WORLD), -// new SquareRegion(0.0, 60.0, 6.0, 3.0, 70.0, 3.0, HALLOWEEN_WORLD) -// ); -// -// multiRegion.addDetection(); -// } - } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java new file mode 100644 index 000000000..4afb4a314 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java @@ -0,0 +1,114 @@ +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.witchhouse.advancement.Floors; +import fr.openmc.core.registry.ambient.CustomAmbient; +import fr.openmc.core.registry.regions.CustomRegion; +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.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; +import org.bukkit.util.Vector; + +import java.util.List; + +public class WitchHouseManager { + + public Floors currentFloor; + public static List enabledRegions; //TODO add values to it + public int floorAdvancement; + public boolean finalRoomReach; + + BukkitTask spawnTimeTask; + + @Getter + public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.WITCH_HOUSE; + + public WitchHouseManager(Floors advancements, int countAdvancement) { + currentFloor = advancements; + this.floorAdvancement = countAdvancement; + finalRoomReach = currentFloor.equals(Floors.FLOOR_2); //TODO last floor FLOOR_15 + } + + public void updateAdvancement(int increase) { + floorAdvancement += increase; + + if (currentFloor.getRequire() > floorAdvancement) { + return; + } + int currentRoom = Integer.parseInt(currentFloor.name().replaceFirst(".*\\D", "")); + + currentRoom++; + + currentFloor = Floors.valueOf("FLOOR_" + currentRoom); + + //TODO broadcast + } + + public void prepareSpawn() { + // entre 1m et 1m30 -> dire que l'on peut spawn vague de mob, avec int min et int max + // selon l'étage plus de mob + ou - dure + + spawnTimeTask = Bukkit.getScheduler().runTaskAsynchronously(OMCPlugin.getInstance(), + () -> { + // dire au zone de check pour spawn des mobs, sinon mettre en attente + }); + + + } + + public void delayedSpawnMob() { + + } + + 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(Entity entity, double force) { + repulsePlayer(entity.getLocation(), 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()); + + if (knockback.lengthSquared() < 1.0E-6) { + knockback = playerLocation.getDirection(); + } + + knockback.normalize().multiply(force); + + entity.setVelocity(knockback); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floor.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floor.java new file mode 100644 index 000000000..cb74a6ae9 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floor.java @@ -0,0 +1,110 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.registry.mobs.CustomMobEntry; +import fr.openmc.core.registry.regions.types.Region; +import fr.openmc.core.utils.RandomUtils; +import fr.openmc.core.utils.world.LocationUtils; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.List; + +public record Floor(Region region, List entities, double radius) { + + public void spawnMob(int number) { + for (int n = 0; n < number; n++) { + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), this::spawn, (RandomUtils.randomBetween(2, 7) + n) * 20L); + } + } + + private void spawn() { + + Location spawnLoc = getRandomPosFromPlayer( + getRandomPlayerInRegion() + ); + + new BukkitRunnable() { + private int maxPoints = 30; //gives the amount of time the mob takes to spawn, there it's 30*2 = 60 ticks = 3 seconds + private int points = 1; + + @Override + public void run() { + spawnCircle(spawnLoc, 0.8, points); + + points++; + + if (points >= maxPoints) { + cancel(); + + CustomMobEntry selectEntity = RandomUtils.getRandomObjectFromList(entities); + + selectEntity.spawn(spawnLoc); + } + } + }.runTaskTimer(OMCPlugin.getInstance(), 0L, 2L); + } + + public Player getRandomPlayerInRegion() { + return RandomUtils.getRandomObjectFromList( + OMCPlugin.getInstance().getServer() + .getOnlinePlayers() + .stream() + .filter(p -> region.contains(p.getLocation())) + .toList() + ); + } + + public Location getRandomPosFromPlayer(Player player) { + return LocationUtils.randomLocation( + new Location( + player.getWorld(), + player.getX(), + getFloorPos(player), + player.getZ() + ), + radius + ); + } + + public int getFloorPos(Player player) { + Block block = player.getLocation().getBlock(); + if (player.isFlying() || player.isFlying()) { + int minY = region.getMin().y(); + + while (block.getY() >= minY && block.getType().isAir()) + block = block.getRelative(0, -1, 0); + } + return block.getY() + 1; + } + + public static void spawnCircle(Location center, double radius, int points) { + World world = center.getWorld(); + if (world == null) return; + + for (int i = 0; i < points; i++) { + double angle = 2 * Math.PI * i / points; + + double x = center.getX() + radius * Math.cos(angle); + double z = center.getZ() + radius * Math.sin(angle); + + Location particleLocation = new Location( + world, + x, + center.getY() + 0.05, + z + ); + + world.spawnParticle( + Particle.DUST, + particleLocation, + 1, + 0, 0, 0, + 0, + new Particle.DustOptions(Color.RED, 1.0f) + ); + } + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java new file mode 100644 index 000000000..60938cae3 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java @@ -0,0 +1,31 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement; + +import fr.openmc.core.OMCRegistry; +import lombok.Getter; + +import java.util.List; + +@Getter +public enum Floors { + FLOOR_1(new Floor( + OMCRegistry.CUSTOM_REGIONS.EXAMPLE_REGION, + List.of(), + 3.0 + ), 0), + + FLOOR_2(new Floor( + OMCRegistry.CUSTOM_REGIONS.EXAMPLE_REGION, + List.of(), + 3.0 + ), 1000), + + ; + + private final Floor floor; + private final int require; + + Floors(Floor floor, int require) { + this.floor = floor; + this.require = require; + } +} 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..fc22068bd --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/AdvancementMenu.java @@ -0,0 +1,63 @@ +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.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 AdvancementMenu extends Menu { + + protected AdvancementMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.adminshop.menu.confirm.name");//TODO + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-11::adminshop:");//TODO jar avec des bonbons, faire selon l'avancement ? ( en vrai ouais ) + } + + @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, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); + + 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/RewardsMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardsMenu.java new file mode 100644 index 000000000..770b952e4 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardsMenu.java @@ -0,0 +1,63 @@ +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.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 RewardsMenu extends Menu { + + protected RewardsMenu(Player owner) { + super(owner); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.adminshop.menu.confirm.name");//TODO + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-11::adminshop:");//TODO + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.NORMAL; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) { + + } + + @Override + public @NotNull Map getContent() { + Map content = new HashMap<>(); + + content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); + + 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/ambient/WitchHouseAmbient.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/WitchHouseAmbient.java new file mode 100644 index 000000000..052154ed6 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/WitchHouseAmbient.java @@ -0,0 +1,60 @@ +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 WitchHouseAmbient extends CustomAmbient { + @Override + public String getId() { + return "witch_house_ambient"; + } + + @Override + public AmbientBuilder getAmbientBuilder() { + return new AmbientBuilder(CustomAmbientRegistry.NAMESPACE, this.getId()) + .attributesBuilder(new EnvironnementAttributeBuilder() + .attributes(obj -> { + obj.addProperty("visual/sky_light_color", "#FAED5C"); + obj.addProperty("visual/ambient_light_color", "#001A19"); + + 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", 512); + obj.addProperty("visual/fog_color", "#3C374A"); + obj.addProperty("visual/water_fog_color", "#3D2E42"); + + obj.addProperty("visual/cloud_height", 240); + }) + .ambientParticles(Particle.WITCH, 0.02) + .ambientParticles(Particle.DRAGON_BREATH, 0.02) +// .ambientSounds(new AmbientSoundBuilder() +// .additions(new AmbientSoundBuilder.AdditionsBuilder() +// .sound("minecraft:ambient.underwater.loop.additions.rare") +// .tickChance(0.001) +// ) +// ) + ) + .ambientLight(0.2f) + .skybox(DimensionType.Skybox.OVERWORLD) + .hasSkylight(true) + .waterColor("#604f7d") + .defaultClock("overworld") + .timelines("#minecraft:in_overworld") + .hasFixedTime(true, 200) + .hasPrecipitation(true, WeatherType.RAIN); + } + + @Override + public ResourceKey getTransitionDimension() { + return Level.END; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java new file mode 100644 index 000000000..447527858 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java @@ -0,0 +1,65 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.floor1_3; + +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.WitchHouseManager; +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.inventory.ItemStack; + +import java.util.List; + +public class HouseZombieLV1 extends CustomMob { + + double RADIUS = 3.0; + + public HouseZombieLV1(String id) { + super(id, + TranslationManager.translation("feature.dailyevents.miraculousfishing.mob.ancient_villager"), //TODO + Zombie.class, + 100, + 67, + List.of( + new XpLoot(100, 150, 0.5) //TODO ajouté les bonbons + ) + ); + } + + @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 + ) + )); + + zombie.getNearbyEntities(RADIUS, RADIUS, RADIUS).stream() + .filter(entity -> entity instanceof Player) + .forEach(player -> WitchHouseManager.repulsePlayer(player, 0.3f)); + + return zombie; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java deleted file mode 100644 index b331c4c97..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/HalloweenManager.java +++ /dev/null @@ -1,87 +0,0 @@ -package fr.openmc.core.features.events.contents.halloween.halloween; - -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.bootstrap.features.Feature; -import fr.openmc.core.bootstrap.features.types.HasCommands; -import fr.openmc.core.bootstrap.features.types.HasDatabase; -import fr.openmc.core.bootstrap.features.types.HasListeners; -import fr.openmc.core.bootstrap.features.types.LoadAfterItemsAdder; -import fr.openmc.core.bootstrap.integration.OMCLogger; -import fr.openmc.core.bootstrap.listeners.ListenerFactory; -import fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement.Advancements; -import fr.openmc.core.features.events.contents.halloween.halloween.model.HalloweenDB; -import fr.openmc.core.features.events.contents.halloween.halloween.shop.WitchShopManager; -import lombok.Getter; - -import java.sql.SQLException; -import java.util.*; - -public class HalloweenManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { - - @Getter - private static HalloweenDB halloweenDB; - - private static Dao halloweenDao; - - public static List unlockedRooms; - - @Override - public void init() { - halloweenDB = loadEvent(); - unlockedRooms = halloweenDB.getUnlockedRooms(); - WitchShopManager.init(); - } - - @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, List.of(Advancements.ROOM_1.name()), false); - return halloweenDB; - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - - private static void saveEvent() { - try { - halloweenDao.createOrUpdate(halloweenDB); - } catch (Exception e) { - OMCLogger.error("Impossible de sauvegarder les corpses pendant l'arret.", e); - } - } - - public static boolean hasUnlock(Advancements advancements) { - return unlockedRooms.contains(advancements.name()); - } - - public static boolean unlockNewRoom(Advancements advancements) { - return unlockedRooms.add(advancements.name()); - } - - @Override - public Set getListeners() { - return Set.of(); - } - - @Override - public Set getCommands() { - return Set.of( - - ); - } -} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java deleted file mode 100644 index e96a767fc..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/WitchHouseManager.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.dimension; - -public class WitchHouseManager { - - - -} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java deleted file mode 100644 index 8c47fa78d..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/Advancements.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement; - -import lombok.Getter; - -@Getter -public enum Advancements { - ROOM_1(0), - ROOM_2(1000) - ; - - private final int require; - - Advancements(int require) { - this.require = require; - } -} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java deleted file mode 100644 index 653e97276..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/halloween/dimension/advancement/HouseRoom.java +++ /dev/null @@ -1,11 +0,0 @@ -package fr.openmc.core.features.events.contents.halloween.halloween.dimension.advancement; - -import fr.openmc.core.registry.regions.types.Region; - -public class HouseRoom { - - public Region region; - - - -} 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 a1f88f40b..34d3bab49 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.WitchHouseAmbient; import fr.openmc.core.registry.ambient.contents.DarkAmbient; import fr.openmc.core.registry.ambient.contents.HellAmbient; import fr.openmc.core.registry.ambient.listeners.AmbientFixedTimeListener; @@ -37,6 +38,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 WITCH_HOUSE = register(new WitchHouseAmbient()); @Override public Set getListeners() { diff --git a/src/main/resources/data/witch_house_spawn.yml b/src/main/resources/data/witch_house_spawn.yml new file mode 100644 index 000000000..061641011 --- /dev/null +++ b/src/main/resources/data/witch_house_spawn.yml @@ -0,0 +1,5 @@ +spawn: + world: world # Nom du monde + x: 0.0 # Coordonnées X + y: 0.0 # Coordonnées Y + z: 0.0 # Coordonnées Z \ No newline at end of file From cf590c5137da7db4958a6b55d6c918ef0d3b0659 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Wed, 21 Oct 2026 19:47:08 +0200 Subject: [PATCH 13/44] new menus ( je m'aime ) --- .../contents/omc_menus/configs/menus.yml | 32 +++++++++++++++++- .../halloween/halloween_candy_jare_0.png | Bin 0 -> 5187 bytes .../halloween/halloween_candy_jare_1.png | Bin 0 -> 7105 bytes .../halloween/halloween_candy_jare_2.png | Bin 0 -> 7773 bytes .../halloween/halloween_candy_jare_3.png | Bin 0 -> 8691 bytes .../halloween/halloween_candy_jare_4.png | Bin 0 -> 9364 bytes .../halloween/halloween_deposit_menu.png | Bin 0 -> 4835 bytes .../halloween/halloween_reward_menu.png | Bin 0 -> 5053 bytes .../halloween/halloween_store_menu.png | Bin 0 -> 3836 bytes 9 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_0.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_1.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_2.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_3.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_4.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_deposit_menu.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_reward_menu.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_store_menu.png diff --git a/src/main/resources/contents/omc_menus/configs/menus.yml b/src/main/resources/contents/omc_menus/configs/menus.yml index 411ed932c..476e7bfaa 100644 --- a/src/main/resources/contents/omc_menus/configs/menus.yml +++ b/src/main/resources/contents/omc_menus/configs/menus.yml @@ -65,7 +65,37 @@ font_images: permission: halloween.event_main_menu show_in_gui: true suggestion_in_command: false - path: "halloween_event_main_menu.png" + path: "halloween/halloween_event_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_0 + 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_0 + 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_0 + 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_0 + show_in_gui: true + suggestion_in_command: false + path: "halloween/halloween_candy_jar_4.png" y_position: 30 home_mailbox: permission: mailbox.home diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_0.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_0.png new file mode 100644 index 0000000000000000000000000000000000000000..146c75b21efd717fb3fff0c274de97bd852d289a GIT binary patch literal 5187 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 PUo`%)bb!^EU%mf7pQYc} literal 0 HcmV?d00001 diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_1.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_1.png new file mode 100644 index 0000000000000000000000000000000000000000..389b6f3358702ba7023d93bb592f2efb6a291411 GIT binary patch literal 7105 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 YwH&44lUsqbJ2}8W$5gvs(=qCQ0O@hzWdHyG literal 0 HcmV?d00001 diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_2.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_2.png new file mode 100644 index 0000000000000000000000000000000000000000..8a7abd0a54b262bffa9b32fe44dbe0c562570602 GIT binary patch literal 7773 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 SKsi7LfCu`I^bk6Zk^cu#8bQ_o literal 0 HcmV?d00001 diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_3.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_3.png new file mode 100644 index 0000000000000000000000000000000000000000..538a478dde0600d23e3005823f5cd0a84a8317a4 GIT binary patch literal 8691 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 Lj5M3o9pe5E8VK;* literal 0 HcmV?d00001 diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_4.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_4.png new file mode 100644 index 0000000000000000000000000000000000000000..8bc59f53708269e97a24a3eeb2b335b018736b25 GIT binary patch literal 9364 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 JO2H!h{{Va7Kx+U1 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..eb2013d76fc6108cf18170450fa23133878c7583 GIT binary patch literal 4835 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 AbN~PV literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9a323f872aeab1d950cf466173b9babc5bb1adaf GIT binary patch literal 5053 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 HU7!9BRMOSt literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2d6b4ebd5c8c03069fd769a32649f5a1f1b0352e GIT binary patch literal 3836 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 kKH#kkyq^6puULWd6K2RQ#a)i_ztglk Date: Fri, 23 Oct 2026 17:55:42 +0200 Subject: [PATCH 14/44] Add new utils to EnumUtils --- .../java/fr/openmc/core/utils/EnumUtils.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/main/java/fr/openmc/core/utils/EnumUtils.java b/src/main/java/fr/openmc/core/utils/EnumUtils.java index 87bab40b3..7c8ce70bc 100644 --- a/src/main/java/fr/openmc/core/utils/EnumUtils.java +++ b/src/main/java/fr/openmc/core/utils/EnumUtils.java @@ -1,5 +1,7 @@ package fr.openmc.core.utils; +import java.util.Arrays; +import java.util.List; import java.util.Locale; public class EnumUtils { @@ -32,4 +34,58 @@ 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()) + .toList(); + } + + /** + * 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()) + .toList(); + } + + /** + * 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; + } } From 3b02eda8d10de328017654b9af062c30dc7bdf7d Mon Sep 17 00:00:00 2001 From: Nocolm Date: Fri, 23 Oct 2026 17:59:00 +0200 Subject: [PATCH 15/44] gros commit pour 1er test, j'aurai du en faire des petits arrg --- src/main/java/fr/openmc/core/OMCPlugin.java | 3 +- .../halloween/festival/HalloweenManager.java | 95 +++-- ...Listener.java => TerrorHouseListener.java} | 47 ++- .../halloween/festival/model/HalloweenDB.java | 53 +-- .../halloween/festival/shop/ShopMoney.java | 21 +- .../festival/shop/WitchShopItem.java | 5 +- .../festival/shop/WitchShopManager.java | 63 +++- .../{ConfirmMenu.java => ConfirmBuyMenu.java} | 34 +- .../festival/shop/menu/WitchChoiceMenu.java | 73 ++++ .../festival/shop/menu/WitchShopMainMenu.java | 9 +- .../shop/menu/WitchShopStoreMenu.java | 17 +- .../shop/menu/buttons/ChoiceButton.java | 31 ++ .../shop/menu/buttons/DepositButton.java | 31 ++ ...HouseButton.java => TerorHouseButton.java} | 5 +- .../witchhouse/TerrorHouseManager.java | 181 ++++++++++ .../witchhouse/WitchHouseManager.java | 114 ------ .../witchhouse/advancement/Floors.java | 31 -- .../witchhouse/advancement/PointRewards.java | 24 ++ .../advancement/{ => floor}/Floor.java | 56 ++- .../witchhouse/advancement/floor/Floors.java | 49 +++ .../advancement/menu/AdvancementMenu.java | 38 +- .../advancement/menu/CandyChoiceMenu.java | 98 ++++++ .../advancement/menu/ConfirmSellMenu.java | 227 ++++++++++++ .../{RewardsMenu.java => RewardViewMenu.java} | 24 +- .../advancement/reward/EmptyReward.java | 27 ++ .../advancement/reward/PointReward.java | 15 + .../reward/plush/HalloweenRoot2026.java | 67 ++++ ...seAmbient.java => TerrorHouseAmbient.java} | 2 +- .../mobs/floor1_3/HouseZombieLV1.java | 6 +- .../ambient/CustomAmbientRegistry.java | 4 +- .../registry/items/CustomItemRegistry.java | 3 +- .../regions/CustomRegionRegistry.java | 9 + .../registry/regions/preset/SquareRegion.java | 29 +- .../contents/omc_halloween/configs/items.yml | 26 ++ .../models/items/root_plush.json | 327 ++++++++++++++++++ .../models/root_halloween_plush_texture.png | Bin 0 -> 1968 bytes .../contents/omc_icons/configs/fonts.yml | 6 + .../textures/font/halloween_point.png | Bin 0 -> 444 bytes .../contents/omc_menus/configs/menus.yml | 38 +- .../halloween/halloween_choice_menu.png | Bin 0 -> 5439 bytes .../halloween_purchase_confirm_menu.png | Bin 0 -> 4118 bytes src/main/resources/data/witch_house_spawn.yml | 5 - 42 files changed, 1568 insertions(+), 325 deletions(-) rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/{WitchHouseListener.java => TerrorHouseListener.java} (54%) rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/{ConfirmMenu.java => ConfirmBuyMenu.java} (89%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchChoiceMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/ChoiceButton.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/DepositButton.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/{WitchHouseButton.java => TerorHouseButton.java} (92%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/TerrorHouseManager.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java delete mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/PointRewards.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/{ => floor}/Floor.java (66%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floors.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/CandyChoiceMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/ConfirmSellMenu.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/{RewardsMenu.java => RewardViewMenu.java} (58%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/EmptyReward.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/PointReward.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/plush/HalloweenRoot2026.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/{WitchHouseAmbient.java => TerrorHouseAmbient.java} (97%) create mode 100644 src/main/resources/contents/omc_halloween/models/items/root_plush.json create mode 100644 src/main/resources/contents/omc_halloween/textures/models/root_halloween_plush_texture.png create mode 100644 src/main/resources/contents/omc_icons/textures/font/halloween_point.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_choice_menu.png create mode 100644 src/main/resources/contents/omc_menus/textures/halloween/halloween_purchase_confirm_menu.png delete mode 100644 src/main/resources/data/witch_house_spawn.yml diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 1ed3cf097..47f57d642 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -151,7 +151,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/features/events/contents/halloween/festival/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java index 844ce2b2d..9804c91fc 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java @@ -4,8 +4,9 @@ import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; +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.HasCommands; import fr.openmc.core.bootstrap.features.types.HasDatabase; @@ -13,17 +14,16 @@ import fr.openmc.core.bootstrap.features.types.LoadAfterItemsAdder; import fr.openmc.core.bootstrap.integration.OMCLogger; import fr.openmc.core.bootstrap.listeners.ListenerFactory; -import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.Floors; +import fr.openmc.core.features.events.contents.halloween.festival.listeners.TerrorHouseListener; +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.mailboxes.MailboxManager; import lombok.Getter; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.Bukkit; +import org.bukkit.inventory.ItemStack; -import java.io.File; import java.sql.SQLException; import java.util.*; @@ -36,20 +36,18 @@ public class HalloweenManager extends Feature implements LoadAfterItemsAdder, Ha private static Dao halloweenDao; - public static List unlockedFloors; - - private static File witchHouseSpawnFile; - private static FileConfiguration witchHouseSpawnConfig; - private static Location pasteLocation; + @Getter + private static Set participant; @Override public void init() { - witchHouseSpawnFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "witch_house_spawn.yml"); - loadWitchHouseSpawnConfig(); - halloweenDB = loadEvent(); - unlockedFloors = halloweenDB.getUnlockedRooms(); + participant = halloweenDB.getParticipants(); WitchShopManager.init(); + TerrorHouseManager.init( + halloweenDB.getGlobalAdvancement(), + halloweenDB.getFloorAdvancement() + ); } @Override @@ -66,68 +64,53 @@ protected void save() { public static HalloweenDB loadEvent() { try { HalloweenDB halloweenDB = halloweenDao.queryForFirst(); - if (halloweenDB == null) - halloweenDB = new HalloweenDB(0, List.of(Floors.FLOOR_1.name()), false); + + if (halloweenDB == null) { + halloweenDB = new HalloweenDB(0, 0, false); + halloweenDao.create(halloweenDB); + } + return halloweenDB; } catch (SQLException e) { throw new RuntimeException(e); } } - private static void loadWitchHouseSpawnConfig() { - if(!witchHouseSpawnFile.exists()) { - witchHouseSpawnFile.getParentFile().mkdirs(); - OMCPlugin.getInstance().saveResource("data/witch_house_spawn.yml", false); - } - - witchHouseSpawnConfig = YamlConfiguration.loadConfiguration(witchHouseSpawnFile); - loadPasteLocation(); - } - - private static void loadPasteLocation() { - if (witchHouseSpawnConfig.contains("spawn")) { - World world = OMCPlugin.getInstance().getServer().getWorld(witchHouseSpawnConfig.getString("spawn.world", "world")); - double x = witchHouseSpawnConfig.getDouble("spawn.x", 0.0); - double y = witchHouseSpawnConfig.getDouble("spawn.Y", 0.0); - double z = witchHouseSpawnConfig.getDouble("spawn.z", 0.0); - - pasteLocation = new Location( - world, - x, - y, - z - ); - } - } - 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'arret.", e); + OMCLogger.error( + "Impossible de sauvegarder l'event d'halloween pendant l'arrêt.", + e + ); } } - public static boolean hasUnlock(Floors floor) { - return unlockedFloors.contains(floor.name()); - } - - public static boolean unlockNewRoom(Floors floor) { - return unlockedFloors.add(floor.name()); + public static boolean hasParticipant(UUID uuid) { + return participant.contains(uuid); } - public static void placeWitchShop() { - OMCRegistry.CUSTOM_STRUCTURES.WITCH_SHOP.place(pasteLocation); + public static void addParticipant(UUID uuid) { + participant.add(uuid); } - public static void removeWitchShop() { - OMCRegistry.CUSTOM_STRUCTURES.WITCH_SHOP.removeAll(); + 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); + }); } @Override public Set getListeners() { return Set.of( - CandyListener::new + CandyListener::new, + TerrorHouseListener::new ); } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java similarity index 54% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java index 66921e57a..ee53d9626 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/WitchHouseListener.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java @@ -3,16 +3,19 @@ import fr.openmc.core.commands.utils.SpawnManager; import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.DimensionGenerator; -import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.WitchHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +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.regions.CustomRegion; import fr.openmc.core.registry.regions.events.EntityCustomRegionEnterEvent; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerJoinEvent; -public class WitchHouseListener implements Listener { +public class TerrorHouseListener implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { @@ -30,10 +33,10 @@ public void onWorldChange(PlayerChangedWorldEvent event) { if (HalloweenManager.getHalloweenDB().isActive()) { if (event.getFrom().equals(DimensionGenerator.HALLOWEEN_WORLD)) - WitchHouseManager.getWitchHouseAmbient().reset(player); + TerrorHouseManager.getWitchHouseAmbient().reset(player); if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) - WitchHouseManager.getWitchHouseAmbient().apply(player); + TerrorHouseManager.getWitchHouseAmbient().apply(player); } else { if (player.isOp()) return; @@ -48,9 +51,39 @@ public void onWorldChange(PlayerChangedWorldEvent event) { public void onHouseRegionEnter(EntityCustomRegionEnterEvent event) { CustomRegion region = event.getRegion(); - if (!WitchHouseManager.enabledRegions.contains(region)) return; + if (!region.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) + return; - if (event.getEntity() instanceof Player player) - WitchHouseManager.repulsePlayer(region, player, 0.3); + 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); + return; + } + + Floor floor = floors.getFloor(); + + if (floor == null) { + checkAndRepulse(region, entity); + return; + } + + if (TerrorHouseManager.limitPassed()) return; + + if (floor.canSpawn) { + floor.spawnMob(); + } + } + + private void checkAndRepulse(CustomRegion region, Entity entity) { + if (TerrorHouseManager.useRegions.contains(region)) + if (entity instanceof Player player) { + TerrorHouseManager.repulsePlayer(region, player, 0.3); + // TODO message + } } } 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 index f4af72b57..ea2431493 100644 --- 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 @@ -5,46 +5,53 @@ import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import lombok.Getter; +import lombok.Setter; -import java.util.ArrayList; -import java.util.List; +import java.lang.reflect.Type; +import java.util.*; @Getter -@DatabaseTable(tableName = "halloween_season_event_data") +@Setter +@DatabaseTable(tableName = "halloween_festival_event") public class HalloweenDB { - @DatabaseField(columnName = "advancement") - private int currentAdvancement; + 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 = "unlocked_room") - private String unlockedRooms; + @DatabaseField(columnName = "floor_advancement") + private int floorAdvancement; @DatabaseField(columnName = "is_active") private boolean active; - private static final Gson GSON = new Gson(); + @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 currentAdvancement, List unlockedRooms, boolean active) { - this.currentAdvancement = currentAdvancement; - this.unlockedRooms = GSON.toJson(unlockedRooms); + public HalloweenDB(int globalAdvancement, int floorAdvancement, boolean active) { + this.globalAdvancement = globalAdvancement; + this.floorAdvancement = floorAdvancement; this.active = active; } - public void setUnlockedRooms(List unlockedRooms) { - this.unlockedRooms = GSON.toJson(unlockedRooms); + public Set getParticipants() { + Set participants = GSON.fromJson(participantsJson, UUID_SET_TYPE); + return participants != null ? participants : new HashSet<>(); } - public List getUnlockedRooms() { - if (unlockedRooms == null || unlockedRooms.isBlank()) { - return new ArrayList<>(); - } - - return GSON.fromJson( - unlockedRooms, - new TypeToken>() {}.getType() - ); + 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/shop/ShopMoney.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/ShopMoney.java index 11a18206e..868f59ea4 100644 --- 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 @@ -3,22 +3,25 @@ import fr.openmc.core.OMCRegistry; import fr.openmc.core.registry.items.CustomItem; import lombok.Getter; +import net.kyori.adventure.text.Component; @Getter public enum ShopMoney { - //TODO rajouter les crafts des bonbons et les autre dans le shopMoney - RED_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_RED), - YELLOW_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW), - GREEN_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN), - BLUE_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE), - MONSTER_CANDY(WitchShopManager.getMoneyItemIcon("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN), + //TODO rajouter les crafts + Translation pour 'name' + RED_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_RED, 1000), + YELLOW_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW, 10000), //extremely rare no craft + GREEN_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 10), + BLUE_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 100), + MONSTER_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 1), ; - private final String icon; + private final Component name; private final CustomItem item; + private final int scores; - ShopMoney(String icon, CustomItem item) { - this.icon = icon; + 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 index a56308d15..906033c65 100644 --- 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 @@ -1,7 +1,8 @@ package fr.openmc.core.features.events.contents.halloween.festival.shop; import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; -import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.Floors; +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; @@ -31,7 +32,7 @@ public WitchShopItem(Floors advancements, CustomItem item, int price) { } public Component getName() { - if (HalloweenManager.hasUnlock(advancements)) + 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 index 6277c97cb..372c0b5ee 100644 --- 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 @@ -1,10 +1,12 @@ 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.events.contents.halloween.festival.HalloweenManager; -import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.Floors; +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; @@ -44,10 +46,11 @@ private static Map> getPaginateWitchStoreItems() { 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())) + ); - List subList = list.subList(i, Math.min(i + SLOT_FACTOR, list.size())); - - paginateItems.put(page++, new HashSet<>(subList)); + paginateItems.put(page++, subItems); } return paginateItems; @@ -88,18 +91,55 @@ public static void buyItem(Player player, WitchShopItem item, int amount) { int totalPrice = item.getPrice() * amount; if (ItemUtils.hasEnoughItems(player, item.getItem().getBest(), totalPrice)) { - ItemUtils.giveItem(player, item.getItem().getBest(), amount); + ItemUtils.giveItem((OMCPlayer) player, item.getItem().getBest(), amount); sendInfo(player, TranslationManager.translation("feature.adminshop.player_buy_item", //TODO Component.text(amount), item.getName(), Component.text(AdminShopUtils.formatPrice(totalPrice)) )); player.playSound(player, BUY_SOUND, 1f, new Random().nextFloat(0.6f, 1.4f)); + + TerrorHouseManager.updateAdvancement(item.getShopMoney().getScores() * item.getPrice()); + + HalloweenManager.addParticipant(player.getUniqueId()); + } else { sendError(player, TranslationManager.translation("feature.adminshop.have_enough_money")); //TODO } } + /** + * 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")); //TODO + return; + } + + // Check if the player has enough items to sell + if (!ItemUtils.hasEnoughItems(player, item.getItem().getBest(), amount)) { + sendError(player, TranslationManager.translation("feature.adminshop.player_not_enough_item")); //TODO + 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); + + sendInfo(player, TranslationManager.translation("feature.adminshop.player_sell_item", //TODO + Component.text(amount))); //TODO dire "vous avez ajouter xxxx points" + } + private static void sendError(Player player, Component message) { MessagesManager.sendMessage(player, message, Prefix.HALLOWEEN, MessageType.ERROR, true); player.playSound(player, ERROR_SOUND, 1f,1f); @@ -112,10 +152,13 @@ private static void sendInfo(Player player, Component message) { public static List extractLoreForItem(WitchShopItem item) { List lore = new ArrayList<>(); - if (HalloweenManager.hasUnlock(item.getAdvancements())) { + if (TerrorHouseManager.enabledFloors.contains(item.getAdvancements())) { lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO getPrice(item) ).color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); + lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO halloween.shop.points + Component.text(item.getShopMoney().getScores()).color(NamedTextColor.BLUE) + ).decoration(TextDecoration.ITALIC, false)); } else { @@ -127,14 +170,14 @@ public static List extractLoreForItem(WitchShopItem item) { } public static Component getPrice(WitchShopItem item) { - return Component.text(item.getPrice() + " " + item.getShopMoney().getIcon()); + return Component.text(item.getPrice() + " " + item.getShopMoney().getItem().getSprite()); } - public static String getMoneyItemIcon(String icon) { + public static String getHalloweenPointIcon() { if (ItemsAdderHook.isEnable()) { - return FontImageWrapper.replaceFontImages("§f:"+icon+":"); + return FontImageWrapper.replaceFontImages("§f:halloween_point:"); } else { - return "Ⓐ"; //TODO Translationmanager.translate("<...>." + icon) + return "Ⓟ"; } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmBuyMenu.java similarity index 89% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmBuyMenu.java index 97837946a..df119e453 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/ConfirmBuyMenu.java @@ -27,13 +27,13 @@ import java.util.Map; import java.util.function.Consumer; -public class ConfirmMenu extends Menu { +public class ConfirmBuyMenu extends Menu { private final WitchShopItem shopItem; private int quantity; private final int maxQuantity; - public ConfirmMenu(Player owner, WitchShopItem shopItem) { + public ConfirmBuyMenu(Player owner, WitchShopItem shopItem) { super(owner); this.shopItem = shopItem; this.quantity = 1; @@ -42,17 +42,17 @@ public ConfirmMenu(Player owner, WitchShopItem shopItem) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.adminshop.menu.confirm.name"); + return TranslationManager.translation("feature.adminshop.menu.confirm.name"); //TODO } @Override public String getTexture() { - return FontImageWrapper.replaceFontImages("§r§f:offset_-11::adminshop:"); + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_purchase_confirm_menu:"); } @Override public @NotNull InventorySize getInventorySize() { - return InventorySize.NORMAL; + return InventorySize.LARGEST; } @Override @@ -61,19 +61,27 @@ 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); - List lore = TranslationManager.translationLore("feature.adminshop.menu.confirm.lore", + List lore = TranslationManager.translationLore("feature.adminshop.menu.confirm.lore", //TODO 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), - Component.text(shopItem.getShopMoney().getIcon(), NamedTextColor.GREEN), + shopItem.getShopMoney().getItem().getSprite(), Component.text(AdminShopManager.priceFormat.format(totalPrice), NamedTextColor.GREEN), - Component.text(shopItem.getShopMoney().getIcon(), NamedTextColor.GREEN) - + shopItem.getShopMoney().getItem().getSprite(), + Component.text(AdminShopManager.priceFormat.format(scorePerUnit) + + WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN), + Component.text(AdminShopManager.priceFormat.format(totalScore) + + WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN) ); content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); @@ -103,7 +111,7 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} if (event.getClick() == ClickType.MIDDLE) { DialogInput.sendFloat( getOwner(), - TranslationManager.translation("feature.adminshop.menu.confirm.input"), + TranslationManager.translation("feature.adminshop.menu.confirm.input"), //TODO 1, maxQuantity, quantity, @@ -147,10 +155,10 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} 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", + meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", //TODO plus ? - TranslationManager.translation("feature.adminshop.menu.confirm.add") : - TranslationManager.translation("feature.adminshop.menu.confirm.remove"), + TranslationManager.translation("feature.adminshop.menu.confirm.add") : //TODO + TranslationManager.translation("feature.adminshop.menu.confirm.remove"), //TODO Component.text(text.replace("+", "").replace("-", ""))) .color(plus ? NamedTextColor.GREEN : NamedTextColor.RED) .decoration(TextDecoration.ITALIC, false))) 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..2f417453a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/WitchChoiceMenu.java @@ -0,0 +1,73 @@ +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.TerorHouseButton; +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 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.city.menus.main.name"); //TODO + } + + @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<>(); + + // ** Witch House Button + TerorHouseButton.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 index f4a4a4a52..eb5692953 100644 --- 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 @@ -1,9 +1,11 @@ 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.WitchHouseButton; +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.TerorHouseButton; 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; @@ -34,7 +36,7 @@ public WitchShopMainMenu(Player owner) { @Override public String getTexture() { - return "§r§f:offset_-48::halloween_event_main_menu:"; + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_event_main_menu:"); } @Override @@ -46,8 +48,7 @@ public String getTexture() { public @NotNull Map getContent() { Map inventory = new HashMap<>(); - // ** Witch House Button - WitchHouseButton.init(this, inventory, WITCH_HOUSE_SLOTS); + ChoiceButton.init(this, inventory, WITCH_HOUSE_SLOTS); // ** Witch Store Button WitchStoreButton.init(this, inventory, WITCH_SHOP_SLOTS); 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 index 99efe1557..2d73ca4fa 100644 --- 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 @@ -1,5 +1,6 @@ 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; @@ -31,8 +32,8 @@ public class WitchShopStoreMenu extends PaginatedMenu { @Getter private final int page; - private final Column.Range line = new Column.Range(10, 16); - private final int column = 4; + private final Column.Range line = new Column.Range(1, 7); + private final int COLUMN = 4; public WitchShopStoreMenu(Player owner, int page) { super(owner); @@ -64,7 +65,7 @@ public List getItems() { Iterator contents = WitchShopManager.getStoreContent(this.page).iterator(); - for (int c = 0; c < column; c++) { + for (int c = 0; c < COLUMN; c++) { for (int l = line.floor(); l <= line.ceiling(); l++) { if (!contents.hasNext()) break; @@ -75,7 +76,7 @@ public List getItems() { itemMeta.displayName(item.getName()); itemMeta.lore(WitchShopManager.extractLoreForItem(item)); }).setOnClick(event -> { - //TODO open confirm menu if has enough moneyItem + new ConfirmBuyMenu(getOwner(), item); })); } } @@ -101,12 +102,6 @@ public Map getButtons() { new WitchShopMainMenu(getOwner()).open(); })); - //TODO filter : - // - room - // - unlocked - // - lower cost - // - highest cost - if (hasNextPage()) { map.put(53, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_NEXT_ORANGE, itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); @@ -124,7 +119,7 @@ public Map getButtons() { @Override public String getTexture() { - return "§r§f:offset_-48::city_template6x9:"; //TODO + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_store_menu:"); } @Override 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..fbe6e4558 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/ChoiceButton.java @@ -0,0 +1,31 @@ +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.city.menus.main.ranks.title"));//TODO + itemMeta.lore(TranslationManager.translationLore( + "feature.city.menus.main.ranks.lore.unlocked", //TODO + Component.text("").color(NamedTextColor.LIGHT_PURPLE) + )); + 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..cd0b8fcb6 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/DepositButton.java @@ -0,0 +1,31 @@ +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.city.menus.main.ranks.title"));//TODO + itemMeta.lore(TranslationManager.translationLore( + "feature.city.menus.main.ranks.lore.unlocked", //TODO + Component.text("").color(NamedTextColor.LIGHT_PURPLE) + )); + 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/WitchHouseButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerorHouseButton.java similarity index 92% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchHouseButton.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerorHouseButton.java index 64b45c17e..2326eb272 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/WitchHouseButton.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerorHouseButton.java @@ -8,14 +8,11 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.entity.Player; import java.util.Map; -public class WitchHouseButton { +public class TerorHouseButton { public static void init(Menu menu, Map contents, int[] slots) { - Player player = menu.getOwner(); - MenuUtils.createButtonItem( contents, slots, 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..afca3729c --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/TerrorHouseManager.java @@ -0,0 +1,181 @@ +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.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 finalRoomReach; + + public static int entityCount = 0; + public static final int MAX_ENTITY = 225; // 15 entities * 15 floors + + @Getter + public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.WITCH_HOUSE; + + public static void init(int gAdvancement, int fAdvancement) { + globalAdvancement = gAdvancement; + floorAdvancement = fAdvancement; + + currentFloorToReach = getFloorFromAdvancement(globalAdvancement); + currentRewardToReach = getRewardFromAdvancement(globalAdvancement); + + enabledFloors = EnumUtils.getValuesBefore(currentFloorToReach, false); + + finalRoomReach = currentFloorToReach.equals(Floors.FLOOR_2); //TODO last floor FLOOR_15 + + for (Floors floors : Floors.values()) { + Floor floor = floors.getFloor(); + if (floor == null) continue; + CustomRegion region = floor.getRegion(); + if (region != null) + useRegions.add(region); + } + } + + // --- Advancement / Floor Part --- // + + public static void updateAdvancement(int increase) { + globalAdvancement += increase; + floorAdvancement += increase; + + CheckForPointRewards(); + + if (currentFloorToReach.equals(Floors.FLOOR_2)) //TODO last floor FLOOR_15 + return; + + if (currentFloorToReach.getRequire() > floorAdvancement) + return; + + updateFloor(); + + //TODO broadcast + } + + private static void CheckForPointRewards() { + if (currentRewardToReach.equals(PointRewards.NULL)) + return; + + if (globalAdvancement >= currentRewardToReach.getGlobalPointsRequire()) { + currentRewardToReach.getReward().giveReward(); + + currentRewardToReach = currentRewardToReach.getNextReward(); + } + } + + private static void updateFloor() { + floorAdvancement -= currentFloorToReach.getRequire(); + + enabledFloors.add(currentFloorToReach); + + currentFloorToReach = EnumUtils.getValueAfter(currentFloorToReach); + + if (currentFloorToReach == null) + return; + + Floor floor = currentFloorToReach.getFloor(); + + if (floor == null) + return; + + floor.setCanSpawn(true); + } + + public static Floors getFloorFromAdvancement(int advancement) { + Floors currentFloors = Floors.FLOOR_1; + + for (Floors floors : Floors.values()) { + if (floors.getRequire() < advancement) + currentFloors = floors; + else if (floors.getRequire() == advancement) + return 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(Entity entity, double force) { + repulsePlayer(entity.getLocation(), 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()); + + if (knockback.lengthSquared() < 1.0E-6) { + knockback = playerLocation.getDirection(); + } + + knockback.normalize().multiply(force); + + entity.setVelocity(knockback); + } + + // --- Entity part --- // + public static boolean limitPassed() { + return entityCount >= MAX_ENTITY; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java deleted file mode 100644 index 4afb4a314..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/WitchHouseManager.java +++ /dev/null @@ -1,114 +0,0 @@ -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.witchhouse.advancement.Floors; -import fr.openmc.core.registry.ambient.CustomAmbient; -import fr.openmc.core.registry.regions.CustomRegion; -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.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitTask; -import org.bukkit.util.Vector; - -import java.util.List; - -public class WitchHouseManager { - - public Floors currentFloor; - public static List enabledRegions; //TODO add values to it - public int floorAdvancement; - public boolean finalRoomReach; - - BukkitTask spawnTimeTask; - - @Getter - public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.WITCH_HOUSE; - - public WitchHouseManager(Floors advancements, int countAdvancement) { - currentFloor = advancements; - this.floorAdvancement = countAdvancement; - finalRoomReach = currentFloor.equals(Floors.FLOOR_2); //TODO last floor FLOOR_15 - } - - public void updateAdvancement(int increase) { - floorAdvancement += increase; - - if (currentFloor.getRequire() > floorAdvancement) { - return; - } - int currentRoom = Integer.parseInt(currentFloor.name().replaceFirst(".*\\D", "")); - - currentRoom++; - - currentFloor = Floors.valueOf("FLOOR_" + currentRoom); - - //TODO broadcast - } - - public void prepareSpawn() { - // entre 1m et 1m30 -> dire que l'on peut spawn vague de mob, avec int min et int max - // selon l'étage plus de mob + ou - dure - - spawnTimeTask = Bukkit.getScheduler().runTaskAsynchronously(OMCPlugin.getInstance(), - () -> { - // dire au zone de check pour spawn des mobs, sinon mettre en attente - }); - - - } - - public void delayedSpawnMob() { - - } - - 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(Entity entity, double force) { - repulsePlayer(entity.getLocation(), 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()); - - if (knockback.lengthSquared() < 1.0E-6) { - knockback = playerLocation.getDirection(); - } - - knockback.normalize().multiply(force); - - entity.setVelocity(knockback); - } -} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java deleted file mode 100644 index 60938cae3..000000000 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floors.java +++ /dev/null @@ -1,31 +0,0 @@ -package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement; - -import fr.openmc.core.OMCRegistry; -import lombok.Getter; - -import java.util.List; - -@Getter -public enum Floors { - FLOOR_1(new Floor( - OMCRegistry.CUSTOM_REGIONS.EXAMPLE_REGION, - List.of(), - 3.0 - ), 0), - - FLOOR_2(new Floor( - OMCRegistry.CUSTOM_REGIONS.EXAMPLE_REGION, - List.of(), - 3.0 - ), 1000), - - ; - - private final Floor floor; - private final int require; - - Floors(Floor floor, int require) { - this.floor = floor; - this.require = require; - } -} 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.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floor.java similarity index 66% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floor.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floor.java index cb74a6ae9..88dfea1d1 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/Floor.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floor.java @@ -1,10 +1,13 @@ -package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement; +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor; import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; import fr.openmc.core.registry.mobs.CustomMobEntry; -import fr.openmc.core.registry.regions.types.Region; +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 lombok.Setter; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -12,12 +15,53 @@ import java.util.List; -public record Floor(Region region, List entities, double radius) { +@Getter +public class Floor { - public void spawnMob(int number) { - for (int n = 0; n < number; n++) { - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), this::spawn, (RandomUtils.randomBetween(2, 7) + n) * 20L); + private final SquareRegion region; + private final List entities; + private final int entityToSpawn; + private final double radius; + + @Setter + public boolean canSpawn; + + public Floor(SquareRegion region, List entities, double radius, int entityToSpawn) { + this(region, entities, entityToSpawn, radius, false); + } + + public Floor(SquareRegion region, List entities, int entityToSpawn, double radius, boolean canSpawn) { + this.region = region; + this.entities = entities; + this.entityToSpawn = entityToSpawn; + this.radius = radius; + this.canSpawn = canSpawn; + } + + public void reloadMobSpawn() { + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { + canSpawn = true; + },RandomUtils.randomBetween(60, 120) * 20L); + } + + public void spawnMob() { + + canSpawn = false; + + long time = 0; + + spawn(); + + for (int n = 0; n < entityToSpawn - 1; n++) { + time += RandomUtils.randomBetween(2, 7) + n; + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), this::spawn, time * 20L); + TerrorHouseManager.entityCount++; + + if (TerrorHouseManager.limitPassed()) + break; } + + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), this::reloadMobSpawn, time * 20L); } private void spawn() { 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..8da6e60d8 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/floor/Floors.java @@ -0,0 +1,49 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor; + +import fr.openmc.core.OMCRegistry; +import lombok.Getter; + +import java.util.List; + +@Getter +public enum Floors { + + FLOOR_1(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 8), 0), + + FLOOR_2(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 8), 1000), + + FLOOR_3(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 8), 5000), + + FLOOR_4(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 10000), + + FLOOR_5(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 15000), + + FLOOR_6(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 20000), + + FLOOR_7(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 25000), + + FLOOR_8(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 30000), + + FLOOR_9(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 35000), + + FLOOR_10(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 40000), + + FLOOR_11(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 45000), + + FLOOR_12(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 50000), + + FLOOR_13(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 59000), + + FLOOR_14(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 65000), + + FLOOR_15(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 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 + } +} 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 index fc22068bd..4d3a0aabc 100644 --- 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 @@ -5,6 +5,9 @@ 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.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 org.bukkit.entity.Player; @@ -18,7 +21,7 @@ public class AdvancementMenu extends Menu { - protected AdvancementMenu(Player owner) { + public AdvancementMenu(Player owner) { super(owner); } @@ -29,7 +32,20 @@ protected AdvancementMenu(Player owner) { @Override public String getTexture() { - return FontImageWrapper.replaceFontImages("§r§f:offset_-11::adminshop:");//TODO jar avec des bonbons, faire selon l'avancement ? ( en vrai ouais ) + + 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 @@ -46,7 +62,23 @@ public void onInventoryClick(InventoryClickEvent e) { public @NotNull Map getContent() { Map content = new HashMap<>(); - content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); + content.put(21, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.CANDY_RED, itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + }).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; } 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..b3e4e8c7e --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/CandyChoiceMenu.java @@ -0,0 +1,98 @@ +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.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.adminshop.menu.confirm.name");//TODO + } + + @Override + public String getTexture() { + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_deposit_menu:"); //TODO + } + + @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("messages.menus.next_page")); //TODO + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.MONSTER_CANDY); + })); + + content.put(20, new ItemMenuBuilder(this, ShopMoney.GREEN_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.GREEN_CANDY); + })); + + content.put(13, new ItemMenuBuilder(this, ShopMoney.BLUE_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.BLUE_CANDY); + })); + + content.put(24, new ItemMenuBuilder(this, ShopMoney.RED_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.RED_CANDY); + })); + + content.put(17, new ItemMenuBuilder(this, ShopMoney.YELLOW_CANDY.getItem(), itemMeta -> { + itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + }).setOnClick(click -> { + new ConfirmSellMenu(getOwner(), ShopMoney.YELLOW_CANDY); + })); + + 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/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..68507f546 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/ConfirmSellMenu.java @@ -0,0 +1,227 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.menu; + +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.adminshop.ShopItem; +import fr.openmc.core.features.economy.EconomyManager; +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.Material; +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 // + + 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 = countPlayerItems(owner, shopItem.getItem().getBest()); + } + + @Override + public @NotNull Component getName() { + return TranslationManager.translation("feature.adminshop.menu.confirm.name"); //TODO + } + + @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"); //TODO + + List lore = TranslationManager.translationLore("feature.adminshop.menu.confirm.lore", //TODO + 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(EconomyManager.getEconomyIcon(), NamedTextColor.GREEN), //TODO faire icon halloween point + Component.text(AdminShopManager.priceFormat.format(totalScore), NamedTextColor.GREEN), + Component.text(EconomyManager.getEconomyIcon(), NamedTextColor.GREEN), //TODO faire icon halloween point + 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"), //TODO + 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(); + AdminShopManager.sellItem( + getOwner(), + shopItem.getItem().getId(), + 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")); //TODO + }).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", //TODO + plus ? + TranslationManager.translation("feature.adminshop.menu.confirm.add") : //TODO + TranslationManager.translation("feature.adminshop.menu.confirm.remove"), //TODO + 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); + } + + /** + * Counts the number of items of a specific material in a player's inventory. + * + * @param player The player whose inventory to check. + * @param toCount The item to count. + * @return The count of items of the specified material in the player's inventory. + */ + private int countPlayerItems(Player player, ItemStack toCount) { + int count = 0; + for (ItemStack item : player.getInventory().getContents()) + if (item != null && item.isSimilar(toCount)) + count += item.getAmount(); + return count; + } + + /** + * 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 = countPlayerItems(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/RewardsMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardViewMenu.java similarity index 58% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardsMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardViewMenu.java index 770b952e4..4ff27cfe5 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardsMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/menu/RewardViewMenu.java @@ -5,6 +5,9 @@ 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.menu.WitchShopMainMenu; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.reward.PointReward; import fr.openmc.core.utils.text.messages.TranslationManager; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -16,9 +19,9 @@ import java.util.List; import java.util.Map; -public class RewardsMenu extends Menu { +public class RewardViewMenu extends Menu { - protected RewardsMenu(Player owner) { + public RewardViewMenu(Player owner) { super(owner); } @@ -29,12 +32,12 @@ protected RewardsMenu(Player owner) { @Override public String getTexture() { - return FontImageWrapper.replaceFontImages("§r§f:offset_-11::adminshop:");//TODO + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_reward_menu:"); } @Override public @NotNull InventorySize getInventorySize() { - return InventorySize.NORMAL; + return InventorySize.LARGEST; } @Override @@ -46,7 +49,18 @@ public void onInventoryClick(InventoryClickEvent e) { public @NotNull Map getContent() { Map content = new HashMap<>(); - content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); + PointReward reward = TerrorHouseManager.currentRewardToReach.getReward(); + + content.put(13, new ItemMenuBuilder(this, reward.getItemMenuPreview(), itemMeta -> { + itemMeta.displayName(reward.getRewardName()); + itemMeta.lore(reward.getRewardLore()); + })); + + 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; } 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..403001063 --- /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 new ArrayList<>(); + } +} 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..cd5ddba72 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/advancement/reward/plush/HalloweenRoot2026.java @@ -0,0 +1,67 @@ +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.features.events.contents.halloween.festival.HalloweenManager; +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 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 : HalloweenManager.getParticipant()) { + + Player player = Bukkit.getPlayer(uuid); + + if (player != null) { + + OMCPlayer omcPlayer = OMCPlayer.of(player); + + HalloweenManager.sendMailItems(omcPlayer, omcPlayer, rewardToGive); + } else { + OfflinePlayer offlinePlayer = CacheOfflinePlayer.getOfflinePlayer(uuid); + + if (offlinePlayer == null) { + //TODO problème + continue; + } + + MailboxManager.sendItemsToOfflinePlayer(offlinePlayer, rewardToGive); + } + } + + } + + @Override + public ItemStack getItemMenuPreview() { + return reward.getBest(); + } + + @Override + public Component getRewardName() { + return null; //TODO item name + } + + @Override + public List getRewardLore() { + return null; //TODO item lore + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/WitchHouseAmbient.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/TerrorHouseAmbient.java similarity index 97% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/WitchHouseAmbient.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/TerrorHouseAmbient.java index 052154ed6..29bfa53ad 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/WitchHouseAmbient.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/ambient/TerrorHouseAmbient.java @@ -10,7 +10,7 @@ import net.minecraft.world.level.dimension.DimensionType; import org.bukkit.Particle; -public class WitchHouseAmbient extends CustomAmbient { +public class TerrorHouseAmbient extends CustomAmbient { @Override public String getId() { return "witch_house_ambient"; diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java index 447527858..c3c5764d2 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java @@ -1,6 +1,6 @@ package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.floor1_3; -import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.WitchHouseManager; +import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.TerrorHouseManager; import fr.openmc.core.registry.loottable.loots.XpLoot; import fr.openmc.core.registry.mobs.CustomMob; import fr.openmc.core.utils.RandomUtils; @@ -14,7 +14,7 @@ public class HouseZombieLV1 extends CustomMob { - double RADIUS = 3.0; + final double RADIUS = 3.0; public HouseZombieLV1(String id) { super(id, @@ -58,7 +58,7 @@ public Zombie spawn(Location spawnLocation) { zombie.getNearbyEntities(RADIUS, RADIUS, RADIUS).stream() .filter(entity -> entity instanceof Player) - .forEach(player -> WitchHouseManager.repulsePlayer(player, 0.3f)); + .forEach(player -> TerrorHouseManager.repulsePlayer(player, 0.3f)); return zombie; } 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 34d3bab49..4f084fde0 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java @@ -10,7 +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.WitchHouseAmbient; +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.listeners.AmbientFixedTimeListener; @@ -38,7 +38,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 WITCH_HOUSE = register(new WitchHouseAmbient()); + public final CustomAmbient WITCH_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 27d78bb74..950c220f8 100644 --- a/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java +++ b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java @@ -15,7 +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.halloween.CandyItem; +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; @@ -95,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)); 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..00d68ebad 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,11 @@ package fr.openmc.core.registry.regions; +import com.sk89q.worldedit.math.BlockVector3; 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 +18,12 @@ public class CustomRegionRegistry extends Registry public final ExampleRegion EXAMPLE_REGION = register(new ExampleRegion()); + public final SquareRegion TEST_REGION = register(new SquareRegion( + DimensionGenerator.HALLOWEEN_WORLD, + BlockVector3.at(0, 0, 0), + BlockVector3.at(1, 1, 1) + )); + @Override public Key key(CustomRegion registryObject) { return registryObject.getKey(); 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 index 921aa00ed..55ba3b234 100644 --- a/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java @@ -2,25 +2,34 @@ import com.sk89q.worldedit.math.BlockVector3; import fr.openmc.core.registry.regions.CustomRegion; -import fr.openmc.core.utils.MathUtils; +import lombok.Getter; import net.kyori.adventure.key.Key; import org.bukkit.World; public class SquareRegion extends CustomRegion { public World world; + public BlockVector3 pos1; + public BlockVector3 pos2; + + @Getter public BlockVector3 min; + + @Getter public BlockVector3 max; + public Key key; - public SquareRegion(World world, BlockVector3 corner1, BlockVector3 corner2) { - this(world, corner1, corner2, null); + public SquareRegion(World world, BlockVector3 pos1, BlockVector3 pos2) { + this(world, pos1, pos2, null); } - public SquareRegion(World world, BlockVector3 corner1, BlockVector3 corner2, Key key) { + public SquareRegion(World world, BlockVector3 pos1, BlockVector3 pos2, Key key) { this.world = world; - min = corner1.getMinimum(corner2); - max = corner1.getMaximum(corner2); + min = pos1.getMinimum(pos2); + max = pos1.getMaximum(pos2); + this.pos1 = pos1; + this.pos2 = pos2; this.key = key; } @@ -49,13 +58,13 @@ public boolean contains(BlockVector3 pos) { } @Override - public BlockVector3 getMin() { - return min; + public BlockVector3 getPos1() { + return pos1; } @Override - public BlockVector3 getMax() { - return max; + public BlockVector3 getPos2() { + return pos2; } @Override diff --git a/src/main/resources/contents/omc_halloween/configs/items.yml b/src/main/resources/contents/omc_halloween/configs/items.yml index 040fa93ed..5981e28ea 100644 --- a/src/main/resources/contents/omc_halloween/configs/items.yml +++ b/src/main/resources/contents/omc_halloween/configs/items.yml @@ -67,6 +67,32 @@ items: 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: iaa_crafting_table: fermentum: diff --git a/src/main/resources/contents/omc_halloween/models/items/root_plush.json b/src/main/resources/contents/omc_halloween/models/items/root_plush.json new file mode 100644 index 000000000..001b3ead5 --- /dev/null +++ b/src/main/resources/contents/omc_halloween/models/items/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:root_halloween_plush_texture", + "particle": "omc_halloween: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/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 0000000000000000000000000000000000000000..ff5e91570260a277b7eba751d1b97fab49c0bddc GIT binary patch literal 1968 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 P{vx%!Y-?6$>iyt<`RVQv literal 0 HcmV?d00001 diff --git a/src/main/resources/data/witch_house_spawn.yml b/src/main/resources/data/witch_house_spawn.yml deleted file mode 100644 index 061641011..000000000 --- a/src/main/resources/data/witch_house_spawn.yml +++ /dev/null @@ -1,5 +0,0 @@ -spawn: - world: world # Nom du monde - x: 0.0 # Coordonnées X - y: 0.0 # Coordonnées Y - z: 0.0 # Coordonnées Z \ No newline at end of file From 3e47bf45186fcb506dea0cb09b1957ffc587eed9 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:37:05 +0200 Subject: [PATCH 16/44] fix ImmutableCollections error --- src/main/java/fr/openmc/core/utils/EnumUtils.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/openmc/core/utils/EnumUtils.java b/src/main/java/fr/openmc/core/utils/EnumUtils.java index 7c8ce70bc..ea8633a26 100644 --- a/src/main/java/fr/openmc/core/utils/EnumUtils.java +++ b/src/main/java/fr/openmc/core/utils/EnumUtils.java @@ -1,8 +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 { /** @@ -44,8 +46,10 @@ public static > T match(String key, Class enumClass, T defa */ 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()) - .toList(); + .filter(e -> withIt + ? e.ordinal() <= value.ordinal() + : e.ordinal() < value.ordinal()) + .collect(Collectors.toCollection(ArrayList::new)); } /** @@ -57,8 +61,10 @@ public static > List getValuesBefore(T value, boolean withI */ 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()) - .toList(); + .filter(e -> withIt + ? e.ordinal() >= value.ordinal() + : e.ordinal() > value.ordinal()) + .collect(Collectors.toCollection(ArrayList::new)); } /** From 6b87bc2ab39b1ae0f48ffad535f590885bacbfc3 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:37:20 +0200 Subject: [PATCH 17/44] fix menu names --- ...n_candy_jare_0.png => halloween_candy_jar_0.png} | Bin ...n_candy_jare_1.png => halloween_candy_jar_1.png} | Bin ...n_candy_jare_2.png => halloween_candy_jar_2.png} | Bin ...n_candy_jare_3.png => halloween_candy_jar_3.png} | Bin ...n_candy_jare_4.png => halloween_candy_jar_4.png} | Bin 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/contents/omc_menus/textures/halloween/{halloween_candy_jare_0.png => halloween_candy_jar_0.png} (100%) rename src/main/resources/contents/omc_menus/textures/halloween/{halloween_candy_jare_1.png => halloween_candy_jar_1.png} (100%) rename src/main/resources/contents/omc_menus/textures/halloween/{halloween_candy_jare_2.png => halloween_candy_jar_2.png} (100%) rename src/main/resources/contents/omc_menus/textures/halloween/{halloween_candy_jare_3.png => halloween_candy_jar_3.png} (100%) rename src/main/resources/contents/omc_menus/textures/halloween/{halloween_candy_jare_4.png => halloween_candy_jar_4.png} (100%) diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_0.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_0.png similarity index 100% rename from src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_0.png rename to src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_0.png diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_1.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_1.png similarity index 100% rename from src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_1.png rename to src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_1.png diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_2.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_2.png similarity index 100% rename from src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_2.png rename to src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_2.png diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_3.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_3.png similarity index 100% rename from src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_3.png rename to src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_3.png diff --git a/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_4.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_4.png similarity index 100% rename from src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jare_4.png rename to src/main/resources/contents/omc_menus/textures/halloween/halloween_candy_jar_4.png From d1b3ba14485d8c78bb3e93d60ab6ebf7a25ed26f Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:37:37 +0200 Subject: [PATCH 18/44] fix menus textures --- .../halloween/halloween_choice_menu.png | Bin 5439 -> 5535 bytes .../halloween/halloween_deposit_menu.png | Bin 4835 -> 4864 bytes .../halloween_festival_main_menu.png} | Bin .../halloween_purchase_confirm_menu.png | Bin 4118 -> 4140 bytes .../halloween/halloween_reward_menu.png | Bin 5053 -> 5063 bytes .../halloween/halloween_store_menu.png | Bin 3836 -> 3840 bytes 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/contents/omc_menus/textures/{halloween_event_main_menu.png => halloween/halloween_festival_main_menu.png} (100%) 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 index e529288839cd3a3b49c68c428b1fb508636dff88..016f176f639837cc783a75d45b78ad8de2a8ceb7 100644 GIT binary patch literal 5535 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 delta 5183 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 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 index eb2013d76fc6108cf18170450fa23133878c7583..7285a72f68cc7b425c7126d973a8dbe6ced23705 100644 GIT binary patch delta 4562 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 delta 4545 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 diff --git a/src/main/resources/contents/omc_menus/textures/halloween_event_main_menu.png b/src/main/resources/contents/omc_menus/textures/halloween/halloween_festival_main_menu.png similarity index 100% rename from src/main/resources/contents/omc_menus/textures/halloween_event_main_menu.png rename to src/main/resources/contents/omc_menus/textures/halloween/halloween_festival_main_menu.png 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 index 2365c1da81d0145d62589abcfdcc1b2c60740914..b49cdc4a565d9c16e54dffc52b22d65c83780340 100644 GIT binary patch delta 3867 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 delta 3842 zcmW+(dpy(M|9@|klyZ*7-C z9BO45*5U(f(!X2Z3&^rlhlpl{D}cuj%q&=aPt82Ac(!CkrOSfdx%HU81Bm3cQ8Fk; z;gc#Ei5h@#XwKBql>NU3=97Dx_qRG7Obw8qpPVL{0SHTl=twN{{rse?bk@X|lG)XU zA!6@#F|KLyHD`HtCk4sxSpI*=*U@G)&%&a76M2nX?%a%mcAb2w0fe`iXwHzv z^E5Qn)X12XV`|FsJyKb928jG|Y;8|_qjVrc)~}45vf2QoHNL?%7+@Rk0_45Fm^wcX z=#g$G!1k-;$4t-A`WN|lzH4KPL{ed6Dm z%YZ(1H=4Uq-wq>x<2iWnG|TIu1N)(|xe1>y2CT4; zMbHZfCyinjDvq!y(r``}p`_8ORneWBj;3;M%WDWeFp$eL3Wu!rwKj96*VU5>Z7=ZO zO(R)Ca?U_TM9ykbi@=rDzuQl$Y$dDRXRn~h?t5By30UX zV5)^I&#AV<1ohL%^hQyC3G>^ZhiS(I^$f1|%oa4txd2%DR7BRLSn}-k7)TR=T(v!* z@x^S{#GN+$Wq!4b*`5Vzhjv~4D$Z4&xM-qHgqdP+PjmbzBIlH<>;SChMXhVp+)V=r zO1w4B-DdP+9XNcGYs_3Z+Jv_y>DRJc+m>X&SF^-Xt?gkk!=%@|Zm~(fP^8474A%H} zYg&Sl6zIh||ILyAGkelyqX5@d`mo!o)pD~4RZG);(T4Zs6C{0o1$NaLs0v|yBugYD zbPUV=xdAe_Q8csZ#Gh<*eGw~hiH_s5gl_h!;kjrtlX1$@b8~s?Kv7LHgL?X9)}n4go{Q=F4nQz|g7%jT*(B3$TsahhO5~yL;bc4FUCS5$5 zlkSnXRUbkc;gP8D--A1Z$Q=i3Ym8tV&r#Kd31utWc>j|aIguM$)SH^zx!sIR8h?AP z0PQ|6n5_Inef|s`b{Pio0>t&^ByR*v|DqK=pS&(8U0Oznck>eki~+6RHlibIt(6o`+R-n1Ll zQXf=@04Z0;6EWs$rE-fhtwWoptGB)!4{q5^J$_j9)!4N_4X1waY$#&ivQ|s-=YxRJ z?m{s^*rFHUu==p*wU7KY8L6DwAjqxe`PCP~XGnFGc9wR<^26tPx8VAxaL;d|A8()C znWj7+KtYzQ5NmG3L!0YS5~U&JQ<-1FmUZGFE^m?XTXDPZWBWQS4eUt5bM1kZ(BcoU zJ-;vdK&!f+MK*(Ls=ehRDZ;|im~YWMy$;I)J`0oDfUa;67^Bg*>eo3TO2UbCcli3? z58;{}FlSn7K1JFT*>*OQK7OGl-}tTSkcqo6L$^)`(Se^G9sTT;BDL9(Gydnh>Rbn5 zfb>q+s^xx9wqx(jWi2q`YM>y)@4#EwbWHf#U66!kMmUSy(~-q8Vo&$$6C8f)8k=>RZ z?4)D&jPw0;<+r7>7E=%oOC_ty?XQ{pDilQ)WZ(~ZardV*sU( zZJ>oI7osy9Yj*Za!{wJ*6WR2o=>l39noVh2^-^eUSqyn^$=StRYdu524I-I)zd_uXY8c*Ac-T=33++Vbv<-i3I6mxSv=2t zy3*wa^q;spi?fx7;WLXDH`emtus;sYGe88(ni3*N20mChR?`to0qYm^?Pk8nxaYfJv``^6K19h8{`V*cN^ZFm- z|NW!c={<@T!PCryQ)tWfGgt%GL@$waOSm!{)`lRHi9Q)WqeaMoH!ukB6fTQOvm$2mG{`F?Mk(mQ@zuQJ>$ zR~!M}cv>+c48d;J0-ZLv>Td*(yeFSao?*gR<8`7ios#XNi)YFLFeNK}9w%xTfX3T_rJho{~CC9wfsDHL(ry-X6B3 zY}+tC($Zq#wfxL8{+Q&z^WYE%iSyymU>6ie$#vI8_jR>WpKhi2&yvP{rf^@q9lEA; zxqV>3Y0Nn}q08oLf>c3?;meb_#*B$ip)d%uBzs$9hI9zSI4-fg0D0+I&Sk`^s8 znFkm@B>(4zTJX*wFx|9b{9;M1!LJQb;{Iv(LG_5R2)*o9{vCBQQ!}sC)DaQ)ezK$S z+;@+=CzmVTgz9dv&J7v#XqqV=eHVW!RX?DH{7>-O#|&MDBGcUjC61U0b2?5zxOa(_ zj{41s3jT?NpB8URBLvetszGA(Qka+2uZbA)a zsY&j_`1Dj9xI;)blK0f-&JZu=F&`9LdpVwrvv8U4(wmT@`r1R2&)SS1c#!*}&CcAj zaIF>3@XXNEkwxGzv=PZ-7yP55OWYSZ^H4WUY^|!CjW^L<{H;z0m?_?mHb8{RI28aL zZ$kG`uKFxFZ<3RqEF^pHD5CntonU>jveK$-|8gmE|(pO zuZj8PM#D+{TE9?wRsPi!z)YA-ND&|EzPegEC>TUO0$-GF_CMP#y*CZj_ z(z`sOBw{-xOuXujZc68<^1TLpbJ-j&D-~V(^kq`A;5M#7jF-t#84JH%@D4RPBn;K{ zEr_D=S^3_7gFgEy9hRL-*)>%6usvSHo?%o9YP(u1U%$SlCBG_J)F1TtDFpN}SIQeg zDh#L{zp{8w{(9AEn?cl}03W$5VDkebqxOW|-zqa6)=(^_)+5>xqhbT(nNCY6U5x$v zH%co&j~1`uy^+R{Mf8i01jd#g3fe>Bj?cFKBUbt7Fm34_ee7{rew+Tz$nKrA>#~TN z?7ml&NofbBo%1i!YWS^_xz7!(uIBWAs&6)&e_;!C;7pDCk(;39um{53xNI^rzOfI( zD5Dv|VzTXBWV3#@T^{RNaSekmT$hmdc;d27w3yeh*1q}jM3*SQ%fXx=K0g7;>ANA? zfoM;>kyRH2!D{!h^;(5(XZAhGoa{`=eToRe4rDrI-=@?~o7JB_)%Luj^_z44|NbAX CD88Zq 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 index 9a323f872aeab1d950cf466173b9babc5bb1adaf..703aa01dfb178931286a6b70815df45e0add26f2 100644 GIT binary patch literal 5063 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 NU9fe6)|~T8{y%zc`-1=g literal 5053 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 HU7!9BRMOSt 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 index 2d6b4ebd5c8c03069fd769a32649f5a1f1b0352e..ec80d9c2b7a5a0eaf0fc8205fb4438ea9bd6938b 100644 GIT binary patch delta 3033 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 Date: Sat, 24 Oct 2026 00:38:07 +0200 Subject: [PATCH 19/44] remove old candy from daily_event --- .../contents/omc_daily_events/items.yml | 65 ------------------- 1 file changed, 65 deletions(-) diff --git a/src/main/resources/contents/omc_daily_events/items.yml b/src/main/resources/contents/omc_daily_events/items.yml index f96c925bf..8bd96d2aa 100644 --- a/src/main/resources/contents/omc_daily_events/items.yml +++ b/src/main/resources/contents/omc_daily_events/items.yml @@ -66,71 +66,6 @@ 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: - - - consumable: - nutrition: 1 - saturation: 0.6 - recipes: iaa_crafting_table: fermentum: From 80e30d22066194398f92c3b4cb2a8fcd47058dfa Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:38:24 +0200 Subject: [PATCH 20/44] update config --- .../contents/omc_halloween/configs/items.yml | 82 +++++++++---------- .../contents/omc_menus/configs/menus.yml | 2 +- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/main/resources/contents/omc_halloween/configs/items.yml b/src/main/resources/contents/omc_halloween/configs/items.yml index 5981e28ea..ac0b36567 100644 --- a/src/main/resources/contents/omc_halloween/configs/items.yml +++ b/src/main/resources/contents/omc_halloween/configs/items.yml @@ -93,44 +93,44 @@ items: y: 0.8 z: 0.8 -recipes: - iaa_crafting_table: - fermentum: - shapeless: true - ingredients: - - item: omc_daily_events:golden_wheat - amount: 5 - - item: omc_daily_events:golden_beetroot - amount: 5 - - item: omc_daily_events:really_golden_carrot - amount: 5 - - item: omc_daily_events:golden_potato - amount: 5 - - item: omc_daily_events:golden_melon - amount: 5 - - item: omc_daily_events:golden_pumpkin - amount: 5 - result: - item: omc_daily_events:fermentum - - blessed_bread: - enabled: true - pattern: - - FFF - - XXX - - XXX - pattern_2: - - XXX - - FFF - - XXX - pattern_3: - - XXX - - XXX - - FFF - ingredients: - F: - item: omc_daily_events:golden_wheat - amount: 192 - result: - item: omc_daily_events:blessed_bread - amount: 1 \ No newline at end of file +#recipes: +# iaa_crafting_table: +# fermentum: +# shapeless: true +# ingredients: +# - item: omc_daily_events:golden_wheat +# amount: 5 +# - item: omc_daily_events:golden_beetroot +# amount: 5 +# - item: omc_daily_events:really_golden_carrot +# amount: 5 +# - item: omc_daily_events:golden_potato +# amount: 5 +# - item: omc_daily_events:golden_melon +# amount: 5 +# - item: omc_daily_events:golden_pumpkin +# amount: 5 +# result: +# item: omc_daily_events:fermentum +# +# blessed_bread: +# enabled: true +# pattern: +# - FFF +# - XXX +# - XXX +# pattern_2: +# - XXX +# - FFF +# - XXX +# pattern_3: +# - XXX +# - XXX +# - FFF +# ingredients: +# F: +# item: omc_daily_events:golden_wheat +# amount: 192 +# result: +# item: omc_daily_events:blessed_bread +# amount: 1 \ No newline at end of file diff --git a/src/main/resources/contents/omc_menus/configs/menus.yml b/src/main/resources/contents/omc_menus/configs/menus.yml index 5269f778a..559334752 100644 --- a/src/main/resources/contents/omc_menus/configs/menus.yml +++ b/src/main/resources/contents/omc_menus/configs/menus.yml @@ -65,7 +65,7 @@ font_images: permission: halloween.event_main_menu show_in_gui: true suggestion_in_command: false - path: "halloween/halloween_event_main_menu.png" + path: "halloween/halloween_festival_main_menu.png" y_position: 30 halloween_candy_jar_0: permission: halloween.halloween_candy_jar_0 From b4c105546b817c5ac288f515ed82d42822ed56a4 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:39:12 +0200 Subject: [PATCH 21/44] fix halloween root plush ( change name later ) --- .../contents/omc_halloween/models/{items => }/root_plush.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/main/resources/contents/omc_halloween/models/{items => }/root_plush.json (98%) diff --git a/src/main/resources/contents/omc_halloween/models/items/root_plush.json b/src/main/resources/contents/omc_halloween/models/root_plush.json similarity index 98% rename from src/main/resources/contents/omc_halloween/models/items/root_plush.json rename to src/main/resources/contents/omc_halloween/models/root_plush.json index 001b3ead5..3ed965538 100644 --- a/src/main/resources/contents/omc_halloween/models/items/root_plush.json +++ b/src/main/resources/contents/omc_halloween/models/root_plush.json @@ -3,8 +3,8 @@ "credit": "Made by Gex and rework by Nocolm", "texture_size": [64, 64], "textures": { - "2": "omc_halloween:root_halloween_plush_texture", - "particle": "omc_halloween:root_halloween_plush_texture" + "2": "omc_halloween:models/root_halloween_plush_texture", + "particle": "omc_halloween:models/root_halloween_plush_texture" }, "elements": [ { From 05cd2fb6134cb04af4ca2e670945ac4568cf113f Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:39:47 +0200 Subject: [PATCH 22/44] fix LeaderBoard error --- .../leaderboards/leaderboards/PumpkinCountLeaderBoard.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 172b5d150..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 @@ -5,7 +5,6 @@ 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); From 10c475a2b29c876bfaf4cd7c386ebb569bbf3499 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sat, 24 Oct 2026 00:41:31 +0200 Subject: [PATCH 23/44] fix Menus --- .../festival/shop/WitchShopManager.java | 2 +- .../shop/menu/WitchShopStoreMenu.java | 11 ++++-- .../shop/menu/buttons/ChoiceButton.java | 2 +- .../witchhouse/TerrorHouseManager.java | 12 ++++-- .../advancement/menu/AdvancementMenu.java | 9 ++++- .../advancement/menu/CandyChoiceMenu.java | 25 +++++++++--- .../advancement/menu/ConfirmSellMenu.java | 39 +++++++++++-------- .../advancement/menu/RewardViewMenu.java | 23 ++++++++--- .../advancement/reward/EmptyReward.java | 2 +- .../reward/plush/HalloweenRoot2026.java | 4 +- 10 files changed, 87 insertions(+), 42 deletions(-) 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 index 372c0b5ee..673715fd0 100644 --- 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 @@ -137,7 +137,7 @@ public static void sellItem(Player player, ShopMoney item, int amount) { TerrorHouseManager.updateAdvancement(totalScore); sendInfo(player, TranslationManager.translation("feature.adminshop.player_sell_item", //TODO - Component.text(amount))); //TODO dire "vous avez ajouter xxxx points" + Component.text(amount))); //TODO dire "You add xxxx points for xx " } private static void sendError(Player player, Component message) { 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 index 2d73ca4fa..9e6009a5b 100644 --- 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 @@ -32,7 +32,7 @@ public class WitchShopStoreMenu extends PaginatedMenu { @Getter private final int page; - private final Column.Range line = new Column.Range(1, 7); + private final Column.Range LINE = new Column.Range(1, 7); private final int COLUMN = 4; public WitchShopStoreMenu(Player owner, int page) { @@ -55,7 +55,12 @@ public WitchShopStoreMenu(Player owner, int page) { @Override public @NotNull List getStaticSlots() { - return StaticSlots.getStandardSlots(getInventorySize()); + 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 @@ -66,7 +71,7 @@ public List getItems() { Iterator contents = WitchShopManager.getStoreContent(this.page).iterator(); for (int c = 0; c < COLUMN; c++) { - for (int l = line.floor(); l <= line.ceiling(); l++) { + for (int l = LINE.floor(); l <= LINE.ceiling(); l++) { if (!contents.hasNext()) break; 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 index fbe6e4558..ea8329622 100644 --- 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 @@ -19,7 +19,7 @@ public static void init(Menu menu, Map contents, int[] contents, slots, new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { - itemMeta.displayName(TranslationManager.translation("feature.city.menus.main.ranks.title"));//TODO + itemMeta.displayName(Component.text("test OwO"));//TODO itemMeta.lore(TranslationManager.translationLore( "feature.city.menus.main.ranks.lore.unlocked", //TODO Component.text("").color(NamedTextColor.LIGHT_PURPLE) 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 index afca3729c..caabf1793 100644 --- 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 @@ -33,7 +33,9 @@ public class TerrorHouseManager { public static int globalAdvancement; public static int floorAdvancement; - public static boolean finalRoomReach; + 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 @@ -42,15 +44,17 @@ public class TerrorHouseManager { public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.WITCH_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 enabledFloors = EnumUtils.getValuesBefore(currentFloorToReach, false); - - finalRoomReach = currentFloorToReach.equals(Floors.FLOOR_2); //TODO last floor FLOOR_15 + finalFloorReach = currentFloorToReach.equals(FINAL_FLOOR); for (Floors floors : Floors.values()) { Floor floor = floors.getFloor(); @@ -69,7 +73,7 @@ public static void updateAdvancement(int increase) { CheckForPointRewards(); - if (currentFloorToReach.equals(Floors.FLOOR_2)) //TODO last floor FLOOR_15 + if (currentFloorToReach.equals(FINAL_FLOOR)) return; if (currentFloorToReach.getRequire() > floorAdvancement) 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 index 4d3a0aabc..e4c9a47fd 100644 --- 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 @@ -5,11 +5,14 @@ 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; @@ -62,8 +65,12 @@ public void onInventoryClick(InventoryClickEvent e) { public @NotNull Map getContent() { Map content = new HashMap<>(); - content.put(21, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.CANDY_RED, itemMeta -> { + content.put(22, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.CANDY_RED, itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.lore(List.of( + Component.text("Total des points : " + EconomyManager.getFormattedSimplifiedNumber(TerrorHouseManager.globalAdvancement) + " " + WitchShopManager.getHalloweenPointIcon()) + .color(NamedTextColor.GOLD) + )); }).setOnClick(click -> { if (click.isRightClick()) { new RewardViewMenu(getOwner()).open(); 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 index b3e4e8c7e..6d63d8e37 100644 --- 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 @@ -6,8 +6,10 @@ 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 net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; @@ -30,7 +32,7 @@ public CandyChoiceMenu(Player owner) { @Override public String getTexture() { - return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_deposit_menu:"); //TODO + return FontImageWrapper.replaceFontImages("§r§f:offset_-48::halloween_deposit_menu:"); } @Override @@ -49,32 +51,37 @@ public void onInventoryClick(InventoryClickEvent e) { content.put(9, new ItemMenuBuilder(this, ShopMoney.MONSTER_CANDY.getItem(), itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.lore(getCandyPoints(ShopMoney.MONSTER_CANDY)); }).setOnClick(click -> { - new ConfirmSellMenu(getOwner(), ShopMoney.MONSTER_CANDY); + new ConfirmSellMenu(getOwner(), ShopMoney.MONSTER_CANDY).open(); })); content.put(20, new ItemMenuBuilder(this, ShopMoney.GREEN_CANDY.getItem(), itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.lore(getCandyPoints(ShopMoney.GREEN_CANDY)); }).setOnClick(click -> { - new ConfirmSellMenu(getOwner(), ShopMoney.GREEN_CANDY); + new ConfirmSellMenu(getOwner(), ShopMoney.GREEN_CANDY).open(); })); content.put(13, new ItemMenuBuilder(this, ShopMoney.BLUE_CANDY.getItem(), itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.lore(getCandyPoints(ShopMoney.BLUE_CANDY)); }).setOnClick(click -> { - new ConfirmSellMenu(getOwner(), ShopMoney.BLUE_CANDY); + new ConfirmSellMenu(getOwner(), ShopMoney.BLUE_CANDY).open(); })); content.put(24, new ItemMenuBuilder(this, ShopMoney.RED_CANDY.getItem(), itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.lore(getCandyPoints(ShopMoney.RED_CANDY)); }).setOnClick(click -> { - new ConfirmSellMenu(getOwner(), ShopMoney.RED_CANDY); + new ConfirmSellMenu(getOwner(), ShopMoney.RED_CANDY).open(); })); content.put(17, new ItemMenuBuilder(this, ShopMoney.YELLOW_CANDY.getItem(), itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.lore(getCandyPoints(ShopMoney.YELLOW_CANDY)); }).setOnClick(click -> { - new ConfirmSellMenu(getOwner(), ShopMoney.YELLOW_CANDY); + new ConfirmSellMenu(getOwner(), ShopMoney.YELLOW_CANDY).open(); })); content.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { @@ -95,4 +102,10 @@ public void onClose(InventoryCloseEvent event) { public List getTakableSlot() { return List.of(); } + + private List getCandyPoints(ShopMoney money) { + return List.of(Component.text("Valeur : " + money.getScores() + " " + WitchShopManager.getHalloweenPointIcon()) + .color(NamedTextColor.GOLD) + );//TODO translate + } } 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 index 68507f546..ce7c4e718 100644 --- 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 @@ -1,5 +1,6 @@ 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; @@ -7,8 +8,6 @@ import fr.openmc.api.menulib.utils.ItemMenuBuilder; import fr.openmc.core.OMCRegistry; import fr.openmc.core.features.adminshop.AdminShopManager; -import fr.openmc.core.features.adminshop.ShopItem; -import fr.openmc.core.features.economy.EconomyManager; 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; @@ -17,7 +16,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; -import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; @@ -42,7 +40,7 @@ public ConfirmSellMenu(Player owner, ShopMoney shopItem) { super(owner); this.shopItem = shopItem; this.quantity = 1; - this.maxQuantity = countPlayerItems(owner, shopItem.getItem().getBest()); + this.maxQuantity = countPlayerCandies(); } @Override @@ -77,9 +75,9 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} 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(EconomyManager.getEconomyIcon(), NamedTextColor.GREEN), //TODO faire icon halloween point + Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN), Component.text(AdminShopManager.priceFormat.format(totalScore), NamedTextColor.GREEN), - Component.text(EconomyManager.getEconomyIcon(), NamedTextColor.GREEN), //TODO faire icon halloween point + Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN), shiftRightSellAll ); @@ -129,9 +127,9 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} int itemCount = ItemUtils.countItems(getOwner(), shopItem.getItem().getBest()); if (itemCount > 0) { getOwner().closeInventory(); - AdminShopManager.sellItem( + WitchShopManager.sellItem( getOwner(), - shopItem.getItem().getId(), + shopItem, itemCount ); } @@ -192,16 +190,23 @@ private ItemMenuBuilder createQuantityButton(String text, CustomItem customItem, /** * Counts the number of items of a specific material in a player's inventory. * - * @param player The player whose inventory to check. - * @param toCount The item to count. * @return The count of items of the specified material in the player's inventory. */ - private int countPlayerItems(Player player, ItemStack toCount) { - int count = 0; - for (ItemStack item : player.getInventory().getContents()) - if (item != null && item.isSimilar(toCount)) - count += item.getAmount(); - return count; + private int countPlayerCandies() { + int amount = 0; + + for (ItemStack item : getOwner().getInventory().getContents()) { + if (item == null) continue; + + CustomStack customStack = CustomStack.byItemStack(item); + if (customStack == null) continue; + + if (customStack.getNamespacedID().equals( + shopItem.getItem().getCustomStack().getNamespacedID())) + amount += item.getAmount(); + } + + return amount; } /** @@ -210,7 +215,7 @@ private int countPlayerItems(Player player, ItemStack toCount) { * @param amount The amount to increase the quantity by. */ private void increaseQuantity(int amount) { - int playerItemCount = countPlayerItems(getOwner(), shopItem.getItem().getBest()); + int playerItemCount = countPlayerCandies(); quantity = Math.min(quantity + amount, playerItemCount); this.open(); } 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 index 4ff27cfe5..63b8a8ca2 100644 --- 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 @@ -5,11 +5,12 @@ 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.menu.WitchShopMainMenu; +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.reward.PointReward; +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; @@ -18,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Stream; public class RewardViewMenu extends Menu { @@ -49,11 +51,20 @@ public void onInventoryClick(InventoryClickEvent e) { public @NotNull Map getContent() { Map content = new HashMap<>(); - PointReward reward = TerrorHouseManager.currentRewardToReach.getReward(); + PointRewards reward = TerrorHouseManager.currentRewardToReach; - content.put(13, new ItemMenuBuilder(this, reward.getItemMenuPreview(), itemMeta -> { - itemMeta.displayName(reward.getRewardName()); - itemMeta.lore(reward.getRewardLore()); + 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 -> { 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 index 403001063..3ed879966 100644 --- 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 @@ -22,6 +22,6 @@ public Component getRewardName() { @Override public List getRewardLore() { - return new ArrayList<>(); + return List.of(Component.empty()); } } 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 index cd5ddba72..02b41f7f1 100644 --- 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 @@ -57,11 +57,11 @@ public ItemStack getItemMenuPreview() { @Override public Component getRewardName() { - return null; //TODO item name + return Component.empty(); //TODO item name } @Override public List getRewardLore() { - return null; //TODO item lore + return List.of(Component.empty()); //TODO item lore } } From e21382d7c02f371cdd0ce640919319062e83b111 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sun, 25 Oct 2026 22:17:11 +0100 Subject: [PATCH 24/44] =?UTF-8?q?Change=20StructureRegistry=20(=20=C3=A7a?= =?UTF-8?q?=20marche=20!=20)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../registry/structures/CustomStructure.java | 339 +++++++----------- .../structures/CustomStructureRegistry.java | 30 +- .../model/CustomStructureManager.java | 51 ++- .../structures/model/DBPlacedStructure.java | 39 +- 4 files changed, 195 insertions(+), 264 deletions(-) diff --git a/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java index 4bc9e05f7..a880e234b 100644 --- a/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java @@ -1,6 +1,5 @@ package fr.openmc.core.registry.structures; - import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -15,306 +14,234 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.session.ClipboardHolder; -import fr.openmc.core.OMCPlugin; -import fr.openmc.core.bootstrap.integration.OMCLogger; 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.List; import java.util.UUID; -import java.util.concurrent.CompletableFuture; /** - * Une structure réutilisable (ex: "maison"). Elle peut être posée autant de fois qu'on veut, - * chaque placement étant identifié par son propre 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 { - // Format utilisé pour stocker les undos en DB private static final ClipboardFormat BACKUP_FORMAT = BuiltInClipboardFormat.SPONGE_V3_SCHEMATIC; - private final OMCPlugin plugin = OMCPlugin.getInstance(); @Getter private final String id; - private final File file; // .schem / .schematic / .nbt + private final File file; public CustomStructure(String id, File file) { this.id = id; this.file = file; } - // ------------------------------------------------------------------ PLACE - - /** Pose la structure avec un UUID de placement généré. */ - public CompletableFuture place(Location location) { - - if (!CustomStructureManager.actionAllow()) return null; - + /** + * Places this structure and generates a unique ID for the placement. + */ + public UUID place(Location location) throws Exception { return place(UUID.randomUUID(), location); } /** - * Pose la structure en lui donnant un identifiant UUID. - * Échoue si cet UUID est déjà utilisé par un placement existant. - * Peut être appelé depuis n'importe quel thread. - * - * @return le même UUID, une fois la structure posée et l'undo sauvegardé + * Places this structure using the provided placement ID. + * An ID that already exists in the database is rejected. */ - public CompletableFuture place(UUID placementId, Location location) { - - if (!CustomStructureManager.actionAllow()) return null; - - CompletableFuture future = new CompletableFuture<>(); - final Location loc = location.clone(); - - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - try { - if (CustomStructureManager.existsPlacement(placementId)) { - future.completeExceptionally(new IllegalStateException( - "Le placement " + placementId + " existe déjà")); - return; - } - } catch (Exception e) { - future.completeExceptionally(e); - return; - } + public UUID place(UUID placementId, Location location) throws Exception { + requireMainThread(); - Bukkit.getScheduler().runTask(plugin, () -> { - final DBPlacedStructure entry; - try { - entry = pasteWithBackup(placementId, loc); - } catch (Exception e) { - future.completeExceptionally(e); - return; - } - - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - try { - CustomStructureManager.savePlacement(entry); - future.complete(placementId); - } catch (Exception e) { - OMCLogger.error("Structure posée mais undo non sauvegardé !", e); - future.completeExceptionally(e); - } - }); - }); - }); - return future; - } - - private DBPlacedStructure pasteWithBackup(UUID placementId, Location loc) throws Exception { - - if (!CustomStructureManager.actionAllow()) return null; - - Clipboard structure = readFile(file); - com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(loc.getWorld()); - - // Zone du monde qui sera écrasée - BlockVector3 to = BukkitAdapter.asBlockVector(loc); - BlockVector3 offset = to.subtract(structure.getOrigin()); - - Region r = structure.getRegion(); + 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."); + } - BlockVector3 min = r.getMinimumPoint().add(offset); - BlockVector3 max = r.getMaximumPoint().add(offset); + 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); - CuboidRegion area = new CuboidRegion(weWorld, min, max); + 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)) { - // 1) sauvegarde de l'existant - BlockArrayClipboard backup = new BlockArrayClipboard(area); - ForwardExtentCopy copy = new ForwardExtentCopy(session, area, backup, min); + BlockArrayClipboard backup = new BlockArrayClipboard(affectedRegion); + backup.setOrigin(min); + + ForwardExtentCopy copy = new ForwardExtentCopy(session, affectedRegion, backup, min); copy.setCopyingEntities(false); Operations.complete(copy); - // 2) collage + backupData = serialize(backup); + Operations.complete(new ClipboardHolder(structure) .createPaste(session) - .to(to) + .to(target) .ignoreAirBlocks(false) .build()); - - return new DBPlacedStructure(placementId, id, loc.getWorld().getUID().toString(), - min.x(), min.y(), min.z(), serialize(backup)); } - } - - /** Retire UN placement précis grâce à son UUID. - * @return false si introuvable. - */ - public CompletableFuture remove(UUID placementId) { - if (!CustomStructureManager.actionAllow()) return null; + DBPlacedStructure placement = new DBPlacedStructure( + placementId, + id, + world.getUID().toString(), + min.x(), + min.y(), + min.z(), + backupData + ); - return removeInternal(() -> CustomStructureManager.getPlacement(placementId)); - } + try { + CustomStructureManager.savePlacement(placement); + } catch (Exception exception) { + // Roll back the paste if the placement could not be recorded. + restoreBackup(world, min, backupData); + throw exception; + } - /** Retire le placement le plus récent de cette structure. */ - public CompletableFuture removeLast() { - return removeInternal(() -> CustomStructureManager.getLatestPlacement(id)); + return placementId; } - /** Retire TOUS les placements de cette structure (du plus récent au plus ancien). @return le nombre retiré */ - public CompletableFuture removeAll() { - - if (!CustomStructureManager.actionAllow()) return null; + /** + * 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(); - return list().thenCompose(placements -> { - CompletableFuture chain = CompletableFuture.completedFuture(0); - for (DBPlacedStructure p : placements) { - chain = chain.thenCompose(count -> - remove(p.getId()).thenApply(ok -> ok ? count + 1 : count)); - } - return chain; - }); - } + if (!CustomStructureManager.actionAllow()) { + throw new IllegalStateException("WorldEdit or FastAsyncWorldEdit is not enabled."); + } - /** Tous les placements de cette structure, du plus récent au plus ancien. */ - public CompletableFuture> list() { - CompletableFuture> f = new CompletableFuture<>(); - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - try { f.complete(CustomStructureManager.getPlacements(id)); } - catch (Exception e) { f.completeExceptionally(e); } - }); - return f; - } + DBPlacedStructure placement = CustomStructureManager.getPlacement(placementId); + if (placement == null || !id.equals(placement.getStructureId())) { + return false; + } - public CompletableFuture exists(UUID placementId) { - CompletableFuture f = new CompletableFuture<>(); - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - try { f.complete(CustomStructureManager.existsPlacement(placementId)); } - catch (Exception e) { f.completeExceptionally(e); } - }); - return f; - } + World world = Bukkit.getWorld(UUID.fromString(placement.getWorld())); + if (world == null) { + throw new IllegalStateException("World not found: " + placement.getWorld()); + } - private interface Lookup { DBPlacedStructure get() throws Exception; } - - private CompletableFuture removeInternal(Lookup lookup) { - - if (!CustomStructureManager.actionAllow()) return null; - - CompletableFuture future = new CompletableFuture<>(); - - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - // 1) lecture DB - final DBPlacedStructure placed; - try { - placed = lookup.get(); - } catch (Exception e) { future.completeExceptionally(e); return; } - if (placed == null) { future.complete(false); return; } - - Bukkit.getScheduler().runTask(plugin, () -> { - // 2) restauration (main thread) - try { - World world = Bukkit.getWorld(UUID.fromString(placed.getWorld())); - if (world == null) throw new IllegalStateException("Monde introuvable"); - restore(placed, world); - } catch (Exception e) { future.completeExceptionally(e); return; } - - Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { - // 3) suppression de la ligne - try { - CustomStructureManager.deletePlacement(placed.getId()); - future.complete(true); - } catch (Exception e) { future.completeExceptionally(e); } - }); - }); - }); - return future; + BlockVector3 min = BlockVector3.at(placement.getX(), placement.getY(), placement.getZ()); + restoreBackup(world, min, placement.getBackup()); + CustomStructureManager.deletePlacement(placementId); + return true; } - private void restore(DBPlacedStructure placed, World world) throws Exception { - - if (!CustomStructureManager.actionAllow()) return; - - Clipboard backup = deserialize(placed.getBackup()); - backup.setOrigin(backup.getRegion().getMinimumPoint()); - BlockVector3 min = BlockVector3.at(placed.getX(), placed.getY(), placed.getZ()); - + 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) // remet aussi l'air + .ignoreAirBlocks(false) .build()); } } - /** Lit un .schem / .schematic via WorldEdit, ou un .nbt vanilla converti en clipboard WorldEdit. */ - private static Clipboard readFile(File file) throws IOException { - - if (!CustomStructureManager.actionAllow()) return null; + 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("Format de schematic inconnu : " + file.getName()); - try (ClipboardReader reader = format.getReader(new FileInputStream(file))) { + + ClipboardFormat format = ClipboardFormats.findByPath(file.toPath()); + 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(); } } /** - * Convertit un .nbt (structure block) en clipboard WorldEdit, sans rien placer dans le monde. - * Limites : le contenu des tile entities (coffres, panneaux...) et les entités ne sont pas conservés. + * 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 { - - if (!CustomStructureManager.actionAllow()) return null; - Structure structure = Bukkit.getStructureManager().loadStructure(file); - if (structure.getPaletteCount() == 0) throw new IOException("Structure vide : " + file.getName()); - - BlockVector size = structure.getSize(); - CuboidRegion region = new CuboidRegion( - BlockVector3.ZERO, - BlockVector3.at(size.getBlockX() - 1, size.getBlockY() - 1, size.getBlockZ() - 1)); - BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - clipboard.setOrigin(BlockVector3.ZERO); + BlockArrayClipboard clipboard = getBlockArrayClipboard(file, structure); try { - for (org.bukkit.block.BlockState state : structure.getPalettes().get(0).getBlocks()) { - BlockVector3 pos = BlockVector3.at(state.getX(), state.getY(), state.getZ()); - clipboard.setBlock(pos, BukkitAdapter.adapt(state.getBlockData())); + 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 e) { - throw new IOException("Conversion du .nbt impossible : " + file.getName(), e); + } catch (Exception exception) { + throw new IOException("Could not convert NBT structure: " + file.getName(), exception); } + return clipboard; } - private static byte[] serialize(Clipboard clipboard) throws IOException { + private static @NotNull BlockArrayClipboard getBlockArrayClipboard(File file, Structure structure) throws IOException { + if (structure.getPaletteCount() == 0) { + throw new IOException("Structure is empty: " + file.getName()); + } - if (!CustomStructureManager.actionAllow()) return null; + 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; + } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try (ClipboardWriter writer = BACKUP_FORMAT.getWriter(out)) { + private static byte[] serialize(Clipboard clipboard) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (ClipboardWriter writer = BACKUP_FORMAT.getWriter(output)) { writer.write(clipboard); } - return out.toByteArray(); + 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."); + } - if (!CustomStructureManager.actionAllow()) return null; - - try (ClipboardReader reader = BACKUP_FORMAT.getReader(new ByteArrayInputStream(data))) { + try (ByteArrayInputStream input = new ByteArrayInputStream(data); + ClipboardReader reader = BACKUP_FORMAT.getReader(input)) { return reader.read(); } } -} \ No newline at end of file + + 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 index 5487afe73..ab2919c88 100644 --- a/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java @@ -12,29 +12,35 @@ public class CustomStructureRegistry extends Registry implements KeyedRegistry, LoadIfEnable { - private static final File structureFolder = new File(OMCPlugin.getInstance().getDataFolder(), "data/omc_structure"); + private static final File STRUCTURE_FOLDER = + new File(OMCPlugin.getInstance().getDataFolder(), "data/omc_structure"); - public static final String structureKey = "omc_structure"; + public static final String STRUCTURE_KEY = "omc_structure"; - // ** REGISTER STRUCTURES ** - public final CustomStructure WITCH_SHOP = register("test","pillar.nbt"); + public final CustomStructure WITCH_SHOP = register("test", "pillar.nbt"); public CustomStructureRegistry() { - FilesUtils.createDirectoryIfNotExists(structureFolder); + FilesUtils.createDirectoryIfNotExists(STRUCTURE_FOLDER); } @Override - public String key(CustomStructure registryObject) { - return registryObject.getId(); + public String key(CustomStructure structure) { + return structure.getId(); } public CustomStructure register(String name, String fileName) { - return register(name, new File(structureFolder, fileName)); + FilesUtils.createDirectoryIfNotExists(STRUCTURE_FOLDER); + return register(name, new File(STRUCTURE_FOLDER, fileName)); } public CustomStructure register(String name, File file) { - if (file == null || name == null) return null; - if (!file.exists()) return null; - return KeyedRegistry.super.register(new CustomStructure((structureKey + name), 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)); } -} \ No newline at end of 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 index 992a7fb98..d2256363e 100644 --- a/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java +++ b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java @@ -6,7 +6,7 @@ import com.j256.ormlite.table.TableUtils; import fr.openmc.core.bootstrap.features.Feature; import fr.openmc.core.bootstrap.features.types.HasDatabase; -import fr.openmc.core.bootstrap.integration.OMCLogger; +import fr.openmc.core.bootstrap.features.types.LoadIfEnable; import fr.openmc.core.hooks.WorldEditHook; import java.sql.SQLException; @@ -14,66 +14,55 @@ import java.util.UUID; /** - * Feature qui porte uniquement la table des undos de structures. - * Les accès DB sont synchrones : à appeler hors du thread principal (voir CustomStructure). + * Provides simple synchronous database access for placed structures. */ -public class CustomStructureManager extends Feature implements HasDatabase { +public class CustomStructureManager extends Feature implements + LoadIfEnable, HasDatabase { private static Dao dao; - public static boolean WELoaded = false; - - @Override - public void init() { - WELoaded = WorldEditHook.isEnable(); - } - @Override public void initDB(ConnectionSource connectionSource) throws SQLException { TableUtils.createTableIfNotExists(connectionSource, DBPlacedStructure.class); dao = DaoManager.createDao(connectionSource, DBPlacedStructure.class); } -// @Override -// protected void save() { -// -// } - - public static void savePlacement(DBPlacedStructure p) throws SQLException { - dao.create(p); + 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 DBPlacedStructure getLatestPlacement(String structureId) throws SQLException { - return dao.queryBuilder() - .orderBy("createdAt", false) - .where().eq("structureId", structureId) - .queryForFirst(); - } - - /** Du plus récent au plus ancien. */ public static List getPlacements(String structureId) throws SQLException { + requireInitialized(); return dao.queryBuilder() .orderBy("createdAt", false) - .where().eq("structureId", structureId) + .where() + .eq("structureId", structureId) .query(); } public static void deletePlacement(UUID id) throws SQLException { + requireInitialized(); dao.deleteById(id); } public static boolean actionAllow() { - if (!WELoaded) - OMCLogger.warn("Action prevent from use because WE or FAWE not enable"); - return WELoaded; + 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 index 96c1c21db..73814e403 100644 --- a/src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java +++ b/src/main/java/fr/openmc/core/registry/structures/model/DBPlacedStructure.java @@ -1,6 +1,5 @@ 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; @@ -8,39 +7,49 @@ import java.util.UUID; -/** Une instance de structure posée dans le monde + la sauvegarde de ce qu'il y avait avant (undo). */ +/** + * Stores one placed structure and the blocks that were there before it was placed. + */ @Getter @DatabaseTable(tableName = "structures_placed") public class DBPlacedStructure { - /** Identifiant unique de CE placement (pas de la structure). */ @DatabaseField(id = true, dataType = DataType.UUID) private UUID id; - /** Id de la CustomStructure (ex: "maison"). Plusieurs placements peuvent avoir le même. */ - @DatabaseField(canBeNull = false, index = true) + @DatabaseField(canBeNull = false) private String structureId; @DatabaseField(canBeNull = false) - private String world; // UUID du monde + private String world; + + @DatabaseField + private int x; - // Coin minimum de la zone sauvegardée - @DatabaseField private int x; - @DatabaseField private int y; - @DatabaseField private int z; + @DatabaseField + private int y; + + @DatabaseField + private int z; @DatabaseField(dataType = DataType.BYTE_ARRAY, canBeNull = false) - private byte[] backup; // schematic WorldEdit de la zone AVANT placement + private byte[] backup; - @DatabaseField private long createdAt; + @DatabaseField + private long createdAt; - public DBPlacedStructure() {} // requis par ORMLite + public DBPlacedStructure() { + // Required by ORMLite. + } - public DBPlacedStructure(UUID id, String structureId, String world, int x, int y, int z, byte[] backup) { + 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.x = x; + this.y = y; + this.z = z; this.backup = backup; this.createdAt = System.currentTimeMillis(); } From d7de00c6bb625bbdeb331dd52aee05b9392c0b10 Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sun, 25 Oct 2026 22:17:35 +0100 Subject: [PATCH 25/44] add infos to sb --- .../features/displays/scoreboards/sb/MainScoreboard.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 720128b1a..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,7 +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; @@ -70,8 +72,8 @@ public void update(Player player, SternalBoard board) { @Override protected List getSwapping() { return List.of( - //new HalloweenFestivalInfos(), - //new ContestInfos() + new HalloweenFestivalInfos(), + new ContestInfos() ); } From a5e0f1805d4752b065798b355b11bde367bcae9a Mon Sep 17 00:00:00 2001 From: Nocolm Date: Sun, 25 Oct 2026 22:17:43 +0100 Subject: [PATCH 26/44] add infos to sb --- .../sbinfos/HalloweenFestivalInfos.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java 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..2240a5b22 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java @@ -0,0 +1,76 @@ +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.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 net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.entity.Player; + +import java.time.DayOfWeek; +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(MiniMessage.miniMessage().deserialize( + "</gradient>", + Placeholder.component("title", TranslationManager.translation("feature.displays.scoreboard.corpse.title", true)) + ).decoration(TextDecoration.BOLD, true)); //TODO + + PointRewards reward = TerrorHouseManager.currentRewardToReach.getNextReward(); + 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("", + text(EconomyManager.getFormattedSimplifiedNumber(globalAdvancement)) + ) + + : TranslationManager.translation("", + 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("last floor reached")//TODO + : TranslationManager.translation("goal {étage} : xx / xx",//TODO + text(floorToReach.getSimplifyFloor()), + text(EconomyManager.getFormattedSimplifiedNumber(floorAdvancement)), + text(EconomyManager.getFormattedSimplifiedNumber(floorToReach.getRequire()))) + ) + ); + + lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) + .appendSpace() + .append(text(DateUtils.convertMillisToTime(HalloweenFestivalManager.getRemainingTime()), TextColor.color(0xFF8F06))) + ); + } +} From f7508e2ee22bf54a571874ba0e8c1d595e447cd3 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Tue, 27 Oct 2026 22:04:06 +0100 Subject: [PATCH 27/44] fix, add NPC and add some translations... --- src/main/java/fr/openmc/core/OMCPlugin.java | 5 +- .../halloween/festival/CandyItem.java | 2 +- ...ger.java => HalloweenFestivalManager.java} | 72 +++++++++++++-- .../listeners/TerrorHouseListener.java | 26 ++++-- .../halloween/festival/npc/WitchNPCS.java | 83 ++++++++++++++++++ .../halloween/festival/shop/ShopMoney.java | 13 +-- .../festival/shop/WitchShopItem.java | 1 - .../festival/shop/WitchShopManager.java | 69 ++++++++++----- .../festival/shop/menu/ConfirmBuyMenu.java | 12 +-- .../festival/shop/menu/WitchChoiceMenu.java | 8 +- .../festival/shop/menu/WitchShopMainMenu.java | 4 +- .../shop/menu/WitchShopStoreMenu.java | 6 +- .../shop/menu/buttons/ChoiceButton.java | 5 +- .../shop/menu/buttons/DepositButton.java | 5 +- ...ouseButton.java => TerrorHouseButton.java} | 9 +- .../shop/menu/buttons/WitchStoreButton.java | 7 +- .../witchhouse/TerrorHouseManager.java | 48 +++++++--- .../witchhouse/advancement/floor/Floor.java | 4 +- .../witchhouse/advancement/floor/Floors.java | 4 + .../advancement/menu/AdvancementMenu.java | 11 ++- .../advancement/menu/CandyChoiceMenu.java | 21 ++--- .../advancement/menu/ConfirmSellMenu.java | 20 ++--- .../advancement/menu/RewardViewMenu.java | 2 +- .../reward/plush/HalloweenRoot2026.java | 11 +-- .../mobs/floor1_3/HouseZombieLV1.java | 7 +- .../resources/data/omc_structure/pillar.nbt | Bin 0 -> 7642 bytes .../default/itemsadder.properties | 9 ++ .../translations/en_US/events.properties | 45 ++++++++++ .../translations/en_US/itemsadder.properties | 10 +++ 29 files changed, 398 insertions(+), 121 deletions(-) rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/{HalloweenManager.java => HalloweenFestivalManager.java} (61%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/npc/WitchNPCS.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/{TerorHouseButton.java => TerrorHouseButton.java} (75%) create mode 100644 src/main/resources/data/omc_structure/pillar.nbt diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 47f57d642..ffc7c1fdb 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -35,6 +35,7 @@ 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.festival.HalloweenFestivalManager; import fr.openmc.core.features.events.contents.halloween.pumpkin.managers.HalloweenManager; import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestParticlesUtils; @@ -62,6 +63,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; @@ -118,7 +120,8 @@ public class OMCPlugin extends JavaPlugin { MailboxManager::new, DiscordLinkManager::new, ProfileManager::new, - () -> new fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager(), + CustomStructureManager::new, + () -> new HalloweenFestivalManager(), () -> new ElevatorManager(), () -> new CorpseManager(), QuestsManager::new, 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 index 341a7d473..a6c1b8df0 100644 --- 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 @@ -30,7 +30,7 @@ public CandyItem(String candyID , int diabetesIndex, Material baseItem) { public @NonNull ItemStack getVanilla() { ItemStack item = new ItemStack(baseItem); item.editMeta(meta -> meta.itemName( - TranslationManager.translation("feature." + super.getId().replace(":", ".") + ".name") + TranslationManager.translation("itemsadder." + super.getId().replace(":", ".") + ".name") )); return item; } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java similarity index 61% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java index 9804c91fc..57c1c84f5 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java @@ -4,30 +4,38 @@ 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.HasCommands; -import fr.openmc.core.bootstrap.features.types.HasDatabase; -import fr.openmc.core.bootstrap.features.types.HasListeners; -import fr.openmc.core.bootstrap.features.types.LoadAfterItemsAdder; +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.listeners.TerrorHouseListener; +import fr.openmc.core.features.events.contents.halloween.festival.npc.WitchNPCS; 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.mailboxes.MailboxManager; +import fr.openmc.core.hooks.WorldEditHook; +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 lombok.Getter; +import net.kyori.adventure.text.Component; +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 HalloweenManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { +public class HalloweenFestivalManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { //TODO quand acheter truc dans shop, augmenté avancement bonbons pour débloqué les étages, quand tous les étages débloqué, faire obtenir des récompenses a tous les joueurs ayant contribué @@ -39,6 +47,9 @@ public class HalloweenManager extends Feature implements LoadAfterItemsAdder, Ha @Getter private static Set<UUID> participant; + private static final String EVENT_GROUP = "halloween_festival_event"; + private static final UUID EVENT_UUID = UUIDUtil.createOfflinePlayerUUID(EVENT_GROUP); + @Override public void init() { halloweenDB = loadEvent(); @@ -91,14 +102,46 @@ private static void saveEvent() { } } + public static void startEvent(long duration) { + if (hasStart()) + return; + + DynamicCooldownManager.use(EVENT_UUID, EVENT_GROUP, duration); + } + + public static void stopEvent() { + if (!DynamicCooldownManager.isReady(EVENT_UUID, EVENT_GROUP)) { + DynamicCooldownManager.clear(EVENT_UUID, EVENT_GROUP, false); + } + } + + 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)) @@ -106,11 +149,28 @@ public static void sendMailItems(OMCPlayer player, OMCOfflinePlayer receiver, It }); } + 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); + } + } + @Override public Set<ListenerFactory> getListeners() { return Set.of( CandyListener::new, - TerrorHouseListener::new + TerrorHouseListener::new, + WitchNPCS::new ); } 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 index ee53d9626..90c87a2f2 100644 --- 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 @@ -1,13 +1,17 @@ package fr.openmc.core.features.events.contents.halloween.festival.listeners; import fr.openmc.core.commands.utils.SpawnManager; -import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; +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.Floor; import fr.openmc.core.features.events.contents.halloween.festival.witchhouse.advancement.floor.Floors; 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.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -23,15 +27,15 @@ public void onPlayerJoin(PlayerJoinEvent event) { if (!player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) return; - player.teleport(SpawnManager.getSpawnLocation()); - // TODO message + if (!HalloweenFestivalManager.isActive()) + player.teleport(SpawnManager.getSpawnLocation()); } @EventHandler public void onWorldChange(PlayerChangedWorldEvent event) { Player player = event.getPlayer(); - if (HalloweenManager.getHalloweenDB().isActive()) { + if (HalloweenFestivalManager.getHalloweenDB().isActive()) { if (event.getFrom().equals(DimensionGenerator.HALLOWEEN_WORLD)) TerrorHouseManager.getWitchHouseAmbient().reset(player); @@ -42,7 +46,12 @@ public void onWorldChange(PlayerChangedWorldEvent event) { if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) { player.teleport(SpawnManager.getSpawnLocation()); - // TODO message + MessagesManager.sendMessage(player, + TranslationManager.translation("feature.events.halloween.festival.player_not_allow"), + Prefix.HALLOWEEN, + MessageType.INFO, + true + ); } } } @@ -83,7 +92,12 @@ private void checkAndRepulse(CustomRegion region, Entity entity) { if (TerrorHouseManager.useRegions.contains(region)) if (entity instanceof Player player) { TerrorHouseManager.repulsePlayer(region, player, 0.3); - // TODO message + 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/npc/WitchNPCS.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/npc/WitchNPCS.java new file mode 100644 index 000000000..37d20d2ed --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/npc/WitchNPCS.java @@ -0,0 +1,83 @@ +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.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<Npc> 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("<red>☠ </red><gray><lang:feature.corpse.npc.display.owner:></gray>");//TODO + + 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; + + 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 index 868f59ea4..a5447aefd 100644 --- 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 @@ -2,17 +2,18 @@ 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 { - //TODO rajouter les crafts + Translation pour 'name' - RED_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_RED, 1000), - YELLOW_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_YELLOW, 10000), //extremely rare no craft - GREEN_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_GREEN, 10), - BLUE_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BLUE, 100), - MONSTER_CANDY(Component.text("candy_brown"), OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 1), + //TODO rajouter les crafts + 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; 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 index 906033c65..ddc1e73b0 100644 --- 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 @@ -1,6 +1,5 @@ package fr.openmc.core.features.events.contents.halloween.festival.shop; -import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; 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; 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 index 673715fd0..5c3319f68 100644 --- 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 @@ -4,7 +4,7 @@ import fr.openmc.api.omcplayer.OMCPlayer; import fr.openmc.core.OMCRegistry; import fr.openmc.core.features.adminshop.AdminShopUtils; -import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; +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; @@ -74,17 +74,12 @@ 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")); //TODO + 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")); //TODO - return; - } - - if (item.getPrice() <= 0) { - sendError(player, TranslationManager.translation("feature.adminshop.item_not_sellable")); //TODO + sendError(player, TranslationManager.translation("feature.adminshop.inventory_full")); return; } @@ -93,18 +88,24 @@ public static void buyItem(Player player, WitchShopItem item, int amount) { ItemUtils.giveItem((OMCPlayer) player, item.getItem().getBest(), amount); - sendInfo(player, TranslationManager.translation("feature.adminshop.player_buy_item", //TODO - Component.text(amount), item.getName(), Component.text(AdminShopUtils.formatPrice(totalPrice)) + sendInfo(player, TranslationManager.translation( + "feature.events.halloween.festival.shop.player_buy_item", + Component.text(amount), item.getName(), + Component.text(AdminShopUtils.formatPrice(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()); - HalloweenManager.addParticipant(player.getUniqueId()); + HalloweenFestivalManager.addParticipant(player.getUniqueId()); } else { - sendError(player, TranslationManager.translation("feature.adminshop.have_enough_money")); //TODO + sendError(player, TranslationManager.translation( + "feature.events.halloween.festival.player_not_enough_item", + item.getShopMoney().getName() + )); } } @@ -119,13 +120,16 @@ 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")); //TODO + 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.adminshop.player_not_enough_item")); //TODO + sendError(player, TranslationManager.translation( + "feature.events.halloween.festival.player_not_enough_item", + item.getName() + )); return; } @@ -136,8 +140,25 @@ public static void sellItem(Player player, ShopMoney item, int amount) { TerrorHouseManager.updateAdvancement(totalScore); - sendInfo(player, TranslationManager.translation("feature.adminshop.player_sell_item", //TODO - Component.text(amount))); //TODO dire "You add xxxx points for xx <candy.sprite>" + if (totalScore >= 100_000) { + + HalloweenFestivalManager.broadcast(TranslationManager.translation( + "feature.events.halloween.festival.deposit.broadcast_add_point", + player.displayName(), + Component.text(totalScore), + Component.text(getHalloweenPointIcon()), + Component.text(amount), + item.getItem().getSprite() + )); + } else { + sendInfo(player, TranslationManager.translation( + "feature.events.halloween.festival.deposit.add_point", + Component.text(totalScore), + Component.text(getHalloweenPointIcon()), + Component.text(amount), + item.getItem().getSprite() + )); + } } private static void sendError(Player player, Component message) { @@ -153,24 +174,28 @@ public static List<Component> extractLoreForItem(WitchShopItem item) { List<Component> lore = new ArrayList<>(); if (TerrorHouseManager.enabledFloors.contains(item.getAdvancements())) { - lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy", //TODO + 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.adminshop.lore_item.buy", //TODO halloween.shop.points - Component.text(item.getShopMoney().getScores()).color(NamedTextColor.BLUE) + lore.add(TranslationManager.translation("feature.events.halloween.festival.shop.lore_item.point", + Component.text(item.getShopMoney().getScores()), + Component.text(getHalloweenPointIcon()) ).decoration(TextDecoration.ITALIC, false)); } else { - lore.add(TranslationManager.translation("feature.adminshop.lore_item.buy." + item.getAdvancements().name().toLowerCase()) //TODO change key - .color(NamedTextColor.GREEN).decoration(TextDecoration.ITALIC, false)); + 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() + " " + item.getShopMoney().getItem().getSprite()); + return Component.text(item.getPrice()) + .appendSpace() + .append(item.getShopMoney().getItem().getSprite()); } public static String getHalloweenPointIcon() { 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 index df119e453..43724fa8d 100644 --- 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 @@ -42,7 +42,7 @@ public ConfirmBuyMenu(Player owner, WitchShopItem shopItem) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.adminshop.menu.confirm.name"); //TODO + return TranslationManager.translation("feature.adminshop.menu.confirm.name"); } @Override @@ -70,7 +70,7 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} int quantityToStack = Math.max(0, quantity / 64); - List<Component> lore = TranslationManager.translationLore("feature.adminshop.menu.confirm.lore", //TODO + List<Component> 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(), @@ -111,7 +111,7 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} if (event.getClick() == ClickType.MIDDLE) { DialogInput.sendFloat( getOwner(), - TranslationManager.translation("feature.adminshop.menu.confirm.input"), //TODO + TranslationManager.translation("feature.adminshop.menu.confirm.input"), 1, maxQuantity, quantity, @@ -155,10 +155,10 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} private ItemMenuBuilder createQuantityButton(String text, ItemStack itemStack, Consumer<InventoryClickEvent> action) { boolean plus = text.contains("+"); return new ItemMenuBuilder(this, itemStack, meta -> - meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", //TODO + meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", plus ? - TranslationManager.translation("feature.adminshop.menu.confirm.add") : //TODO - TranslationManager.translation("feature.adminshop.menu.confirm.remove"), //TODO + 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))) 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 index 2f417453a..b31002bcd 100644 --- 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 @@ -5,8 +5,7 @@ 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.TerorHouseButton; -import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.buttons.WitchStoreButton; +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; @@ -31,7 +30,7 @@ public WitchChoiceMenu(Player owner) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.city.menus.main.name"); //TODO + return TranslationManager.translation("feature.events.halloween.festival.menu.choice.name"); } @Override @@ -48,8 +47,7 @@ public String getTexture() { public @NotNull Map<Integer, ItemMenuBuilder> getContent() { Map<Integer, ItemMenuBuilder> inventory = new HashMap<>(); - // ** Witch House Button - TerorHouseButton.init(this, inventory, WITCH_HOUSE_SLOT); + TerrorHouseButton.init(this, inventory, WITCH_HOUSE_SLOT); DepositButton.init(this, inventory, DEPOSIT_SLOTS); 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 index eb5692953..9f11a629d 100644 --- 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 @@ -5,7 +5,6 @@ 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.TerorHouseButton; 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; @@ -31,7 +30,7 @@ public WitchShopMainMenu(Player owner) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.city.menus.main.name"); //TODO + return TranslationManager.translation("feature.events.halloween.festival.menu.main.name"); } @Override @@ -50,7 +49,6 @@ public String getTexture() { ChoiceButton.init(this, inventory, WITCH_HOUSE_SLOTS); - // ** Witch Store Button WitchStoreButton.init(this, inventory, WITCH_SHOP_SLOTS); return inventory; 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 index 9e6009a5b..f2a98153b 100644 --- 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 @@ -118,8 +118,10 @@ public Map<Integer, ItemMenuBuilder> getButtons() { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.city.menus.chest.name", - Component.text(""), Component.text(this.page)); //TODO + return TranslationManager.translation( + "feature.events.halloween.festival.menu.store.name", + Component.text(this.page) + ); } @Override 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 index ea8329622..49c8e9b41 100644 --- 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 @@ -19,10 +19,9 @@ public static void init(Menu menu, Map<Integer, ItemMenuBuilder> contents, int[] contents, slots, new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { - itemMeta.displayName(Component.text("test OwO"));//TODO + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.house.name")); itemMeta.lore(TranslationManager.translationLore( - "feature.city.menus.main.ranks.lore.unlocked", //TODO - Component.text("").color(NamedTextColor.LIGHT_PURPLE) + "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 index cd0b8fcb6..f4954178d 100644 --- 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 @@ -19,10 +19,9 @@ public static void init(Menu menu, Map<Integer, ItemMenuBuilder> contents, int[] contents, slots, new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { - itemMeta.displayName(TranslationManager.translation("feature.city.menus.main.ranks.title"));//TODO + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.deposit.name")); itemMeta.lore(TranslationManager.translationLore( - "feature.city.menus.main.ranks.lore.unlocked", //TODO - Component.text("").color(NamedTextColor.LIGHT_PURPLE) + "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/TerorHouseButton.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerrorHouseButton.java similarity index 75% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerorHouseButton.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerrorHouseButton.java index 2326eb272..d2a35f087 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerorHouseButton.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/shop/menu/buttons/TerrorHouseButton.java @@ -4,23 +4,20 @@ import fr.openmc.api.menulib.utils.ItemMenuBuilder; import fr.openmc.api.menulib.utils.MenuUtils; 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 TerorHouseButton { +public class TerrorHouseButton { public static void init(Menu menu, Map<Integer, ItemMenuBuilder> contents, int[] slots) { MenuUtils.createButtonItem( contents, slots, new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { - itemMeta.displayName(TranslationManager.translation("feature.city.menus.main.ranks.title"));//TODO + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.terror_house.name")); itemMeta.lore(TranslationManager.translationLore( - "feature.city.menus.main.ranks.lore.unlocked", //TODO - Component.text("").color(NamedTextColor.LIGHT_PURPLE) + "feature.events.halloween.festival.button.terror_house.lore" )); itemMeta.setItemModel(NamespacedKey.minecraft("air")); }).setCloseButton()//.setOnClick(inventoryClickEvent -> { //TODO tp dans la dimension 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 index b9e3c8ba1..e4c932d86 100644 --- 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 @@ -5,8 +5,6 @@ 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 net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; @@ -21,10 +19,9 @@ public static void init(Menu menu, Map<Integer, ItemMenuBuilder> contents, int[] contents, slots, new ItemMenuBuilder(menu, Material.PAPER, itemMeta -> { - itemMeta.displayName(TranslationManager.translation("feature.city.menus.main.ranks.title")); //TODO + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.button.store.name")); itemMeta.lore(TranslationManager.translationLore( - "feature.city.menus.main.ranks.lore.unlocked", //TODO - Component.text("").color(NamedTextColor.LIGHT_PURPLE) + "feature.events.halloween.festival.button.store.lore" )); itemMeta.setItemModel(NamespacedKey.minecraft("air")); }).setOnClick(inventoryClickEvent -> { 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 index caabf1793..c01bf664d 100644 --- 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 @@ -3,6 +3,8 @@ 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; @@ -54,7 +56,7 @@ public static void init(int gAdvancement, int fAdvancement) { // Floors enabledFloors = EnumUtils.getValuesBefore(currentFloorToReach, false); - finalFloorReach = currentFloorToReach.equals(FINAL_FLOOR); + finalFloorReach = currentFloorToReach.equals(FINAL_FLOOR) && currentFloorToReach.getRequire() >= globalAdvancement; for (Floors floors : Floors.values()) { Floor floor = floors.getFloor(); @@ -73,15 +75,13 @@ public static void updateAdvancement(int increase) { CheckForPointRewards(); - if (currentFloorToReach.equals(FINAL_FLOOR)) + if (finalFloorReach) return; if (currentFloorToReach.getRequire() > floorAdvancement) return; updateFloor(); - - //TODO broadcast } private static void CheckForPointRewards() { @@ -96,21 +96,49 @@ private static void CheckForPointRewards() { } private static void updateFloor() { + if (finalFloorReach) + return; + floorAdvancement -= currentFloorToReach.getRequire(); enabledFloors.add(currentFloorToReach); - currentFloorToReach = EnumUtils.getValueAfter(currentFloorToReach); - - if (currentFloorToReach == null) - return; - Floor floor = currentFloorToReach.getFloor(); if (floor == null) return; floor.setCanSpawn(true); + + 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; + + 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) { @@ -119,8 +147,6 @@ public static Floors getFloorFromAdvancement(int advancement) { for (Floors floors : Floors.values()) { if (floors.getRequire() < advancement) currentFloors = floors; - else if (floors.getRequire() == advancement) - return floors; else break; } 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 index 88dfea1d1..f3149c219 100644 --- 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 @@ -102,7 +102,7 @@ public Player getRandomPlayerInRegion() { } public Location getRandomPosFromPlayer(Player player) { - return LocationUtils.randomLocation( + return LocationUtils.getSafeNearbySurface(LocationUtils.randomLocation( new Location( player.getWorld(), player.getX(), @@ -110,7 +110,7 @@ public Location getRandomPosFromPlayer(Player player) { player.getZ() ), radius - ); + ), (int) radius); } public int getFloorPos(Player player) { 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 index 8da6e60d8..a515c200c 100644 --- 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 @@ -46,4 +46,8 @@ public enum Floors { 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 index e4c9a47fd..0d89c0c15 100644 --- 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 @@ -30,7 +30,7 @@ public AdvancementMenu(Player owner) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.adminshop.menu.confirm.name");//TODO + return TranslationManager.translation("feature.events.halloween.festival.menu.advancement"); } @Override @@ -66,10 +66,13 @@ public void onInventoryClick(InventoryClickEvent e) { Map<Integer, ItemMenuBuilder> content = new HashMap<>(); content.put(22, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.CANDY_RED, itemMeta -> { - itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + itemMeta.displayName(TranslationManager.translation("feature.events.halloween.festival.menu.advancement.item_name")); itemMeta.lore(List.of( - Component.text("Total des points : " + EconomyManager.getFormattedSimplifiedNumber(TerrorHouseManager.globalAdvancement) + " " + WitchShopManager.getHalloweenPointIcon()) - .color(NamedTextColor.GOLD) + 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()) { 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 index 6d63d8e37..7ca887e5e 100644 --- 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 @@ -9,7 +9,6 @@ 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 net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; @@ -27,7 +26,7 @@ public CandyChoiceMenu(Player owner) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.adminshop.menu.confirm.name");//TODO + return TranslationManager.translation("feature.events.halloween.festival.menu.candy_choice"); } @Override @@ -50,35 +49,35 @@ public void onInventoryClick(InventoryClickEvent e) { Map<Integer, ItemMenuBuilder> content = new HashMap<>(); content.put(9, new ItemMenuBuilder(this, ShopMoney.MONSTER_CANDY.getItem(), itemMeta -> { - itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); //TODO + 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("messages.menus.next_page")); //TODO + 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("messages.menus.next_page")); //TODO + 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("messages.menus.next_page")); //TODO + 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("messages.menus.next_page")); //TODO + 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(); @@ -104,8 +103,10 @@ public List<Integer> getTakableSlot() { } private List<Component> getCandyPoints(ShopMoney money) { - return List.of(Component.text("Valeur : " + money.getScores() + " " + WitchShopManager.getHalloweenPointIcon()) - .color(NamedTextColor.GOLD) - );//TODO translate + 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 index ce7c4e718..0c52dd7ba 100644 --- 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 @@ -45,7 +45,7 @@ public ConfirmSellMenu(Player owner, ShopMoney shopItem) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.adminshop.menu.confirm.name"); //TODO + return TranslationManager.translation("feature.adminshop.menu.confirm.name"); } @Override @@ -68,16 +68,16 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} double totalScore = scorePerUnit * quantity; int quantityToStack = Math.max(0, quantity / 64); - Component shiftRightSellAll = TranslationManager.translation("feature.adminshop.menu.confirm.sell_all"); //TODO + Component shiftRightSellAll = TranslationManager.translation("feature.adminshop.menu.confirm.sell_all"); - List<Component> lore = TranslationManager.translationLore("feature.adminshop.menu.confirm.lore", //TODO + List<Component> 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.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GOLD), Component.text(AdminShopManager.priceFormat.format(totalScore), NamedTextColor.GREEN), - Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GOLD), shiftRightSellAll ); @@ -109,7 +109,7 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} switch (event.getClick()) { case ClickType.MIDDLE -> DialogInput.sendFloat( getOwner(), - TranslationManager.translation("feature.adminshop.menu.confirm.input"), //TODO + TranslationManager.translation("feature.adminshop.menu.confirm.input"), 1, maxQuantity, quantity, @@ -144,7 +144,7 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} 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")); //TODO + meta.displayName(TranslationManager.translation("messages.global.accept")); }).setOnClick(event -> { getOwner().closeInventory(); WitchShopManager.sellItem(getOwner(), shopItem, quantity); @@ -164,10 +164,10 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} private ItemMenuBuilder createQuantityButton(String text, ItemStack itemStack, Consumer<InventoryClickEvent> action) { boolean plus = text.contains("+"); return new ItemMenuBuilder(this, itemStack, meta -> - meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", //TODO + meta.displayName(TranslationManager.translation("feature.adminshop.menu.confirm.quantity", plus ? - TranslationManager.translation("feature.adminshop.menu.confirm.add") : //TODO - TranslationManager.translation("feature.adminshop.menu.confirm.remove"), //TODO + 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))) 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 index 63b8a8ca2..d34933886 100644 --- 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 @@ -29,7 +29,7 @@ public RewardViewMenu(Player owner) { @Override public @NotNull Component getName() { - return TranslationManager.translation("feature.adminshop.menu.confirm.name");//TODO + return TranslationManager.translation("feature.events.halloween.festival.menu.reward"); } @Override 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 index 02b41f7f1..4ed1c09c2 100644 --- 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 @@ -2,11 +2,12 @@ import fr.openmc.api.omcplayer.OMCPlayer; import fr.openmc.core.OMCRegistry; -import fr.openmc.core.features.events.contents.halloween.festival.HalloweenManager; +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; @@ -27,7 +28,7 @@ public void giveReward() { ItemStack[] rewardToGive = new ItemStack[]{reward.getBest()}; - for (UUID uuid : HalloweenManager.getParticipant()) { + for (UUID uuid : HalloweenFestivalManager.getParticipant()) { Player player = Bukkit.getPlayer(uuid); @@ -35,7 +36,7 @@ public void giveReward() { OMCPlayer omcPlayer = OMCPlayer.of(player); - HalloweenManager.sendMailItems(omcPlayer, omcPlayer, rewardToGive); + HalloweenFestivalManager.sendMailItems(omcPlayer, omcPlayer, rewardToGive); } else { OfflinePlayer offlinePlayer = CacheOfflinePlayer.getOfflinePlayer(uuid); @@ -57,11 +58,11 @@ public ItemStack getItemMenuPreview() { @Override public Component getRewardName() { - return Component.empty(); //TODO item name + return TranslationManager.translation("itemsadder.omc_halloween.root_plush.name"); } @Override public List<Component> getRewardLore() { - return List.of(Component.empty()); //TODO item lore + return List.of(TranslationManager.translation("itemsadder.omc_halloween.root_plush.lore.0")); } } diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java index c3c5764d2..e71ea1939 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java @@ -1,6 +1,8 @@ package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.floor1_3; +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; @@ -18,12 +20,13 @@ public class HouseZombieLV1 extends CustomMob<Zombie> { public HouseZombieLV1(String id) { super(id, - TranslationManager.translation("feature.dailyevents.miraculousfishing.mob.ancient_villager"), //TODO + TranslationManager.translation("feature.events.halloween.festival.mob.zombie.name.0"), Zombie.class, 100, 67, List.of( - new XpLoot(100, 150, 0.5) //TODO ajouté les bonbons + new XpLoot(50, 75, 0.5), + new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.3, 1, 4) ) ); } 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 0000000000000000000000000000000000000000..5d8513b7b42d68cc32208bd4291d034f7548e8d4 GIT binary patch literal 7642 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/translations/default/itemsadder.properties b/src/main/resources/translations/default/itemsadder.properties index 32c2e1ddc..0c53a6346 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=<blue>The Mixture itemsadder.omc_foods.the_mixture.lore.0=<dark_gray><italic>un mystérieux mélange... itemsadder.omc_foods.the_mixture.lore.1=<gold>Aucun Effet Secondaire! itemsadder.omc_foods.tomate.name=Tomate +itemsadder.omc_halloween.candy_red.name=<red>Bonbon Rouge +itemsadder.omc_halloween.candy_yellow.name=<yellow>Bonbon Jaune +itemsadder.omc_halloween.candy_green.name=<green>Bonbon Vert +itemsadder.omc_halloween.candy_blue.name=<blue>Bonbon Bleu +itemsadder.omc_halloween.candy_brown.name=<brown>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=<green>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_US/events.properties b/src/main/resources/translations/en_US/events.properties index 07221df3e..61b9590b3 100644 --- a/src/main/resources/translations/en_US/events.properties +++ b/src/main/resources/translations/en_US/events.properties @@ -52,3 +52,48 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>The Halloween 2025 event i <br><#ff6b25>You can find your rewards in your</#ff6b25><#ff6b25><bold> mailbox</bold></#ff6b25><#ff6b25>.</#ff6b25>\ <br><#ffd580>Thank you everyone for your participation!</#ffd580> +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=<gold>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=<gold>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=<gray>Buy items to decorate your city</gray> +feature.events.halloween.festival.button.house.name=House and Advancement +feature.events.halloween.festival.button.house.lore=<gray>Access to the Terror House and check the Advancement</gray> +feature.events.halloween.festival.button.terror_house.name=<red>Terror House</red> +feature.events.halloween.festival.button.terror_house.lore=<gray>Visit the Terror House and reach the top !</gray> +feature.events.halloween.festival.button.deposit.name=<gold>Advancement</gold> +feature.events.halloween.festival.button.deposit.lore=<gray>Increase the advancement buy deposing candy !</gray> + +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=<red>Reach the %1$s to unlock this item !</red> +feature.events.halloween.festival.deposit.add_point=<green>You added</green><gold> %1$s %2$s </gold><green>for %3$s %4$s</green> +feature.events.halloween.festival.deposit.broadcast_add_point=<gold><bold>%1$s added %2$s %3$s for %4$s %5$s !</bold></gold> +feature.events.halloween.festival.player_not_enough_item=<red>You don't have enough of %1$s in your inventory !</red> +feature.events.halloween.festival.shop.confirm_lore=<dark_gray>■</dark_gray> <yellow>Quantity :</yellow> %1$s <gray>(</gray>%2$s <gray>stack</gray>%3$s<gray>)</gray>\ + <br><dark_gray>■</dark_gray> <yellow>Unit price:</yellow> %4$s%5$s for %6$s \ + <br><dark_gray>■</dark_gray> <yellow>Total price:</yellow> %7$s%8$s for %9$s \ + <br><dark_gray>■</dark_gray> <green>Click the wheel to <dark_green>define</dark_green> the quantity manually</green> + +feature.events.halloween.festival.new_floor_unlock=<gray>New Floor Unlock !</gray>\ +<br><gray>Collect %1$s %3$s to unlock the next floor</gray>\ +<br><gray>Collected : %2$s / %1$s %3$s</gray>\ +<br>\ +<br><gray>New items in the shop, come and check them out!</gray> +feature.events.halloween.festival.last_floor_unlock=<gray>Last Floor Unlock !</gray>\ +<br><gray>Collect %1$s %3$s to unlock an exclusive reward</gray>\ +<br><gray>Collected : %2$s / %1$s %3$s</gray>\ +<br>\ +<br><gray>New items in the shop, come and check them out!</gray> + +feature.events.halloween.festival.player_not_allow=<red>You are not allowed to do this !</red> +feature.events.halloween.festival.floor_lock=<red>This floor is lock !</red> + +feature.events.halloween.festival.mob.zombie.name.0=Receptionist \ 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..16067ee42 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=<blue>The Mixture itemsadder.omc_foods.the_mixture.lore.0=<dark_gray><italic>a mysterious mixture... itemsadder.omc_foods.the_mixture.lore.1=<gold>No Side Effect! itemsadder.omc_foods.tomate.name=Tomato +itemsadder.omc_halloween.candy_red.name=<red>Red Candy +itemsadder.omc_halloween.candy_yellow.name=<gold>Yellow Candy +itemsadder.omc_halloween.candy_green.name=<green>Green Candy +itemsadder.omc_halloween.candy_blue.name=<blue>Blue Candy +itemsadder.omc_halloween.candy_brown.name=<brown>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=<green>FrankenRoot +itemsadder.omc_halloween.root_plush.lore.0=<gray>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 From a32bf9c5e95caf67273f7bd8a9648a1464c9e9ce Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Wed, 28 Oct 2026 09:44:34 +0100 Subject: [PATCH 28/44] item translation --- .../resources/contents/omc_halloween/configs/items.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/contents/omc_halloween/configs/items.yml b/src/main/resources/contents/omc_halloween/configs/items.yml index ac0b36567..6be1cb188 100644 --- a/src/main/resources/contents/omc_halloween/configs/items.yml +++ b/src/main/resources/contents/omc_halloween/configs/items.yml @@ -10,7 +10,7 @@ items: - candy/candy_red material: PAPER lore: - - <lang:itemsadder.omc_halloween.candy_red.lore.0> + - <lang:itemsadder.omc_halloween.candy.lore.0> consumable: nutrition: 1 saturation: 0.6 @@ -23,7 +23,7 @@ items: - candy/candy_yellow material: PAPER lore: - - <lang:itemsadder.omc_halloween.candy_yellow.lore.0> + - <lang:itemsadder.omc_halloween.candy.lore.0> consumable: nutrition: 1 saturation: 0.6 @@ -36,7 +36,7 @@ items: - candy/candy_green material: PAPER lore: - - <lang:itemsadder.omc_halloween.candy_green.lore.0> + - <lang:itemsadder.omc_halloween.candy.lore.0> consumable: nutrition: 1 saturation: 0.6 @@ -49,7 +49,7 @@ items: - candy/candy_blue material: PAPER lore: - - <lang:itemsadder.omc_halloween.candy_blue.lore.0> + - <lang:itemsadder.omc_halloween.candy.lore.0> consumable: nutrition: 1 saturation: 0.6 @@ -62,7 +62,7 @@ items: - candy/candy_brown material: PAPER lore: - - <lang:itemsadder.omc_halloween.candy_brown.lore.0> + - <lang:itemsadder.omc_halloween.candy.lore.1> consumable: nutrition: 1 saturation: 0.6 From faea14d8b61d1442064328633227a35e2a553bbf Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Wed, 28 Oct 2026 09:52:00 +0100 Subject: [PATCH 29/44] add limited use of item ( elytra, ender pearl... ) --- .../listeners/TerrorHouseListener.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) 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 index 90c87a2f2..6659db10d 100644 --- 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 @@ -12,12 +12,16 @@ 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.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityToggleGlideEvent; 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 { @@ -88,6 +92,26 @@ public void onHouseRegionEnter(EntityCustomRegionEnterEvent event) { } } + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.getHand() != EquipmentSlot.HAND) return; + + Material item = event.getMaterial(); + + if (item == Material.ENDER_PEARL || item == Material.CHORUS_FRUIT) { + event.setCancelled(true); + } + } + + @EventHandler + public void onPlayerToggleGlide(EntityToggleGlideEvent event) { + if (!(event.getEntity() instanceof Player)) return; + + if (event.isGliding()) { + event.setCancelled(true); + } + } + private void checkAndRepulse(CustomRegion region, Entity entity) { if (TerrorHouseManager.useRegions.contains(region)) if (entity instanceof Player player) { From cec2ac25241e053a894ba00a10874ac99617bdf5 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Wed, 28 Oct 2026 12:52:10 +0100 Subject: [PATCH 30/44] CustomStructureRegistry Fix --- src/main/java/fr/openmc/core/OMCRegistry.java | 2 +- .../registry/structures/CustomStructure.java | 2 +- .../structures/CustomStructureRegistry.java | 13 +++---------- .../structures/model/CustomStructureManager.java | 16 ++++++++++++++++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/fr/openmc/core/OMCRegistry.java b/src/main/java/fr/openmc/core/OMCRegistry.java index f922ddac1..5fbc753f8 100644 --- a/src/main/java/fr/openmc/core/OMCRegistry.java +++ b/src/main/java/fr/openmc/core/OMCRegistry.java @@ -65,7 +65,7 @@ public final class OMCRegistry { new RegistryContext(() -> CUSTOM_MOBS = new CustomMobRegistry(), RegistryLoadingType.AFTER_IA), new RegistryContext(() -> CUSTOM_STRUCTURES = new CustomStructureRegistry(), - RegistryLoadingType.RUNTIME), + 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/registry/structures/CustomStructure.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java index a880e234b..aa465d21e 100644 --- a/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructure.java @@ -171,7 +171,7 @@ private static Clipboard readStructure(File file) throws IOException { return readNbt(file); } - ClipboardFormat format = ClipboardFormats.findByPath(file.toPath()); + ClipboardFormat format = ClipboardFormats.findByFile(file); if (format == null) { throw new IOException("Unsupported structure format: " + file.getName()); } diff --git a/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java index ab2919c88..2d3559544 100644 --- a/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java +++ b/src/main/java/fr/openmc/core/registry/structures/CustomStructureRegistry.java @@ -1,27 +1,21 @@ package fr.openmc.core.registry.structures; -import fr.openmc.core.OMCPlugin; 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 fr.openmc.core.utils.FilesUtils; import java.io.File; +import static fr.openmc.core.registry.structures.model.CustomStructureManager.STRUCTURE_FOLDER; + public class CustomStructureRegistry extends Registry<String, CustomStructure> implements KeyedRegistry<String, CustomStructure>, LoadIfEnable<WorldEditHook> { - private static final File STRUCTURE_FOLDER = - new File(OMCPlugin.getInstance().getDataFolder(), "data/omc_structure"); - public static final String STRUCTURE_KEY = "omc_structure"; public final CustomStructure WITCH_SHOP = register("test", "pillar.nbt"); - - public CustomStructureRegistry() { - FilesUtils.createDirectoryIfNotExists(STRUCTURE_FOLDER); - } + public final CustomStructure TERROR_HOUSE = register("terror house", "Terrorhouse.schem"); @Override public String key(CustomStructure structure) { @@ -29,7 +23,6 @@ public String key(CustomStructure structure) { } public CustomStructure register(String name, String fileName) { - FilesUtils.createDirectoryIfNotExists(STRUCTURE_FOLDER); return register(name, new File(STRUCTURE_FOLDER, fileName)); } 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 index d2256363e..f94f61496 100644 --- a/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java +++ b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java @@ -4,11 +4,15 @@ 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.FilesUtils; +import java.io.File; +import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.UUID; @@ -21,6 +25,18 @@ public class CustomStructureManager extends Feature implements private static Dao<DBPlacedStructure, UUID> 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); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Override public void initDB(ConnectionSource connectionSource) throws SQLException { TableUtils.createTableIfNotExists(connectionSource, DBPlacedStructure.class); From 1137038a1f155deadc0b9b0bfcd89a05e73d5108 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 13:57:44 +0100 Subject: [PATCH 31/44] Fix sb --- .../core/features/displays/scoreboards/BaseScoreboard.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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(); From 2d73d5b46844f47bb75ba577130aeff3135967dd Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 14:01:00 +0100 Subject: [PATCH 32/44] =?UTF-8?q?Tr=C3=A8s=20gros=20commit=20d=C3=A9so?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/openmc/api/datapacks/OMCDatapack.java | 2 +- src/main/java/fr/openmc/core/OMCPlugin.java | 4 +- .../bootstrap/integration/DatapackLoader.java | 2 +- .../integration/ResourcePacksGenerator.java | 2 +- .../dimopener/DimensionOpenerManager.java | 2 +- .../festival/HalloweenFestivalManager.java | 59 ++++++- .../commands/HalloweenFestivalCommands.java | 70 ++++++++ .../listeners/TerrorHouseListener.java | 53 ++++-- .../halloween/festival/npc/WitchNPCS.java | 4 + .../festival/shop/WitchShopItem.java | 2 +- .../festival/shop/WitchShopManager.java | 18 ++- .../festival/shop/menu/ConfirmBuyMenu.java | 15 +- .../shop/menu/WitchShopStoreMenu.java | 30 ++-- .../witchhouse/DimensionGenerator.java | 10 +- .../witchhouse/TerrorHouseManager.java | 51 +++--- .../witchhouse/advancement/floor/Floor.java | 152 ++++++------------ .../witchhouse/advancement/floor/Floors.java | 57 ++++--- .../advancement/menu/ConfirmSellMenu.java | 27 +--- .../reward/plush/HalloweenRoot2026.java | 2 +- .../ambient/TerrorHouseAmbient.java | 20 +-- .../festival/witchhouse/chests/LootChest.java | 74 +++++++++ .../witchhouse/chests/LootChestManager.java | 72 +++++++++ .../chests/loottable/LootChestLootTable.java | 41 +++++ .../witchhouse/chests/menu/LootChestMenu.java | 125 ++++++++++++++ .../mobs/easy/HouseSkeletonLV1.java | 39 +++++ .../witchhouse/mobs/easy/HouseSpiderLV1.java | 32 ++++ .../{floor1_3 => easy}/HouseZombieLV1.java | 13 +- .../witchhouse/mobs/hard/HouseBruteLV3.java | 48 ++++++ .../witchhouse/mobs/hard/HouseWitchLV3.java | 36 +++++ .../witchhouse/mobs/hard/HouseZombieLV3.java | 52 ++++++ .../witchhouse/mobs/normal/HouseBlazeLV2.java | 51 ++++++ .../mobs/normal/HouseSkeletonLV2.java | 42 +++++ .../mobs/normal/HouseSpiderLV2.java | 34 ++++ .../mobs/normal/HouseWitherSkeletonLV2.java | 67 ++++++++ .../mobs/normal/HouseZombieLV2.java | 51 ++++++ .../pumpkin/commands/HalloweenCommands.java | 7 - .../sbinfos/HalloweenFestivalInfos.java | 24 ++- .../core/hooks/itemsadder/ItemsAdderHook.java | 3 +- .../ambient/CustomAmbientRegistry.java | 2 +- .../loottable/CustomLootTableRegistry.java | 3 +- .../core/registry/mobs/CustomMobRegistry.java | 65 ++++++++ .../core/registry/regions/CustomRegion.java | 3 +- .../regions/CustomRegionRegistry.java | 112 ++++++++++++- .../registry/regions/preset/SquareRegion.java | 29 ++-- .../model/CustomStructureManager.java | 5 +- .../core/utils/file/CustomCopyOption.java | 11 ++ .../core/utils/{ => file}/FilesUtils.java | 56 +++++-- .../core/utils/types/MultiResourceBundle.java | 2 +- .../core/utils/world/LocationUtils.java | 5 + .../data/omc_structure/TerrorHouse.schem | Bin 0 -> 71312 bytes .../translations/en_US/events.properties | 43 ++++- 51 files changed, 1411 insertions(+), 318 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/commands/HalloweenFestivalCommands.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChest.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChestManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/loottable/LootChestLootTable.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/menu/LootChestMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSkeletonLV1.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSpiderLV1.java rename src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/{floor1_3 => easy}/HouseZombieLV1.java (82%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseBruteLV3.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseWitchLV3.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseZombieLV3.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseBlazeLV2.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSkeletonLV2.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSpiderLV2.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseWitherSkeletonLV2.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseZombieLV2.java create mode 100644 src/main/java/fr/openmc/core/utils/file/CustomCopyOption.java rename src/main/java/fr/openmc/core/utils/{ => file}/FilesUtils.java (87%) create mode 100644 src/main/resources/data/omc_structure/TerrorHouse.schem 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 ffc7c1fdb..8562c1498 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -36,7 +36,7 @@ import fr.openmc.core.features.events.EventsManager; import fr.openmc.core.features.events.contents.dailyevents.DailyEventsManager; 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.halloween.pumpkin.managers.HalloweenManager; import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestParticlesUtils; import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; @@ -112,7 +112,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, 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/events/contents/halloween/festival/HalloweenFestivalManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/HalloweenFestivalManager.java index 57c1c84f5..f67823bac 100644 --- 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 @@ -13,19 +13,26 @@ 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; @@ -37,7 +44,7 @@ public class HalloweenFestivalManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { - //TODO quand acheter truc dans shop, augmenté avancement bonbons pour débloqué les étages, quand tous les étages débloqué, faire obtenir des récompenses a tous les joueurs ayant contribué + //TODO quand acheter truc dans shop @Getter private static HalloweenDB halloweenDB; @@ -47,18 +54,21 @@ public class HalloweenFestivalManager extends Feature implements LoadAfterItemsA @Getter private static Set<UUID> participant; - private static final String EVENT_GROUP = "halloween_festival_event"; + 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 @@ -107,12 +117,28 @@ public static void startEvent(long duration) { 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() { @@ -165,6 +191,33 @@ public static void removeWitchStore() { } } + 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<ListenerFactory> getListeners() { return Set.of( @@ -177,7 +230,7 @@ public Set<ListenerFactory> getListeners() { @Override public Set<Object> 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..46338e8d4 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/commands/HalloweenFestivalCommands.java @@ -0,0 +1,70 @@ +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 store") + @CommandPermission("omc.admins.commands.halloween_festival.place.store") + public void placeStore(Player player) { + HalloweenFestivalManager.placeWitchStore(player.getLocation()); + } + + @Subcommand("remove store") + @CommandPermission("omc.admins.commands.halloween_festival.remove.store") + public void removeStore(Player player) { + HalloweenFestivalManager.removeWitchStore(); + } + + @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/TerrorHouseListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java index 6659db10d..8649a3cad 100644 --- 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 @@ -1,11 +1,13 @@ 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.Floor; 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; @@ -13,6 +15,7 @@ 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; @@ -25,6 +28,13 @@ 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(); @@ -33,6 +43,8 @@ public void onPlayerJoin(PlayerJoinEvent event) { if (!HalloweenFestivalManager.isActive()) player.teleport(SpawnManager.getSpawnLocation()); + else + TerrorHouseManager.getWitchHouseAmbient().apply(player); } @EventHandler @@ -73,49 +85,56 @@ public void onHouseRegionEnter(EntityCustomRegionEnterEvent event) { .filter(floor -> floor.getFloor().getRegion().equals(region)) .findAny().orElse(null); - if (floors == null) { + if (floors == null) checkAndRepulse(region, entity); - return; - } + } - Floor floor = floors.getFloor(); + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Block block = event.getClickedBlock(); - if (floor == null) { - checkAndRepulse(region, entity); + if (block != null && block.getType().equals(Material.CHEST)) { + LootChestManager.openChestAt(block.getLocation(), event.getPlayer()); + event.setCancelled(true); return; } - if (TerrorHouseManager.limitPassed()) return; - - if (floor.canSpawn) { - floor.spawnMob(); - } - } - - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) { if (event.getHand() != EquipmentSlot.HAND) return; Material item = event.getMaterial(); if (item == Material.ENDER_PEARL || item == Material.CHORUS_FRUIT) { event.setCancelled(true); + MessagesManager.sendMessage( + event.getPlayer(), + TranslationManager.translation("feature.events.halloween.festival.player_not_allow"), + Prefix.HALLOWEEN, + MessageType.INFO, + false + ); } } @EventHandler public void onPlayerToggleGlide(EntityToggleGlideEvent event) { - if (!(event.getEntity() instanceof Player)) return; + 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, 0.3); + TerrorHouseManager.repulsePlayer(region, player, -2); MessagesManager.sendMessage(player, TranslationManager.translation("feature.events.halloween.festival.floor_lock"), Prefix.HALLOWEEN, 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 index 37d20d2ed..29cc53a6f 100644 --- 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 @@ -6,6 +6,7 @@ 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; @@ -74,6 +75,9 @@ public static void removeNPCS() { 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); 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 index ddc1e73b0..64d72fce7 100644 --- 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 @@ -27,7 +27,7 @@ public WitchShopItem(Floors advancements, CustomItem item, Component name, int p } public WitchShopItem(Floors advancements, CustomItem item, int price) { - this(advancements, item, item.getBest().displayName(), price); + this(advancements, item, item.getBest().effectiveName(), price); } public Component getName() { 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 index 5c3319f68..056add42f 100644 --- 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 @@ -4,6 +4,7 @@ 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; @@ -84,14 +85,15 @@ public static void buyItem(Player player, WitchShopItem item, int amount) { } int totalPrice = item.getPrice() * amount; - if (ItemUtils.hasEnoughItems(player, item.getItem().getBest(), totalPrice)) { + if (ItemUtils.hasEnoughItems(player, item.getShopMoney().getItem().getBest(), totalPrice)) { ItemUtils.giveItem((OMCPlayer) player, item.getItem().getBest(), amount); sendInfo(player, TranslationManager.translation( "feature.events.halloween.festival.shop.player_buy_item", - Component.text(amount), item.getName(), - Component.text(AdminShopUtils.formatPrice(totalPrice)), + Component.text(amount), + item.getName(), + Component.text(totalPrice), item.getShopMoney().getItem().getSprite() )); @@ -145,15 +147,15 @@ public static void sellItem(Player player, ShopMoney item, int amount) { HalloweenFestivalManager.broadcast(TranslationManager.translation( "feature.events.halloween.festival.deposit.broadcast_add_point", player.displayName(), - Component.text(totalScore), + 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(totalScore), + Component.text(EconomyManager.getFormattedSimplifiedNumber(totalScore)), Component.text(getHalloweenPointIcon()), Component.text(amount), item.getItem().getSprite() @@ -178,9 +180,9 @@ public static List<Component> extractLoreForItem(WitchShopItem item) { 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()), + Component.text(item.getShopMoney().getScores() * item.getPrice()), Component.text(getHalloweenPointIcon()) - ).decoration(TextDecoration.ITALIC, false)); + ).decoration(TextDecoration.ITALIC, false).color(NamedTextColor.GOLD)); } else { 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 index 43724fa8d..de46d04ac 100644 --- 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 @@ -1,5 +1,6 @@ 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; @@ -29,6 +30,8 @@ public class ConfirmBuyMenu extends Menu { + //TODO template ConfirmItemMenu + private final WitchShopItem shopItem; private int quantity; private final int maxQuantity; @@ -70,18 +73,19 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} int quantityToStack = Math.max(0, quantity / 64); + //TODO il bug aaaaaaaaaaaaaaa List<Component> 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(scorePerUnit) + - WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN), - Component.text(AdminShopManager.priceFormat.format(totalScore) + - WitchShopManager.getHalloweenPointIcon(), NamedTextColor.GREEN) + Component.text(AdminShopManager.priceFormat.format(totalScore), NamedTextColor.GREEN), + Component.text(WitchShopManager.getHalloweenPointIcon()) ); content.put(9, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.REFUSE_BTN, true)); @@ -105,7 +109,7 @@ public void onInventoryClick(InventoryClickEvent inventoryClickEvent) {} })); content.put(13, new ItemMenuBuilder(this, shopItem.getItem(), meta -> { - meta.displayName(shopItem.getName().color(NamedTextColor.WHITE).decoration(TextDecoration.ITALIC, false)); + meta.displayName(shopItem.getName()); meta.lore(lore); }).setOnClick(event -> { if (event.getClick() == ClickType.MIDDLE) { @@ -200,7 +204,6 @@ private int getMaxBuyQuantity(Player player, WitchShopItem shopItem) { return Math.min(freePlaces, affordable); } - @Override public void onClose(InventoryCloseEvent event) { //empty 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 index f2a98153b..3c53fde0c 100644 --- 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 @@ -8,9 +8,11 @@ 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.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; @@ -32,9 +34,6 @@ public class WitchShopStoreMenu extends PaginatedMenu { @Getter private final int page; - private final Column.Range LINE = new Column.Range(1, 7); - private final int COLUMN = 4; - public WitchShopStoreMenu(Player owner, int page) { super(owner); this.page = page; @@ -68,23 +67,16 @@ public List<ItemStack> getItems() { List<ItemStack> items = new ArrayList<>(); - Iterator<WitchShopItem> contents = WitchShopManager.getStoreContent(this.page).iterator(); - - for (int c = 0; c < COLUMN; c++) { - for (int l = LINE.floor(); l <= LINE.ceiling(); l++) { - - if (!contents.hasNext()) break; + Set<WitchShopItem> contents = WitchShopManager.getStoreContent(this.page); - WitchShopItem item = contents.next(); - - items.add(new ItemMenuBuilder(this, item.getItem(), itemMeta -> { - itemMeta.displayName(item.getName()); - itemMeta.lore(WitchShopManager.extractLoreForItem(item)); - }).setOnClick(event -> { - new ConfirmBuyMenu(getOwner(), item); - })); - } - } + 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; } 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 index 6c078369e..5a818c105 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -21,9 +22,9 @@ private static void setupDimension() { if (!HALLOWEEN_WORLD.getName().equals(DIMENSION_NAME)) return; // ** SPAWNING RULES ** - HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.MONSTER, 10); + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.MONSTER, 55); HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.AMBIENT, 10); - HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.ANIMAL, 6); + HALLOWEEN_WORLD.setSpawnLimit(SpawnCategory.ANIMAL, 0); HALLOWEEN_WORLD.setTicksPerSpawns(SpawnCategory.MONSTER, 30); HALLOWEEN_WORLD.setTicksPerSpawns(SpawnCategory.AMBIENT, 15); @@ -39,6 +40,9 @@ private static void setupDimension() { 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); // ** SET WORLD BORDER AND TIME ** HALLOWEEN_WORLD.getWorldBorder().setSize(500); @@ -46,6 +50,8 @@ private static void setupDimension() { 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 index c01bf664d..167a8460b 100644 --- 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 @@ -43,7 +43,7 @@ public class TerrorHouseManager { public static final int MAX_ENTITY = 225; // 15 entities * 15 floors @Getter - public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.WITCH_HOUSE; + public static CustomAmbient witchHouseAmbient = OMCRegistry.CUSTOM_AMBIENTS.TERROR_HOUSE; public static void init(int gAdvancement, int fAdvancement) { // Advancement @@ -60,15 +60,18 @@ public static void init(int gAdvancement, int fAdvancement) { for (Floors floors : Floors.values()) { Floor floor = floors.getFloor(); - if (floor == null) continue; + if (floor == null) + continue; + + if (enabledFloors.contains(floors)) + floor.enableSpawn(); + CustomRegion region = floor.getRegion(); if (region != null) useRegions.add(region); } } - // --- Advancement / Floor Part --- // - public static void updateAdvancement(int increase) { globalAdvancement += increase; floorAdvancement += increase; @@ -108,7 +111,7 @@ private static void updateFloor() { if (floor == null) return; - floor.setCanSpawn(true); + floor.enableSpawn(); if (currentFloorToReach.equals(Floors.FLOOR_15)) { @@ -131,18 +134,23 @@ private static void updateFloor() { if (currentFloorToReach == null) return; - HalloweenFestivalManager.broadcast( - TranslationManager.translation( - "feature.events.halloween.festival.new_floor_unlock", - Component.text(currentFloorToReach.getRequire()), - Component.text(floorAdvancement), - Component.text(WitchShopManager.getHalloweenPointIcon()) - ) - ); + 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_1; + Floors currentFloors = Floors.FLOOR_2; for (Floors floors : Floors.values()) { if (floors.getRequire() < advancement) @@ -180,10 +188,6 @@ public static void repulsePlayer(CustomRegion region, Entity entity, double forc repulsePlayer(center, entity, force); } - public static void repulsePlayer(Entity entity, double force) { - repulsePlayer(entity.getLocation(), entity, force); - } - public static void repulsePlayer(Location source, Entity entity, double force) { Location playerLocation = entity.getLocation(); @@ -195,16 +199,23 @@ public static void repulsePlayer(Location source, Entity entity, double force) { Vector knockback = playerLocation.toVector() .subtract(source.toVector()); + knockback.setY(0); + if (knockback.lengthSquared() < 1.0E-6) { - knockback = playerLocation.getDirection(); + 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); } - // --- Entity part --- // public static boolean limitPassed() { return entityCount >= MAX_ENTITY; } 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 index f3149c219..cb57cd9ef 100644 --- 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 @@ -1,17 +1,19 @@ 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 lombok.Setter; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; import java.util.List; @@ -20,135 +22,71 @@ public class Floor { private final SquareRegion region; private final List<CustomMobEntry> entities; + private final List<BlockVector3> spawnLocations; private final int entityToSpawn; - private final double radius; - @Setter - public boolean canSpawn; + private final int RADIUS = 5; - public Floor(SquareRegion region, List<CustomMobEntry> entities, double radius, int entityToSpawn) { - this(region, entities, entityToSpawn, radius, false); - } + private BukkitTask spawnTask; - public Floor(SquareRegion region, List<CustomMobEntry> entities, int entityToSpawn, double radius, boolean canSpawn) { + public Floor(SquareRegion region, List<CustomMobEntry> entities, int entityToSpawn, List<BlockVector3> spawnLocations) { this.region = region; this.entities = entities; this.entityToSpawn = entityToSpawn; - this.radius = radius; - this.canSpawn = canSpawn; + this.spawnLocations = spawnLocations; } - public void reloadMobSpawn() { - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { - canSpawn = true; - },RandomUtils.randomBetween(60, 120) * 20L); - } + //TODO marche pas a fix - public void spawnMob() { + public void enableSpawn() { + spawnTask = Bukkit.getScheduler().runTaskTimer(OMCPlugin.getInstance(), () -> { - canSpawn = false; + if (entities.isEmpty()) { + OMCLogger.warn("No mob register for the spawn mob, spawn disable for this floor"); + spawnTask.cancel(); + return; + } - long time = 0; + if (spawnLocations.isEmpty()) { + OMCLogger.warn("No spawn location register for the spawn mob, spawn disable for this floor"); + spawnTask.cancel(); + return; + } - spawn(); + CustomMobEntry mobToSpawn = RandomUtils.getRandomObjectFromList(entities); - for (int n = 0; n < entityToSpawn - 1; n++) { - time += RandomUtils.randomBetween(2, 7) + n; - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), this::spawn, time * 20L); - TerrorHouseManager.entityCount++; + if (!hasPlayer()) + return; if (TerrorHouseManager.limitPassed()) - break; - } - - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), this::reloadMobSpawn, time * 20L); - } - - private void spawn() { - - Location spawnLoc = getRandomPosFromPlayer( - getRandomPlayerInRegion() - ); - - new BukkitRunnable() { - private int maxPoints = 30; //gives the amount of time the mob takes to spawn, there it's 30*2 = 60 ticks = 3 seconds - private int points = 1; + return; - @Override - public void run() { - spawnCircle(spawnLoc, 0.8, points); + int toSpawn = RandomUtils.randomBetween(1, entityToSpawn); - points++; - - if (points >= maxPoints) { - cancel(); - - CustomMobEntry selectEntity = RandomUtils.getRandomObjectFromList(entities); - - selectEntity.spawn(spawnLoc); - } + for (int i = 0; i < toSpawn; i++) { + mobToSpawn.spawn(getRandomSafeLocationInRegion()); + OMCLogger.info("debug : spawn mob " + i); } - }.runTaskTimer(OMCPlugin.getInstance(), 0L, 2L); - } - - public Player getRandomPlayerInRegion() { - return RandomUtils.getRandomObjectFromList( - OMCPlugin.getInstance().getServer() - .getOnlinePlayers() - .stream() - .filter(p -> region.contains(p.getLocation())) - .toList() - ); - } - public Location getRandomPosFromPlayer(Player player) { - return LocationUtils.getSafeNearbySurface(LocationUtils.randomLocation( - new Location( - player.getWorld(), - player.getX(), - getFloorPos(player), - player.getZ() - ), - radius - ), (int) radius); + TerrorHouseManager.entityCount += toSpawn; + }, 0L, 5L * 20L); } - public int getFloorPos(Player player) { - Block block = player.getLocation().getBlock(); - if (player.isFlying() || player.isFlying()) { - int minY = region.getMin().y(); + public Location getRandomSafeLocationInRegion() { - while (block.getY() >= minY && block.getType().isAir()) - block = block.getRelative(0, -1, 0); - } - return block.getY() + 1; + return LocationUtils.randomLocation( + LocationUtils.fromVector( + DimensionGenerator.HALLOWEEN_WORLD, + RandomUtils.getRandomObjectFromList(spawnLocations) + ), + RADIUS + ); } - public static void spawnCircle(Location center, double radius, int points) { - World world = center.getWorld(); - if (world == null) return; - - for (int i = 0; i < points; i++) { - double angle = 2 * Math.PI * i / points; - - double x = center.getX() + radius * Math.cos(angle); - double z = center.getZ() + radius * Math.sin(angle); - - Location particleLocation = new Location( - world, - x, - center.getY() + 0.05, - z - ); - - world.spawnParticle( - Particle.DUST, - particleLocation, - 1, - 0, 0, 0, - 0, - new Particle.DustOptions(Color.RED, 1.0f) - ); - } + 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 index a515c200c..21e4663ea 100644 --- 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 @@ -1,5 +1,6 @@ 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; @@ -8,35 +9,53 @@ @Getter public enum Floors { - FLOOR_1(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 8), 0), - - FLOOR_2(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 8), 1000), - - FLOOR_3(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 8), 5000), - - FLOOR_4(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 10000), - - FLOOR_5(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 15000), + 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(-57, -59, -58), + BlockVector3.at(-40, -59, -63), + BlockVector3.at(-64, -59, -72) + ) + ), 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()), 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()), 5000), + + FLOOR_4(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_4, List.of(), 5, List.of()), 10000), + + FLOOR_5(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_5, List.of(), 5, List.of()), 15000), - FLOOR_6(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 20000), + FLOOR_6(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_6, List.of(), 5, List.of()), 20000), - FLOOR_7(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 25000), + FLOOR_7(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_7, List.of(), 5, List.of()), 25000), - FLOOR_8(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 30000), + FLOOR_8(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_8, List.of(), 5, List.of()), 30000), - FLOOR_9(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 35000), + FLOOR_9(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_9, List.of(), 5, List.of()), 35000), - FLOOR_10(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 40000), + FLOOR_10(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_10, List.of(), 7, List.of()), 40000), - FLOOR_11(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 45000), + FLOOR_11(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_11, List.of(), 7, List.of()), 45000), - FLOOR_12(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 50000), + FLOOR_12(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_12, List.of(), 7, List.of()), 50000), - FLOOR_13(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 59000), + FLOOR_13(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_13, List.of(), 7, List.of()), 59000), - FLOOR_14(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 65000), + FLOOR_14(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_14, List.of(), 7, List.of()), 65000), - FLOOR_15(new Floor(OMCRegistry.CUSTOM_REGIONS.TEST_REGION, List.of(), 3.0, 10), 100000); + FLOOR_15(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_15, List.of(), 3, List.of()), 100000); private final Floor floor; 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 index 0c52dd7ba..ac2e2e4f7 100644 --- 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 @@ -31,6 +31,7 @@ public class ConfirmSellMenu extends Menu { // Copy of the ConfirmMenu from the AdminShop // + //TODO template ConfirmItemMenu private final ShopMoney shopItem; private int quantity; @@ -40,7 +41,7 @@ public ConfirmSellMenu(Player owner, ShopMoney shopItem) { super(owner); this.shopItem = shopItem; this.quantity = 1; - this.maxQuantity = countPlayerCandies(); + this.maxQuantity = ItemUtils.countItems(getOwner(), shopItem.getItem().getBest()); } @Override @@ -187,35 +188,13 @@ private ItemMenuBuilder createQuantityButton(String text, CustomItem customItem, return this.createQuantityButton(text, customItem.getBest(), action); } - /** - * Counts the number of items of a specific material in a player's inventory. - * - * @return The count of items of the specified material in the player's inventory. - */ - private int countPlayerCandies() { - int amount = 0; - - for (ItemStack item : getOwner().getInventory().getContents()) { - if (item == null) continue; - - CustomStack customStack = CustomStack.byItemStack(item); - if (customStack == null) continue; - - if (customStack.getNamespacedID().equals( - shopItem.getItem().getCustomStack().getNamespacedID())) - amount += item.getAmount(); - } - - return amount; - } - /** * 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 = countPlayerCandies(); + int playerItemCount = ItemUtils.countItems(getOwner(), shopItem.getItem().getBest()); quantity = Math.min(quantity + amount, playerItemCount); this.open(); } 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 index 4ed1c09c2..08e09d5ab 100644 --- 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 @@ -63,6 +63,6 @@ public Component getRewardName() { @Override public List<Component> getRewardLore() { - return List.of(TranslationManager.translation("itemsadder.omc_halloween.root_plush.lore.0")); + 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 index 29bfa53ad..579384d23 100644 --- 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 @@ -13,7 +13,7 @@ public class TerrorHouseAmbient extends CustomAmbient { @Override public String getId() { - return "witch_house_ambient"; + return "terror_house_ambient"; } @Override @@ -21,27 +21,21 @@ public AmbientBuilder getAmbientBuilder() { return new AmbientBuilder(CustomAmbientRegistry.NAMESPACE, this.getId()) .attributesBuilder(new EnvironnementAttributeBuilder() .attributes(obj -> { - obj.addProperty("visual/sky_light_color", "#FAED5C"); - obj.addProperty("visual/ambient_light_color", "#001A19"); + 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", 512); + 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.02) - .ambientParticles(Particle.DRAGON_BREATH, 0.02) -// .ambientSounds(new AmbientSoundBuilder() -// .additions(new AmbientSoundBuilder.AdditionsBuilder() -// .sound("minecraft:ambient.underwater.loop.additions.rare") -// .tickChance(0.001) -// ) -// ) + .ambientParticles(Particle.WITCH, 0.005) + .ambientParticles(Particle.DRAGON_BREATH, 0.005) ) .ambientLight(0.2f) .skybox(DimensionType.Skybox.OVERWORLD) @@ -50,7 +44,7 @@ public AmbientBuilder getAmbientBuilder() { .defaultClock("overworld") .timelines("#minecraft:in_overworld") .hasFixedTime(true, 200) - .hasPrecipitation(true, WeatherType.RAIN); + .hasPrecipitation(true, WeatherType.STORM); } @Override 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<UUID, Integer> 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..a3d83daad --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/chests/LootChestManager.java @@ -0,0 +1,72 @@ +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<LootChest> 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<LootChest> getChests() { + return List.of( + 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(-58, -59, -67)), + new LootChest(15 * 60, BlockVector3.at(-50, -59, -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<CustomLoot> 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..58884268c --- /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 ""; //TODO je sais pas quoi mettre + } + + @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<Integer> CHEST_MENU_ITEM_SLOTS = + IntStream.rangeClosed(0, 26) + .boxed() + .toList(); + + @Override + public @NotNull Map<Integer, ItemMenuBuilder> getContent() { + Map<Integer, ItemMenuBuilder> inventory = new HashMap<>(); + + List<Integer> 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<Integer> 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..b0cc88d55 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSkeletonLV1.java @@ -0,0 +1,39 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy; + +import fr.openmc.core.OMCRegistry; +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.inventory.ItemStack; + +import java.util.List; + +public class HouseSkeletonLV1 extends CustomMob<Skeleton> { + + 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; + } +} 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..3d55c063b --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseSpiderLV1.java @@ -0,0 +1,32 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.easy; + +import fr.openmc.core.OMCRegistry; +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 java.util.List; + +public class HouseSpiderLV1 extends CustomMob<Spider> { + + 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); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseZombieLV1.java similarity index 82% rename from src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseZombieLV1.java index e71ea1939..b5aa4944a 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/floor1_3/HouseZombieLV1.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/easy/HouseZombieLV1.java @@ -1,7 +1,6 @@ -package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.floor1_3; +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; @@ -16,14 +15,12 @@ public class HouseZombieLV1 extends CustomMob<Zombie> { - final double RADIUS = 3.0; - public HouseZombieLV1(String id) { super(id, TranslationManager.translation("feature.events.halloween.festival.mob.zombie.name.0"), Zombie.class, - 100, - 67, + 20, + 3.0 , List.of( new XpLoot(50, 75, 0.5), new ItemLoot(OMCRegistry.CUSTOM_ITEMS.CANDY_BROWN, 0.3, 1, 4) @@ -59,10 +56,6 @@ public Zombie spawn(Location spawnLocation) { ) )); - zombie.getNearbyEntities(RADIUS, RADIUS, RADIUS).stream() - .filter(entity -> entity instanceof Player) - .forEach(player -> TerrorHouseManager.repulsePlayer(player, 0.3f)); - return zombie; } } 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..3fc4ffbf2 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseBruteLV3.java @@ -0,0 +1,48 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard; + +import fr.openmc.core.OMCRegistry; +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.inventory.ItemStack; + +import java.util.List; + +public class HouseBruteLV3 extends CustomMob<PiglinBrute> { + + 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; + } +} 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..ce6edd376 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseWitchLV3.java @@ -0,0 +1,36 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard; + +import fr.openmc.core.OMCRegistry; +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 java.util.List; + +public class HouseWitchLV3 extends CustomMob<Witch> { + + 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); + } +} 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..fb100ee69 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/hard/HouseZombieLV3.java @@ -0,0 +1,52 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.hard; + +import fr.openmc.core.OMCRegistry; +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.inventory.ItemStack; + +import java.util.List; + +public class HouseZombieLV3 extends CustomMob<Zombie> { + + 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; + } +} 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..e0676422c --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseBlazeLV2.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.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 java.util.List; + +public class HouseBlazeLV2 extends CustomMob<Blaze> { + + 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); + } +} 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..346c171da --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSkeletonLV2.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.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.inventory.ItemStack; + +import java.util.List; + +public class HouseSkeletonLV2 extends CustomMob<Skeleton> { + + 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; + } +} 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..489873edc --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSpiderLV2.java @@ -0,0 +1,34 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +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 java.util.List; + +public class HouseSpiderLV2 extends CustomMob<CaveSpider> { + + 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); + } +} 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..3a4dec0ae --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseWitherSkeletonLV2.java @@ -0,0 +1,67 @@ +package fr.openmc.core.features.events.contents.halloween.festival.witchhouse.mobs.normal; + +import fr.openmc.core.OMCRegistry; +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.inventory.ItemStack; + +import java.util.List; + +public class HouseWitherSkeletonLV2 extends CustomMob<WitherSkeleton> { + + 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; + } +} 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..ec08afb6b --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseZombieLV2.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.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.inventory.ItemStack; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class HouseZombieLV2 extends CustomMob<Zombie> { + + 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; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java index 9d931fb51..9cbe88aa3 100644 --- a/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/pumpkin/commands/HalloweenCommands.java @@ -1,8 +1,6 @@ package fr.openmc.core.features.events.contents.halloween.pumpkin.commands; -import fr.openmc.core.features.events.contents.halloween.festival.shop.menu.WitchShopMainMenu; 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; @@ -14,9 +12,4 @@ public class HalloweenCommands { public void endHalloweenCommand() { HalloweenManager.endEvent(); } - - @Subcommand("test") - public void tst(Player player) { - new WitchShopMainMenu(player).open(); - } } 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 index 2240a5b22..06c299e68 100644 --- a/src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java +++ b/src/main/java/fr/openmc/core/features/events/sbinfos/HalloweenFestivalInfos.java @@ -9,16 +9,14 @@ 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 net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.entity.Player; -import java.time.DayOfWeek; import java.util.List; import static net.kyori.adventure.text.Component.text; @@ -33,12 +31,9 @@ public boolean isActive() { @Override public void addInfosTo(Player player, List<Component> lines) { - lines.add(MiniMessage.miniMessage().deserialize( - "<gradient:#F82C5D:#F64545><title></gradient>", - Placeholder.component("title", TranslationManager.translation("feature.displays.scoreboard.corpse.title", true)) - ).decoration(TextDecoration.BOLD, true)); //TODO + lines.add(Prefix.HALLOWEEN.getPrefix().decoration(TextDecoration.BOLD, true)); - PointRewards reward = TerrorHouseManager.currentRewardToReach.getNextReward(); + PointRewards reward = TerrorHouseManager.currentRewardToReach; Floors floorToReach = TerrorHouseManager.currentFloorToReach; double globalAdvancement = TerrorHouseManager.globalAdvancement; @@ -46,11 +41,11 @@ public void addInfosTo(Player player, List<Component> lines) { lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) .append(reward.equals(PointRewards.NULL) - ? TranslationManager.translation("", + ? TranslationManager.translation("feature.events.halloween.festival.sb.info.0", text(EconomyManager.getFormattedSimplifiedNumber(globalAdvancement)) ) - : TranslationManager.translation("", + : TranslationManager.translation("feature.events.halloween.festival.sb.info.1", text(EconomyManager.getFormattedSimplifiedNumber(globalAdvancement)), text(EconomyManager.getFormattedSimplifiedNumber(reward.getGlobalPointsRequire())) ) @@ -60,12 +55,13 @@ public void addInfosTo(Player player, List<Component> lines) { lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) .append(TerrorHouseManager.finalFloorReach - ? TranslationManager.translation("last floor reached")//TODO - : TranslationManager.translation("goal {étage} : xx / xx",//TODO + ? 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(EconomyManager.getFormattedSimplifiedNumber(floorToReach.getRequire())), + text(WitchShopManager.getHalloweenPointIcon()) + )) ); lines.add(text(" " + CharRemplacementUtils.getPointChar(player) + " ", NamedTextColor.DARK_GRAY) 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 2c39ce5fd..39de91e17 100644 --- a/src/main/java/fr/openmc/core/hooks/itemsadder/ItemsAdderHook.java +++ b/src/main/java/fr/openmc/core/hooks/itemsadder/ItemsAdderHook.java @@ -8,8 +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.hooks.itemsadder.sprite.SpriteUtils; -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 4f084fde0..556f90475 100644 --- a/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java +++ b/src/main/java/fr/openmc/core/registry/ambient/CustomAmbientRegistry.java @@ -38,7 +38,7 @@ public class CustomAmbientRegistry extends Registry<String, CustomAmbient> public final CustomAmbient GOLDEN = register(new GoldenAmbient()); public final CustomAmbient BLOODY = register(new BloodyAmbient()); public final CustomAmbient BLESSED = register(new BlessedAmbient()); - public final CustomAmbient WITCH_HOUSE = register(new TerrorHouseAmbient()); + public final CustomAmbient TERROR_HOUSE = register(new TerrorHouseAmbient()); @Override public Set<ListenerFactory> getListeners() { 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<String, CustomLootTable> implements KeyedRegistry<String, CustomLootTable> { @@ -51,7 +52,7 @@ public class CustomLootTableRegistry extends Registry<String, CustomLootTable> 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..e84490b28 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,64 @@ public class CustomMobRegistry extends Registry<String, CustomMobEntry> 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_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<UUID> 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 7a8ed6b42..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; @@ -20,6 +21,6 @@ public final boolean contains(Location loc) { 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 00d68ebad..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,6 +1,7 @@ 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; @@ -18,10 +19,113 @@ public class CustomRegionRegistry extends Registry<Key, CustomRegion> public final ExampleRegion EXAMPLE_REGION = register(new ExampleRegion()); - public final SquareRegion TEST_REGION = register(new SquareRegion( - DimensionGenerator.HALLOWEEN_WORLD, - BlockVector3.at(0, 0, 0), - BlockVector3.at(1, 1, 1) + //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 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 index 55ba3b234..083bf129b 100644 --- a/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java +++ b/src/main/java/fr/openmc/core/registry/regions/preset/SquareRegion.java @@ -1,14 +1,17 @@ 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 World world; + public String world; public BlockVector3 pos1; public BlockVector3 pos2; @@ -20,17 +23,13 @@ public class SquareRegion extends CustomRegion { public Key key; - public SquareRegion(World world, BlockVector3 pos1, BlockVector3 pos2) { - this(world, pos1, pos2, null); - } - - public SquareRegion(World world, BlockVector3 pos1, BlockVector3 pos2, 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 = key; + this.key = new NamespacedKey("openmc_custom_region", key).key(); } @Override @@ -40,7 +39,7 @@ public Key getKey() { @Override public World getWorld() { - return world; + return Bukkit.getWorld(world); } @Override @@ -49,12 +48,12 @@ public boolean contains(BlockVector3 pos) { double y = pos.y(); double z = pos.z(); - return x >= Math.min(getMin().x(), getMax().x()) && - x <= Math.max(getMin().x(), getMax().x()) && - y >= Math.min(getMin().y(), getMax().y()) && - y <= Math.max(getMin().y(), getMax().y()) && - z >= Math.min(getMin().z(), getMax().z()) && - z <= Math.max(getMin().z(), getMax().z()); + return x >= getMin().x() && + x <= getMax().x() && + y >= getMin().y() && + y <= getMax().y() && + z >= getMin().z() && + z <= getMax().z(); } @Override @@ -69,7 +68,7 @@ public BlockVector3 getPos2() { @Override public BlockVector3 getCenter() { - return new BlockVector3( + 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/structures/model/CustomStructureManager.java b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java index f94f61496..fb5d0b1fa 100644 --- a/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java +++ b/src/main/java/fr/openmc/core/registry/structures/model/CustomStructureManager.java @@ -9,7 +9,8 @@ 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.FilesUtils; +import fr.openmc.core.utils.file.CustomCopyOption; +import fr.openmc.core.utils.file.FilesUtils; import java.io.File; import java.io.IOException; @@ -31,7 +32,7 @@ public class CustomStructureManager extends Feature implements @Override public void init() { try { - FilesUtils.copyResourceFolder("data/omc_structure", STRUCTURE_FOLDER); + FilesUtils.copyResourceFolder("data/omc_structure", STRUCTURE_FOLDER, CustomCopyOption.SKIP_EXISTING); } catch (IOException e) { throw new RuntimeException(e); } 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<String> 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<String, String> 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<String, String> textTransformer) throws IOException { + Function<String, String> textTransformer, + CopyOption copyOption) throws IOException { try { Enumeration<URL> 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/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/data/omc_structure/TerrorHouse.schem b/src/main/resources/data/omc_structure/TerrorHouse.schem new file mode 100644 index 0000000000000000000000000000000000000000..f4f62e7b77ea90e557527301555a0adf216c9284 GIT binary patch literal 71312 zcmZsCb980hmu<xrr;>_o+o@DoamC4vZQHhOn>V)28{4*Ry|4S%-LK#4K4YA<_Wt9H zamJi$tvU8ydlN={|Mu?>#JLts>RwYV^x)l#XSBw;$CbsKbM>0G3*}|!SkqsLb@a}} z(%AWv$M}x>O%FTwtInrQkAKX55hwq*pXAZs!6D*-Zyi%lUN3bRy)Q5Uz2mw}-&D}* z($5{83XGa7r_E9ghtDkeZ99;N2iQg@kJR$m-;JgWR1%a^R`V7LyQ_$3kA*W(_JWW< z=fhPLX_h>?)_A*50)e7RfXPhW&Yk@eWkb%#o|AE%9rc~eqvla>8OjE&CF{W7V~Cm4 zNHUdA7#NwhCUv*=TWKy_@MJeJLIXB1!1^s65rC#~qgCA+_dCCAo2T`p8CP<~w)s*h z5RG%~?7}I-O0+}Bxn<KVn7&Sqn3l07>jfZwnd_si?{aujZ8fy8uBjUm3H)`{afkHU zjXeGJ+nim^E&7ZdgG%a`wqC0<)+)tH(S_rAu+2nJiF&lGtL!7z2cS8F&nxKDGS#qo z=IX8r9WoL-;hg8S@#I;L4bLOS+tM|eaJjL!9-V^Q^}gbaz1hv0{n+(maD|%&{|#f+ z80Na`$}Mjra!bc7URZ2uH3D(X$^F6(?pOMLC}cgKQ4_$#i_oS8MD|Ac-25JtZbCob zR<)p}`>{4kHXM}=lXvCV9+}pnw{@4UYym_YXJD}hg1M+wI&+M6!RBjqFV%>}K7FHe zIuTe{)gI^f>WYwf{M&Kyu&%D_lzu;2CC33U*?ekR-aBqj+b{p=jxsxgT<!n}F#oh1 zzUyC98nZt#KGVi>zbMN!a=K7k^@%uHQ_7j7+<G`Xx;PY1ZqL{^htgYv69UsJnXCOs zx0o`L+w3P(p`m)RA~xb4eo~s7*jANskxkG{h|#GQ8(ny}ob@OZiz)vTJ+rn(mXc@m z!(Hp=jMra#?raUZ1utoqtm0Gk2lEzj9b?15s|%Q554L)o<gLbjbFzw+>8lmR3ZNs7 z<2f}SW<EbRa3;s{`B^9O@{?lax7pRHSG$Z4Uk_P^82?jNjYtTGYE9X}1J8X-_8FjE zd+X7Fpv050uxsLMyvoE7nQat(aK)*UZ~u`<nmRD~Oux{!Mgj@DV9b&bKQQoydw>j+ z{BQdPLMdHon7wB^Xa>9l+r|HD6pF3g*carpTYAnYdM%ewA$<%k**15!oDq^{DEc&k zcs|&FCm>VL8N)Pc1}kDV6D^Q1_Q09@b+M|C&WDQi)pkS=Nxzm=AREmx$}?Jsr3y|w zQ{X3x&<WUab4Oqbz;?WQNjLB#E9)tHbxyC+iuz<s&C0gVvSor3f*USlv-9K;l>U46 zbwi=XN^-0|QG6l11N*{79D*}hgDI;NrYlPBPo0n%p4%hs7uzF&!;(08s2WUZA{#3n z2!geTyXI10UzBTRr;(^s7B^odtCn^ihdt)vwCIOL==1M+=vz%sUoyRKo3y=ush;c8 zF$wIhLjP=&c|Los)xn-(Etip{<>>?z<((<vv`vzkkW+~Dr)S))Q=luI7w5ZVAmQ)J z^cSa-lhteYpNSv2pF43-HPGeAubIYsp@IoVFrdR|r}3>rMmlcX;8rRKaAxek28McE zYED%zc$F}3Qp(?#AgIW)k2X@Ba<7k>QM4k7c>J`8ameo6=fa27A+bABw;S(E^2=^G zD4g;If*{SB%6ZY?=}?pLo+}jk%n6LaO>CPatOaT_<vbA=cwvC)LbvvDnGsn^E9KNX z?;Y_=%zy7AFJCBH$<c*oy`3|%k4!YMt1Vne*s!X;yLG3`MjqTvKXHs|?={t5xiNS- zf{9bQbuFY3^0iNsaniPDg1}54o=FnsA?2^R#M{=?sW6Xp=<3k*0dgL&(J%gzcGRJ4 zJOuddR2oN)$E8oJ&Xk#z8iGuN1oF)Y;w<1PU_KR>zt8I2i#%H;7?R!GycFGnBxDE* zN@X-O%XEdelr@zljr9y`%l5HWfb64iV#F6PRlTW2{&Pp_3G0d4ze`9Q#KS}a8b!zK zdFnf5`p>49gxjg1Tad`a@N*b$PBHL>8A3xf$-==-#4-A&dEzHyZyzKVTmAP<KA?Me zrrwv@0469r4g_-*CL`|Kw#UCBZ=;CPsPo3Z=7~JfK*FMo#z6g5Jb-kaM2+f|VitbI zGONg>cDGuV!9p{2b7~<C;nxVyk&3TI5nQa&<^WfoV{@`Fm|URE80&^yxe@gsep>$f zZdJxUsv#T%kQ5PW6pz>%t*~9asnMu*@u)q{F>CALg6R0gQ-!tx7;wPmF%f)|WAjAK zw^uw@(NvK;R7{aoX#s67_0E>{X=XeynJIyUGt>BMBK?Ye@A9FoVwCs$k0Z??rOLC~ zK_{stZ6b#Y8E!|hVAE|g8_rQZ(zbD<#b*kWBxK?%Y>Ot{_z%>!)tgu4CH006A`nqq zT8vv$8zM$xK#N;y%<+h^DnSVoo}{e#Py5si*HdRfreEuX^xUbP$je#gJYZhjHN&ML zj&7XDSphL>;f3)?>J?B#0%PJMXCVoBO1K^y)`d~OD{6;>1#VibdvQE0v6#=*w#dX{ zCblq?agFPid8>kDTt)@~JtD!j4&+f7%>BiLT$T{H&IS|-qtWbb)fGSb4Wlk$lr|fA zepV{ti%Z56b#+THpjcrmnCQbS=mA_Vlv0xVA&E6$B<J6JZ1;_0_X&JSn~@|g{kZJs z#O;y6>m`J#mC~kQfKTTRf$+%8qs(E5C}UfFeSzBT?c0t5y8Sr(KmY!++f#iafKKMm z-w#|i7R?vInh43*_Z?`FN3Hla(v;rl&S*LV9rNw&z3M=b)2#8LrV%T!L7D{a2Lvzb z%$h3?A6&h1hJh;qVz8Lyac~r2K&@jdoCyKEKPd5PpAD+&&W@rLeP=o1;D!L%o^yTd z+SgldgUI^?)|a(2kw#rOC$ygKEH3##f{3|_v!h(HiqgQId)H1VVvo9<rKPfBL6Lb7 z_Qifiw%@TXSJ|B>6t=G4W&-5}n}VCTw){@@9MJd+uu*iu?FaTIUA?8p$ct96jXlck zXp$3D)weJFW?3^G@t6ezO#aoAJsaDTDNQL3+uCwOHHxW@{hO2XsdRqmu3^LiW^QVU zMhnlaYNS~Fv0pnjp~k-8B8Z~Z4tD={;TK5)9_^fk>aQpLgiMBQ3Q0bmJN#prKz#SG zT<2wnWzl6RX?tCL_@TqWaIZ1s5T{{A#RU!<gYS$mj;iN1sur$J=KQV`P*yi^u}-GX zGQV<%fb}D%Ehl>_{u^z%2OipM2O^h&9dMRF^S_Mq`(94kr=_D0IOGq!$&|&P>hz~= zEAvZ!c~@)BDNw;0$Bcpt=_Rz~jTH-Ly(5UHT3(F00iV#y)YIz!ytslKGyq&@F5e{1 z4%mNwy)h!(GZ-Dk2D&W=VS5X_i4f+Il)aLS-O~mNsoTcN=wq*|p5v<3IRm?(M(kI{ zd!-aPD=ruDFAJ8U>^2+L(G}Q7uMqw5=87Be)<ylfm~co|^Sn)@Xi-~ic6UeVy%@%d zO}%(URC)3#ghh2FOEu-NjAe~0$Z{4sM_k+p7cknLJ7~5<V=Wv!I=5zqSJB{4f|{RW zI1&Wzut9g)33$}#leS^6d_PfR41>h4V3Mr-cOw0D7fijsMIP4F(ciy|0&!H1YJ&-t zc0_JU;jV;<%oz-HjKp92U&anzmVN%P3qp_4DP!`R#~(f$HZ|9+q&p~>0M~|<PKVTt z>G`eWhqx5I*7RBW>e1D^(o19`@i!&gE@cl(l@F_S6e-de$N5&3yw#0%cP&9C0^6#6 z1fslaeDJeuEs<<P6FxFSw%Oaf6z^^|hWQFMNPAt3zGCu*#~SZ5n9}ya`sJmHWI8OP z@?rRbV<oIh)o>Z!*mwkxcHjB=hxG@lN1An@jrLFQW>xGmgrUy<c0upvo@4Q?*?DR$ zF<TqkctKPd;!Pbv+5c?f0etnG*`TgPcUCE}!r;blLC#9KzCi{X+9-md+LU<1@4L@+ zjxd-DgL~pyUP^(n9sFEU^@cIz`q9rh(LB)&zn@V9Dgr%uwD6kON{?KPIdo*U=z4#C zvy3UmNH#jJ|6p1=zT=N8_#&<OJ7&zUL;V#a$m8b*uvR(6kjgC-3eWMKgN`G-Wb@3( zN~Gk6dQFC#mZJH3!NyY@2<DaAG&NhB@@ri`Y&?sm&$4+xK49$mL)H3LJM~e-V6l$+ z4kBx^BuF$v_Kvy-tjz4&=(?*OVBV@-Z0*jQ(!rD#iFOB+$!8wv`RuG8UG<*Qk@5jT z6nszy3<6SaGH!h!AF=b2=R860uvX0Bkc(dt*{M*c5}ycUvB{r++U?JLbVL)B7odd9 zUrP#B10AOe`X;GCI`2Ij-7$)nA?O=;A5IBiV54D4nrf6pyup{RhGc-2QFaTO*vr>I z`%b3wh0dxV7Gvler!GS6M1_^{X916WtBl?LZ8t?3=3i~HI>>nT$E=rn_KL@8qTCYo ztGm6o;JgtD*?Px9dBMvx!?S9={1lnij+9#PqfSWmpbdU@XQnXaY=EJ=he46VB;N2% z6OXh>MldF;Guvn|0%Nha8~QY@tv_!$fjk}&r?Udq7sC1ijguj_q=CtTC|o`3(C;3A zSk8qOX9%w05Cf6mQq$oYAQQ;!97GvfzzO3)He{{4XH_$Z>F8Bndwz3CGT*9g(lwlY z33mFezY8s}Y(2tGc4u)jb|^ddDHi&QFJ(r%CY^1=Jl%*bvQv4$73ifjVBEsIf~lq3 z!@(W(;adtFAIZrX`H_^m4o;AJPAQdz1LIF_fC>!sr`;o}u}NNjjKVUKMoQ+`f%6D$ zfV~>Zo29TcGQfkb`}O);+3E;41mcSxY=q`bo&*mp8I~Jmzrcx%mlAdadFls8r}po$ z7W|+j0RXrVwO>JPK<XVh-5%Dt=STuLOEmka754nt2>1}+7gt60z9b~}FfBbwjxD93 zg)lcc`cPQ<?l|TYt|E<251@2Nf(CQKYGss0UDL6|H&;#v9^EN^2xlX2rgDg-IO#GZ z!a#H-@>f_R$k_AyBKi#1U;iFe<Zu-`R(LfsD@!@&co-&J`7F9vPIeAI@&F2Onco}% zu8hCcmZeRH%CLOMTHVIE5Xqt%&LK!zF)~8t1ZTyg@{@Wa1dZ9-S-^WOi3X@lN-NNE z8cb-QV}?6S%EWJ=?pNRxI%c@TMR|YntIUMrhTaK~ql?xz!b?ZqHJZdUZM9=kB?z{{ zRQzabmf)Z{(p=O+9fDFFYLErP!7RTIv)B-k#09aR>L*nnYCoeY7xC*<YQe#M9i9x} z&evn5=w$_c##!vy2emmgy9MR{xH?FZjJq*bp*FSKa%_~WTCdV6z>(}KY{y`a3IExF zyCiX`G%h29vjlV>MVv(}2Xv%x(hPubHxl_L7ivG1V~6L|vj&(HT8Ftf4cbUsF)>!M zG;aHk#V-KLvr)2x>5{lDFKvjK3+)^E74H3=?5bMEs@tM~Ch~r#rEH@th|&3*2%$(G zuIOR&{PUd!l1{_N6n5*>{pX6IxE=qC45AgNHHUiSj5Xb|0^Yi!_9MM<zq_Q9v)L#& zx%<V3WvAB(^*NWe^=OrTj0G&7zrB{njwPju!X<jG=Y6j2y_^UvNZL5`HA@_hgew|~ z!K6D$_`g}KQzAtSYjSNdQC``oMmRKcf9^KfIfcw5Bd{!SkBGt8@w$kwK?wdyqtuVA z`qQ(XwgsbmBnRzmD_w!qC9z0*1l+dAe6;>{88|fl;M$AhuR&*opMK{dxNLD|>MHBV zsg(9hN`vVe)5rqEaYWTxuaa}_k0wcDI28;oMGR(yFq-6P1gkNJEevxtd!2g`nRIfr zp${e*p<EbMN;{v(Y;>w?=1;LBMU-dKz#)j+8RaZDHiGZvbqR#unF$Qz@5EwMAp=HW zqJ)HVnUOh0xu*%Fu7D$Sf0+p4%Q-Bc^83B+cZ6BFlB@7pxV%#(CTW-7RLcmXQ3}JW zQx{1S{nta$_DOpQEH+9oXsAJAV4cUaM1B!%5`@2T&Vh4VOl57UU&G(JGhDg9oJIb= z*7iUQdF3TuI45Cm4@AY)1vaZ*#t7e3HsWI@c=L`Bh`%J0dxQW}$<}1QwQH)T6;?P8 z;kl7$@0Ob-7=K6<As&T3#@<mvASbhD@@VWZugQXG*qf&59(^hL1<*yk%Q4B06)~xD zUf+Adk<Jb`^zlMW@nk>8KA8CT1q3f$x`X|K!$=ap9bc(WY;uE`<lxts(;GQF#+NK! z+)H(jj-Tei%R8chtsMN}o*h4p5IueOqf49kN)=Yem-BG<g)|SbIu2`dN^v#+MWm+| z`DCwYTN?pT<)6a(gsQEu*@6E3qNsKKd;Ig*P`>|qK~|G7BaGWXuajOG(*=4ypv=Ej zrBBveq;iP%PFq>YfxPQ|fu;nj6Np<ey#G(e7_h&b`?*#^+g&`LJK^}tqhL-PFC8WP zTFmMO!y<dna$6p}$4zp%MQ`67b5-OU>`go441j<~JWUhmJXYE;7E28H!D%yE#T_lf zT5cY_RbE&4yo2#az=pO8SSRuRn19n{Nzy@@V;F0_oh2ZfAQ9I4L>cb>>EcJPa115s z@7nxVqhzVD@!>bo0)K^5SLg7(gXh&j=QYdpu`q|=k{VT_na|cTjP36npKH?ZEjFG$ zJ1azUrO3W9PNKi_`F&6<*CQjC=?9TVSEnKe2$1JOSXadw?-qW3#Ecx<NZ#Gam*H5- zbYIu<ro2k+&9ndsVX*BVD*E1rv3AhXzrU*AN=T38;tP0|H(UdBZ}_tqS;TPOr+km| zO7G|LUn+*)mt<wVs(52aV&9LXX8xw#cgr#O=OXKjU!mK@y`;cleaGud@!OgZ8ma$= zC3!+yG=v21TkSt)4IR;48<kK^?8Uvs^TktIIRHueT7QO{3)h5z5a;wsL4^kr9mQNm z((8gc4IV>ZM%iB@4+#Yiz50pcx*qvvo#%&1fdKjYg}{EBUG5LW*M|^9j3YY#Gy%Go z%e}DNS}eBHP{1=OnUn|%B|pQg)qduy#0!Y(dVpU9M@Jj$krl<-gszYboo^+gEGNZi zksR!aQ4+0`?)bClv0*IrN1gmz5{*{4wpOvz+meVS_vGYfvEv+B?2OHrTCc=z;8q@Z zgHZIt(?~BB)25I3hG>BveQo`2jIQ@lOtMkktKyDlxnaee%j14xyrue=nqr<(vM^C$ zcj9jpf9rSluTvy!)OYE0DpbR^&uD#WSs8}Qdwx0pK^XjewR>5!W|P^CPnF3|BfpU^ zt)>tR-S?70^lC$bujUcnp{mwPNHNU@VL8iC9pcp=QKA*hf0*S+Xq(i_lqBn<;!hNr zoff2inO0X!>v$fkr-P7+#8UmEE9UWHc*7eFZt%+f`~^y`X`_dll-O%(HszI9FnAcz zqs&Ye!LWnNZxr;5i{h+<7@$b(GQWW5>OHPR#LmL$cbZ7Hp>-a_XhG`R%8w)BD}PK} zho8`CpZ=&f2o<|c&0=K5tNkNniX(0)G_2AJD;jOR?F{70UiVNyd<Er4`mrMkrbpUj zy5ZIGj|UT7q%HSvRO_?`OYY*YJ#}>-bzG-J^HuUlPdG7;y{2GA<8hJ#A&K=UiKVA` zMnNWZ#9S2uoVFD2wq<2$GHL0gg-|9Z<ZcJzC;HA_uR#Tccvg~jjtxJFw7eC#MWJgr zHa=B11O=)?_ZaY0tXG9}Bcf9t)R?|gj;xl9!O>Dm!Uz)0m(6M>7cNnvODqx<v?fG| zIEW`I!Uf5Q$Fh?TcA)~fwbc2^h**s(%gC@SBKB)+i`}#&%0$&7>$KHzQnQ<IZwXk@ zb#2&2TS?SknZGDjcnm2Hm^o57jmUBA%jXs03_a8(fEuu}B>{}gCg<mi^sjA;?nZ!O zkrVex5cX-DSTV=sxSPLv?jIAQSkRA`9Qub~+&OS=F^V2XEyn{*wKv3*$0G@B)aSdq z1r@N!XszvP@X~cD9%{(noi2Q$yn|XWN$}ef`{y$L&;4sj@V%|~!D1%8+g<)3k!|@6 zBh0n?-%~{~3>>2bqgAblAzs;~_OLCGQ_XnII5(zHh#5Yq`9tiI<3~l`V)1454w%j_ zFF{5WtyF1&wpqD@lQzu7&^py8LHA#^nEgr&oTG!T{ti_~FL2>1srxJ=UN;^+v??^A z#gh<vq1sTB<VcK)Vp&oZnuuNOuwCGCSFH~_!_vcy^JSV44B}YcsO*bP7SeV6=Vcl1 zAm;-f+rwxY#fhi%(KlVyf-`A*JwEoGf&`p7+#cfbKt2at>bV2l#-A9+n1pjbX*vC_ zC@EC+GMAoz35k}!VE-7~KU`OggQu6i#>kbYCU#&5)M`hcw@$iVxFkMEzcq-?96z3; zJTGqpS+zFG^6q1_WRSD;2={Aoj*`391Yfl5<#b8!u=_T_p9?L<?MbqBvrovut&xRL zPDGv|@ns`0>Hx>7SDCeRFAjT~P3A7Ra4YnrW@0UVSRAMB&#ptn&YZ19Ae6hdG5pkH z?O$lUuF4Q+4k4tjXb|j}xp>(qy^I$@!as(p@TPx}Ukm4Sb~x|YfUUfViB)O4es_Xo z+C1j_Hfp}6XA!3k!WxAkG&)~RzFMUdhqZ9%;w1E{ve@?mx3mDv=)l%is==BU!Ek{4 ziqYRlwtz5r{}yJoGMty+_xdZsK?JDLCsw-t^c%0Cig1k+VI?OV=cpr9v&%+T-|wmB z4H)^t4$gD6B>NN=q>C8xjU@(SMMW$`JP_X|%$Ja%LV*1dkCB|}>kHYG#i0-m-K2$7 z$c(e>?B+{^=-7|P<O|(pWK9<3lOP<gyHS)k-()#jn+#43VHuYD$5aX?sL8~|sI=%$ zx?y#bPIK~4xQipukh(rqhb%q1#b{pSDDg=koQtrPOU0;*1&Q2H-T6XYpn7svdhRE^ zBG@K<uYFB2_U!(!IjZU!F={5+Jj=ymoqzg1s-C}GLQD~55Gz>esI)E%GgTd4-uE=D z#ee^L)f%?9NJPC@ZjBj?Z*(J^94dosku1p7rTLOa&J16ZrD9YNHkRT$J9Q?xAL<?* z7=S}=MOC3tq4uY^Q9g05B)BkfQb1534Fo*AG9G-C65d~!a-wt!C2uCH+)PzBTecce z`aAHQ-1w+FQsN%CA7c4&yBh+2Nzt)Eje!CNs!|bb6_}GzN;5s65Z_M|P)_>okt-zY zE2S_FUkXPeaj#D*$4f2~8Ki)_oDew4KX|T+Q~zVRV~0$2*ABq^*=jCsd%lqz2fxIz zeM%#l#mh;)vA|Z4`-1w^;iwumG-(>h10(~ak<4M^#z%>z>r~dNHKgEz9vzGf=$U`6 zmLx|s?#mtS$5Oxs#YkR;%Z*iP975)e8?6A1$}q+hyj_HoAR7O+J8{lyeKY?x@E0u- zk`lI&*Wjc*FI->xo4LQY;mgVEqkuZ!3ZxK4a3fvb$QQ&vME(P6!Z?gIC6!gn7sR)3 zUti~0Zz&rbKZczqLH3qcLu-LOhw+ZomfGZqa;D#H6gI1i=%?am1@Z*)sAImqVAu*m zj5L}KJcebSvj5p9KRY{H7$%J>jN@(R=1L`>nd`VRS=_A42CC8KV;DS0Nac}`iC*}t z`Lp$?`LYX<7)Qm6tD%tzse^~XB?pt}k>`I`Eh7U5@R*yd(#=~pw3b?_)pKjqHSHGG z`%5)b6xFC>UJ0ZJUjSTDC%gszp4N|m1yqnrSS{9(8Lm`IC15NWQVBuh*rWpbXCgf% zFs%&q6n^}Q!JPruH!9TT%$TPoeQ2W>&tg%iUh|)${%2CjB}g5Xav>_Y<X*@w-%sa0 zPh<f$Z!Wd1w@6aT-mI(N@E`{tkF-cy30jp^y5$v{P{&H*Et##u5W}w!TUDIz_0G?R zus~NbZ;=#P<(${X8KlCQ&qnf(Z2MOF@Y{Amz<5yHR#yHEyXgw^lzZR;==TT$%YiYQ z*a+-giBUr)$8r*smx|BEHJ6_)*NDjnva5N-eIKich+c)MU#zDQYI`olIw9fLCxo=) zdAuYOT4oE2Ob*W1C69mP#`oY{=baZ3AI^?iNp8faN<!CeXE!@=JcnJ44x;Q?ryL-Y z87|gq4JeX`kc#$BFT0sCp-O4Rqozx^9_}1%BGv>6rWjVqt3xm)8Ko(tB}$efbWIxT zoruojKQStxa_c5>E8uV=qxphAFbu3sV+9ox%TBPsi%ZajfwyZR?rN-bmw=&o+a%8G z9b8I&(6`+xS=-2qp2yfBAq6v)7Tf>D^|!$>Qcbf3AhpSnmL3NLFry|1;yF-BTkJ$U z5n$UaCrhN^3}Xdh5|hL<R^nMOU(|s%4-q6(Og8QeoT-hj?20pSANBeHe(gxVwrZ4x zwG5WI6ImWO*D6e*c3<))5rmg93TM`EYouc6?KSFy`9pi}QH;%FmE7@8R7g_`)wSXv z$=~{`)2x*UE@IkiZYx+dXwG{iS7J`Yxkep<$muk!=;FgH0TRvNcJ8d7NWK28_8B_` z0kd=U=ecC+M#7L4BJ50E6N0@`l)3&j-wYsB0x(E7$ZFv$t&;s$=c;xj8-+7+RGJUA zCz>EcU@Mx?H~E`zg>Zm{2nHOXbq$P$c@QAu;Eg;aawJ4Gw0dF{b+q)i+KGkighMyD zb&8?zO`7{IZE5U4{7PO&fKwl*KHI588ZuhjV{^q=dopG3bSwUtbCD_b?3dGzLpl^k zeW<%CPANpp+`gjS^QQRa+C)Ouc~xBs;Y9e)!(3e=e`tqIKKpihrRg07abpCgv7bhr zzp;amW>=K4YGK=LgM;0G!7xD#G$|}UjI>6_+d)mryadtt+igmTc{`|oUrx-)nl3PC z?)YeKE1iv}F(j@ZE3hF#Nb75+rIyE2cuM_{%y2N;lW;fkSl_}7z>N}>{ECyO%js&& z>FTmX5&z6mu~FY4g~naz4zJ@R;Xd`7^~(-|CN2}HDoPN9VGm&7nf2#nsJ?R-VW(;$ z9+HY$U0@W;_7X&W?v=#N$kX?h6W4bDIoY|uB?XOy0SCrsknbBJECvqRE<F*Zx~+k= zl`L;;-qv`)Zc7~Y>2V76K2<u^*vMSe3eYYDmCU0l0A=JnH2wy?1luwRpLu|d779v4 zv<oe`@NZfevy_07NhBE1eFk>2OFaLNAf~bxaxiFY+@H@B$PAE#Du0~c&c8z7bevcf zM$PjaKcrN3VPHio_<IXar#sJ`DKCv>X`*X}5sFgQzHONaxm7$Qm%Bdr(1lbK!BD71 z{R-ydpX3|vXiy`+BFI^Wyl2R>qV480%Q|Mg{!9GUseL4~fd+MKjb~gPxC2{2vEB#J zz0YV=+bLxWlB}g6Siugl;qN^5-c-uISv_gOfz41S+o^KY>eEg$a(*&ig@8FNi~)J! z?ExN~9eaK4!dd-K;{tUM*dyG{O3uqxan;swfIL)~S!sf^m%}Yl8Fo2XTEd`D=qg+q zyBH*omPRDN_+B<&t>%S>QKi$K?d7U;+AzzV#;C@ETXbxiyvR$~_!M_b>@w^^EhxJ4 zaD`09a27FnC9y<yUI&K!B0w&)uh5)8GVNmzzXH_$0ebeULl)W?DsY@phA-MP)ftzA z#0Thf8|>7>MM9l__sh`6S~4*Y{-G6NXoJu&sb^whld?jzievO<cAkgK<JU>jyjGsf z+qB1y&}XMbjb01SQ=ya5PEW$!<i|4DcZu3adxsl2J9Btx*`#*c!<Tbeua1jF>cKWD zdVuYm9;&uU{2tnl25L~QKfSE!!&wV6gzSWRuZ&sMr*#!Cp6k&q$VcXGer)1Ggjp(W zZig$(UH<U&bVu>Bms0kCu~wSxG$%R>t9Ttp;7V2z0(d#s;X}%+9jMro7KRlGvCzZ> zPJ3ykGf+d3D=I`$L`eMjYnf1Jw|c$k^i;RcTd;$QLx?XbnhfQj>b-zcu_q=DQzj~M zamyhcIm+=WE7oZ1EwSH)zz6P|is*55UeR{Q;n2N7vf(ABma0**Tfg&@c1$ZbZ~W49 zaey;!wZEZl1uM}9DH@iF&q8L16nPze6A6;8J&4SX5aB|hilKA8QH_IVK!%$2!VrMm z0$q<h(y3L6yXFVUB3M3t4oIz2Lu0v$r!rK?8lR&w%64d3Bcj+zF#jtwh{!3DVvUQ& zL%^ehfv7@ll&xVftd<H{b&ixwQL9Ra5izL$Z_WY+-AGwE$eX_0Tu;gESeY)8W>Huf zvE0#7E9X^5IZ3tAkjiR79tM3{!ipZ@<e1984R7-s6x=uucw+k(4;lXKi%}T*cb^!| zyr6<@OdcSpV2`xn<ak6)*=*ndil&AQ1B~7jIF{0><%q6|g|xh&lnVhCF<B1cP}*KR zIOvBKF-Jc=zJ3lO;aYfx;y%5;=Bnr^Hu(X_71Z)eY2!v$BHl2ScbnBy^^<B)X4+l| z%5Jz9*Z7qY9U~$CuoK8YR<4SyER%P7!eX2^4Yr%_@F)QU0DFLmXkF1Nr{>e#RjBGl zeqJN!w@oZKWkdNDQj%k*)6reWc$<-d!#P+@ktpoUyz=?!H=T+R!^4bt3XhdPes(Hb znRGi>2IM!G>yH!N_2e@^Z{%0qzm`x4N2UGY1t=|IyGuK|J|sBir3oXR(9|j$IPl%H zbm?oT0r?uiY1Z3H8;(*?To-F5m&6)M&6!Ev;a(XJ27V?WG3ZJ`a*ASz{x=r>gN%Q7 zgt!Yy68OQEnL+Zsd*_1=g$AVw2?<bgZSQ*q#8uErciXkTk&v!Mf5Of%c4Vvqmo3+! z0#B^^>OG_HMLpYEeVO>Dy*p=AmDwrc@=s}X=O!?9EKBvyGEo7!^vyv+z-eMWQjWkE zzvu9%14U1$T*<qFZ-G=As5PgHWuW};^<f$Pbx!3pQg&@CDC)`)DFclbLY^Gg0<J5G zP^zuO_X1QWTmq&^Idh?`wh<Z`i$txgr_1=So{wwIHWAXwr%xFg%_AEmymXiAtp&fU zO9$wGbD`#!qf(ZyBGo31U6o35dC|bt3G%g^u)c9(5y}j*l+Lw3X$Mzt{@{zjr1Nd_ z(CM)M%C6DEhAu%=7ZEXUn+RyXcK-s)UiGc{{4U?s#C8fV)N$K`VXe1o2?iYSa&3JR z@cdC1DJeeXpUz8~^Cz$crj+rd$-U7CCQq51?C*kHREbX4Tau#2vzY^!8_%P~>%mTc zNMEit96yO@kin@+t*s4a;X+)oLGxB-u+7xuBo!+UaLJ#u2_%^U;URjAa|2DSNwABZ z*H3yX|D>s=(mQN83wCk%`j96pL0dB)Acr*@UcKTIk&6dw_4djs@K3-0B&gu?EPSri zCd|eM=3eXX0s|~2AN^O`jVj~MfwL_LuN+TRI8tnJf=X}QO-;=GepHMnVTbQuIia=t zV&Izb9CvSp&o{CS-f+VQQw`%MIsIeOtI9s1<=%M*{H@*}6jmBgr4AZ?F*fhFQJh<^ z3wy)e#nwQFk6T=#tPDEKd)w=qbe_%@UVcuPqoatc_{<!Q<z1?EJ^#~PN6Y^#0slSt z=oW_s$H<VMl%5+nW*ZVyLB~5J<s>29=-p`DArPzSh<|TJYX;YRTyfE$ZsPc`Y2ppF zt@_4|Uhz)0Yp~jMIkTSQwGk@RQ6I?0<E)#J)U5sM;pD31=6FQZrt^c*QX;}}&|kvf zB53}~9Fb6WDW6#=qhAG@NXX*@Q5uOWdbW$b4mtP5b54FdXH9mVm*$e?@E~)~#?Dx7 ze%OH}%Cc}0&Nq>46$vFZzIX+uq6hF_>H9>E6b1h-B9SgMu=qHc`cs(T4D4RdgBJqI zkRTbap2tZC(rs#>1eFl9?s&y9tn(R_42#UxW_^Np)1aAn>^h!%A5TjhlUE2ldo>xk zo@LP#Oy<-0Tkfi?In$*@e=J2SubP8enz1}dM;r?K9W5>Nwdmuc@$Zi7?jdJ&)bP1g z*t{iLZK*g6a^j08mp<_BP()5Kw1At<UkKq9l|*Qb73xX%oW!4>$Xulprb0pHnD>4! zw|uwXg;|y4@C;W0gZu$#g@rEtrFS~&dSfUW5BL2hy9F`VHEUF|$N2)&-CuV*tWu{7 zOK7`@!6j3Hwp5CKtL&Suca_Kurfa92#VvPz?<)FCTPaD}dx|z0kflW~5^yOmA3C>$ zO{aP1jKd6{D)d(9=0zK<|2ywcNwNgms@Egf@geXj+|5KZ?p!)wF#o<>)Y6K<6GOl7 zt|(8EB<Zu5=;xcb6z3%-`{V6L`2HuBV~A=9<(;5VYx$8P+s;;>Z&BbIO#Hk0>7t5? z^3ph0wjw^ph5@j>#H2}POQYHP$uXyG&dGzACIfRL;Id1t+h&n}Yil4wNQN`X^*JI$ z2-a*V|JB3>f_-BgH$?uUZdahuRA}Kh5-w$dGIo+Ev)8?btRo8#lMS9Vx_pr6hPtU( zC5_KL;CZ^ygGC{5sHka?-WEVke`1+}nvE)&^ju<_`;+h|As31S!oYXlU%yzTM3f?+ zqRUyT_RSklF^2pIe-7Id#aB(QFzmcZcHDjclZ5A}8|8Jd_$2T*YgWj7t&WXU0v5t1 z$?<IX*XOea@r0k$7e8{K&Iit565&0vDY3KX_P0R1)cg^@BdRKp;IDEQ2=wrien}|~ zJPddj8ns>fZMMOW=}0PiX)+qMubwsibeCkeJuVvQkZMIn`n#H*0|D9RJ-atCx4jlT zE~_ib)-ftCBKk3PMg!~CKMG|7eks{1VY;+T+h==9Wu^#q-Q`LKnnGop8xIT()y^@B zbPIn0X?DVtTUJ-pIS4<N7f`t9i?$A_NQ)nd#gvvdq|z0;S;gtWG?FqyDMiJXm5GQu zJ5uG?8)$g0ORhdDKwc=5b7RhEYqOBS#YOq@--^mN+e`xs`KL?PQ4jOALPNTJsQQ++ znq0fvg*Nx}n6MC_1A2A;U-#Zk92%k#V8{hvtMF~x;W_ktRaxn1`P%m9g?qHT{l*Ux z%@Qlp*t4wUVp<aK&vx7da@Ew@ra=zMPi1?3GghV<j@Dm3M{DUSAF0*a6Wj$u17=d% zp9>+Jg*Ya_g0(_8p$s+^+T)m2ziV&5(x49oY8A#6?~8{|asWmx=`|jeWr_ks+k~m@ zn#%8u<h=X$mmTx-IU4O><%<#v616`cu!<;T9JX&q(O$psLACNo6{EHALFQ82&ZO)& zZbr*3HQ$fK)?3mKv$jlmmS_(c^VAjC(HLmWjyT9X;J7(n<E6>WcZCe2F)T-)hAt=v zAvwy(m3A}aq|dRE#s4|W>h+?evxdn1sB6L9WGbvI1sk^i0~@CuxxF>}cV1f*z)Vl3 zw;X30f;tUKrbNBPWCRI9ge5PZ(RSrM(b?Ye=7y5cCte*EfJRBVJNg`70~GM@?r;^2 z2>YQ6Qw$J+;YcyaFf7zEjqOvFgyPdEQd&-Sk#FpJGQcCx!qXTh9_~7>GH&%4`u~{u z7f&rk-*<NwW3}0M`yJ}Ab3VzDS;T+@zgvW9YfK;(n5@lJ@HJ>`ozACc-RqG6qa5VG zD_Dc6>kb_oj-1Dg#;vtd&0<CP3dFgRkFdPEcKA4=@CjIGgq2YVeH?cFKQ{z__w>ji z&IAC*bx!bFk3+AqbP+Sh$+n$rjem-*IL?l|zC$}XJ3of-B~L;Qf37~N?5kG-mhy;9 zGf=mU^c=Ljw*{1L6EQKRY!M&I57+4ncyP(bB@RRPk>+tKxiO7@mYrS3mtU?>i`c>W ztAzjdo(U*raeFlJYCh*XOBp;4f^C?3f^UcsRATpYCU9<<18MtlTo%?<YCHcKb6?4M zQsPyNU&gGQCIJ0rd;_4@qlZn_nJ51<OsFfq=sdsE6^NJ{AWRs)F5%-8p(%<B+?_JR z0cAa>bhV%4RpH^gyfmOyy8{=ZUr)eJL92}lBnDPha4B|-4c+A)d&?HG55+b<wCCKG zs<-SajE6cGBOw`^*+q8h7x{S^hM9=R@ApfeHU@X$`z_R9T!Kj{d1hC-BFBuc`yISy zI4)Y^*DAO^&EA==2p;geEo`(_T@p5G*lmgGQojTvgtTbyqmn@T!+_HFdllN$Ggr!G zz_I(DvgUes`oSm8|H#LGV|}lwZ!AKC6yP@WS>b`06y8!P=QaH-;`18hu^Ihf#T48C zUaL@<ganey#2YGV(>wm0;lElsbIJ?8$Fh|L1TmY{7~%p!5ACe}V8$5<h$z^w(eTU< z-!0iMoXXaV52eKzFl0Iq>o2(ytdEM#2#J=%rwa&&vwxjU4#911^Hg()>lc_WRDQ1L zNQE8Nec0@Mx#dLps(i3-)~P#rHs8DRt(&gNKw;X9mF2I(pAS+s43|0%kk}7OP&k)C zY0fbo4<7{0OQts}$YWr<O1{IBZ_32DpL}83Z!4lG78jp(IJd`6^qtpn->7v}$GN__ zR=c*3{)~KO&~?XYQ&6}t)Br7U43WE8O-?3wd0%XPlX;ph>}mKw>no7s>MzA(;cQeW zR9USD4F1rq8$BZ!O?eO}fYXV$#&zLNYVvtWtZ?kJVq_Tv4p{hAiq+~n95mfJU_+Ol z*KfWQ&|y)ht<M2)C4A6pVlgj0<PNejvK!Wv8VSXcJ8^_4f7e?cm%o=~r|-8K9Q8Ww zwim9cmiv_40VsCF@q^~9b9l;O8ca3K*D@YveB9IJO!nv>^b$r|>M}U`*e5=jm%b?o zP=Yz7Wf*5#Z@n)~m9n+cH~o%qZuf9xAFJf}pEdX&&WEf9OWCXuDmNgU>HTo_cn;rd zH|!i<JAPiQ^$3{zUF*(0D=O4VB4ef0l*4?H#1<i2hhz|xuE1HIIZ;zTq>tlfHc?Z- zh(qCxI!Xq^XDI4)u9Rgcs+B2QGuD8tY}9h4@VOl&x%_C=fvIL?59Jz&S@Ze*3NPOa zuSd+ex=)4E0J;0F^HHUaRxN+(S(aVG#m_SrkCAGMFZyPerMt&0qM<r=AN5({!Iksf zLyjHpsaB(@nG3)tnThS_lDd?dI%?H|)vvmEc<gzk{!CkzFuNegV*dctZ-|RoCG4mS zV%NrTG&cZed6<643`_*U`zbP7zwQ)wl-8{Nd0jxn4e2@mV{(wk#4xY$7;mk)NVL-G zIC$0#qO=VnHC1zLSDs!{Z;pzA=q*fKYP21UO~U`<6`nX4^eE9Pove1zBpao}L3jOI ze?AOZu2&~Z>TQQJK(EXlmpXlYkE{^+sQgCy4&bQ7fh;kb@0zj<T1yLn&LF!e#-H6z z`=P~<)d+t1JZtM`)OIj_6ui5)KVnhT90z`><pS9QXg$=lS223q?h*I-6B0P0u-3O` zoQDf)Hp%?4rAckgYjl;-BbBst<K*-DK<BddzX>f9R%BM}eePc=_t*9JC)*g3^s#2K z^1~P$#NmjpvrUPX<JJP&Zu-Rd9{Y^oe(OkrL@{b#kv|a1oazgql6X-S-j!<#Rva7h z^Ie=JI8YVX=yG6q_*j*wTlZV{Y<>c?lyP}0kPLLlWOHJ}*|h50>7EOONnG=P<~X-l zfxn8&G$A#Kf7xcjOP}iCRFM!g+01fmW%ZQ~h0euECMe<$l1_!@;ta=$Lwvqj6L$Is zeWr%8waTx#2N;~WTu~74#?laqp_6$z>3+W~Zp-N8VFQ0!WyueNkVP!^z*Q4bT1DUi zwmqGk2+*jN)Dbv_fc-+df`bpT)etHg1aLe-UuPCAaL_;%ukHvx4OtXsOWN$&GYj+o z4q&m0Q4?phhJPl#@O~N0d_B33$z9E`w+psH6y#mVP=jifTU%9e1vWvyxg7Lhml2t{ zh?aB0M_`j)H*w3gGO~N<6C~K-k7mCI=GhY<Xc;?=Cyt>nlyh#$A0HXXaaz8oZ78yL z!tQtZLzgeIceFF3H+40ND9IF5o6Kae{)?>lslD!h?pgg?uSME=p93XmK`K51WX#ef zP{jg&Wr7DI4!#c#t4qY^%gAJLRQJPYUOJ9O!mLw4ciW2<v9XXNLPWvmczCH_;5%_3 ziqL<Uqr2<tnzrb^_ArzI?kloN*WM6&(4#MM5qg=j9wme8m6olH^+W-CB0tvY>t%8T zV86G*8q6B1sN%Er-iXkuR|7I9B>SIMGmb&j7h-;tyfv<5>4^@%98&ZkmZYX~sLigL zAyqv>bzHJ!$irrX9tPriYBMP<Vl=8b0ZVpsM@sCFJTFsB&^>wPr_JkrZ?dJ`U5oH9 znW+5e2@W>mRY}1(PX*W$I5eF-38E}He7@v4z|9ga`+RRij}L5+O;7QyGS!jS$P>aY z5j96r$^m|?M|?4gk*dJZNLQDT<9dIWTxi9;Tz#_0{la7g5otH|A2aF*IS`oP4@v5| z-4>qvGQ>xA#A2{vMa>R@ER^z^8KDt5MKy!?lUl~Ch2bUFF}fQw6fAR`{eu?wj7!c< z3>#jg-Si@2#qaMyUC8Lz)y>c`WB(V@{~SGDTe;$RYpaFqba;FotUwWVPsjL+r!02% zK5dIC?27{(m%@3=jp##F3`NkHh=C-@eL-yx5squ)13ePSu{v7ptDtrK@;GHiB?Inz z{JbINT2=21s6TYt=rng;>@_QpAJDd?ms4jIb*Uh!Y#VzeP#uSF?@>o%y1(#CZcfcj zy}f;D>>nK&GH0pmBt3L<y#>uSPmRG4bJ1YaU*C>FYpzN`T<9d0=IBo|N}CF9YX}WR zE8<>3m%E(G`w>&8PcP*x<lo{Ja(vA4#_L(mf&7oKb;NCBHEld#W&%z!gR3Q%20C8E zB`;nNgPE!E05y*CsKmYO(vPmqvXV6Ryzz-7If`R-L*?WgkiimVK-iEpmBvLgo0RbT zJmX^?bUW<!f1>qYL3!)vhMgTeoaBUs8vpIrD8UvZv3FSxCl*y*l;Lc@zxIYW1wOi^ zM0J;NoEH;q_q7c0LvUd*p2&99xMYN2O)ftw$6=$ZiN)myYwC-P%0Xk^x8181yx`Ux zm!}no0W#zAee@g7b;-9!jEd|l=zoqeq*#7p2`%E{!#6%2>55FM+v$qPpmb_o@8+y) ztwgaB_PKcn^@<qefR;!S^YMag^Pe>yDjyj>Is|zez(t9QACq)8J$>&iQ@YPt6N0}J zDvNNeH>;}{PDzF!z_Zh~ki4Dov6`)&z_8L8&L*p6Q73FZQ2&LvOn3I5XRt{O;+>Ga zI40ZQ0=j*^ai<%UkUz$IA}S|u1uxw%v(x)I?q0p1jwULfuxi{iPko@u$Q$C`!~eG& z{uhLvuG$1S+5{?#dXUt~%M#aE`Fyl$#<<HtD{6)=?oJnP*1jUn=2<lt=5P*(94>p= zYKA@pvt#1qT47@e;ddXXV%Z8DJqT_T3EFlE&?AK=O)j+7v)}T%QVwo=vlc$w7JPNH zUdr*C|LoY{QO+oA!1BybdTq;@iZtDw!ov8_OeJATAU*ZM@S{S~eSu2N|8x|VnU!3G zF+Dlx1In#x$V8koG0-6Q;ws%=`ih#{COw-V@@nVNS8Q*dmPFetzCZlPler)HwAThy zl4zXxz^C1Z5v=?poU{XdhMHjeaaj~dR!X>Tm%nF7-`s%&yVc6BDv8VSDbp~m)bsPP zjQtkwm+8sSc``MX)<0L0cdsNEb?WNSeKP(xv^>4NUhSOlMdS^|s>e-hC=x_CW|^vT z(cO5JN>n&+E2Fa~TN{mO4n@AX??zr3&c2#lk<4FtW6esndBw^l-8?NPUSXE`^x#_F zWUd#U*=Zi=6Hy^G;yJCP;r^iEhzI_zOW7h3aw2UpXSdaHf|1|wb*l<>>3uVFa-*AH z%?W@Sqzty#Udl*wGmMBFPAP0fXP7u-mNVoe?VoK?Z%}rKu^f{t7iTYf6iU2_GJqlR zR778)bT^z560BRrgtP0ucV01}^vWm0jaxjT0DgvWrBA>-f03<#R09kb5-acd4I8e2 z)gn67x^*~LxC1s?*|DcvQ5bcxhB3|acKVf56yqZAxVcOF&bRwxdlv53>B+%)2r~o% z2)2W5?~o5JbF_=6HvcIU|COgNT%O(U_aAk&P(f%a;>INhOVyk{hi?Q8Hl1K3X@Can z{n6jpMwB0VGm;u^_Dfgc0QE7rL+uTV`qfw%Vdc-=71ieW1b?e+1G}!r(Z@Tl3ln6N zdN`-jgVLob0wN>ya-oaD*$q<-W*mOk?=I|>^sV*hOJY!F4Ua+6F2{lyDqCt%ziep% z!+_1P-K>G7W%kigPtD#Cb4jJY&YaJf|Dlog>;Gt^m{hJZREi?N6HJSobEGd~IgBB; zA|7HNT)PO=%nlZd_a1=Lm0cSDq^w3#21|hZ4NT^Fx<fNs*Q5P#+UFC8Y>T~<-&7Kt zb_lChG?HE9ym{w#!y;{kTfn@YaA8}qS<k(Fg%Ab(d8(h8{tqJGmTWoP*{bZevTAnC zuluq!D$r#jY#dFwC~LVvkU&+13>J>UBC`FMIOoexA#)@9)e&x^UseW{Ek=Jib3Whq zVIHqN!f>e?MH*9H#&l#?Y&w3{$@5swY@2MsSu6o&Qrh+_Z}XljN4Ag;p#Mh+cxU|a zg{KpVWs)pSx%lU;kGXpQc>FsUTHMRa^|Oud^Mm>G4Eu)+&QH$;$aRJ3cB$tQ@`dG7 z<sFGKAZD-fFldqcL_-`hGNEU42}Jb`or-~)47Mn8w=mHLGlj=HenR2Y(B+AoF~wZ5 z{G5O?icq<z0m9Pf(Mic9U6NinL9K1{c8;rA)Ay)Q6d&t65j%_8)mQ7Z1Q%=b3k|}- zyG^z2gT;t$F8JY6y8~Fp_41<X`b#T;d^2&wX`oz1cQ^5IE;Z-5GNTPWMqVkGt?5*D zLsVWCAEGmOLS-g#qdDEgsTem2-xH4H07v6sveJ?EdSquw{^zXO&nWcoS<FIvsF${4 zQXGZ#A!TN5w}1LO*1@>nY)UTvYHFi(<&3<F4C;$M3YjzBt@YnEhv-Ym%fx^ztHf>* zZ;?zJ#)yx>DE}+Y|Ap>8e}Ed{9}O5U@QuFTmsHEitmDdX=kurrUO}y?q;tROsuX(j zts-Sx4!?Pa7Vd}N+xUJLQ{Y(PTd`iu2tyWiT2$8jsS=+JEdY9Sge$AB+Lcf`G0Qyl zn{<;6KRanDI_fWkzL{tDD6bUtx~eT-QIwBTKViN?1IdTgFRC47LV7eAE6KIblhNeP z7s8Mf#1~OR$K_4TLQvmZ@*f9LOhz!3Nh}Ef_V!oR3*Q})M@x8O;1;bDkh&#^t7^@l za8#8P%dj}|9q<zS#17unRiRyflSwKRKO-iwNK>m22#K#0Cz^^&)5=MK78PzFLZzN{ zp?1Y0tQfidTEbca|G8+b`Fxlx9>h2lI@(>)qiT!_T=YCxtV(_qNL5nvYvL_u-x+hK z%_BKb?2C99!|MOST8XAOWh%>BN2;7vwVK_mq9fNc8dhiqm*$iGFPZ;WT^Y$3`c-RS z%#^EFPTKe-=QCE@8lLOW{Cf0AoR!WxliGQfmk`((p;5#qRJ3}b$6mM!4Kovq!~UVQ zDk);_c+pc)kQbw)I8!-6O2XG_GXfWr0CE|-j$OJU<1EQnT7h9h{auwPPt=}+dnr^z zfgXxS)7Dyeqo8llW{<{5)K0NK9}9P&EN1y7dsG@yqy=Jx;c7)8D&TvNFlo&?aSCrw zNXu?8hQcrvEm{QJ$o!2@lTZVJ8nfpM{Rg@-i48B=S9YOuFPPtJ7L5;HF?*Jer6HwW zk`VN!ip5A<2(aL`6jy8%Bwo16<YqsmY0kaA$5TYV^(-9?z_H0Zb`lb7l?X$&)!R@K zg1l0qBDbw;$D_mM2R*pS{|{MT9TaEttQ!KsCBa=12(H03A?V@@i#sgt?gS6+uEAM+ zad!#swpeg?34ZyVbMC$MeP{mJee12-s(q%XyXWbrXa4ev+oD_LC(NaZ5d#}-s78en zZDM7(bmszEQq9%$iSc9^+|G2o-UT=IoB6eiw`garn$k`zs~DVxQF5}h7Y$T?p3)8f z-+*@wWl?B7?CWtdYFCI{SGABYqg%G24fK0$K*1B5dH3jv#EaD(UlaMG65Oul*K&Zz z#ksh=kjVhO%eRTd*Bob;yGr&|MF&2S!EMbUhL=)qxh$)Z$9Ca7#*Ll|;jC4^gz>?Q z#K|%xP^>q}?Xr1qF@NCDZz;0x<9EWHN#{;WdewJ^yQ1*h3c~{6v3`8|!sPabRJw^b ztuz0CT&M}bW|w)fnu}3U4q_9Q3z%$&&D`oGU_=cGjCcSWi$$GNM;njk`bZh%o81E1 z?`&Kd4O6a@J#|`7RjFV2b4<_il%;6uf^AC6wXFK(aF)hVuJGX8wceEsEOVpAbCjy! z%_6!rUY9;|gjVURSE0Slx-c*+ZQLrJqn=Xtd}C8eRua8oGg;{4vOFp~ZJf0l@%q#) zYWYGY(i+q`1KiW9?T*X@{IZ<{oR|&ZTY{S+s*NcB?Tc+mLr+CqpNaCJ2{7MfS^<}= zEi4dpeCk!SGu~j@;Cfo28l7DQ49Ih>HX1-hfK|h=d^RUr#PHZfz86Tep+6RT;^K`( zF@N^1yt0_MC?xDa?@F(!Jz4-abuK*!p09i)f$R;1eZE|KAtZ<-eG^^`5nFDAI|EOt z4*oKng13iXpMI$NF_5M|ehFO7%47-@_4KyjIiHP+Bzq%CZoXNSYH(_OE_ChJvpgB~ zRB1AhwUyhE$;D&O@uj5cYCdAPkn!Dk)bS1d0_#sevb=x1z<fWLKo8;5;5DFBa%s!9 zYVu1DOTdwZ_H#zY*E;vO_mL~P_YOh~+}xzR7|?9FZrzkza<1ucHKl!x-N?F9GS9la zv>2S#JDjiLbtAoXXEbQ<mKRGMKxLQ5f>R~9NBHIYkMg$F_B>y#cU^(PC-~O;7TnbK z_zkXiNBAV(;YlskH5Zc&X75-TjPyx5eC8_?ntNmx{=Y~0iMa;%-@)J3VT<#9pQ#8y z2(;wyzxB3hXqA$pq!VQw(-Q&0%WCl(N~2Lvdv0k<w~DoJ#2cX3T<$w2SZB-gUta0L zrk9UaH{*7dNT%s7I=wC-`{k=lXs=k)x{lpF*A5HWDDZVzY-S5mczd?V9^8uL0Dasz zY0r+s5aicdKKc>)F|2gs0p$nY@#vM75n=s&rj_@HJ-nVhQ1^hn=-Z(~>+ET%cT-MI zcfG6k0Nlj9Wp6IN-$5jOqt}9dtwf2`S@nR;^XB<}n)xrUbFVP2|MZ(o`OnZRnzJ{& zgjhR*{z#o&Rh$%)G!oiIgn-|ZB*H@mB5jJOJSL==C`n4ryZsmn(nAA<^)ylO0Brsb zOELvceQ=-95JGdmY11It;M?2S5{%h*4q58vtF)`y-?bvIrIr1W2&V?&A6(*sX$y=z zJwTsjCQ1A4MOKafV5g)9rDLZQ7JEASO(-Q&JeLbwe8fAgD10a}54%_@ab60P?n`Yv z{smU#*jGFLsTR00M>0m)qXsH#q|r>zrVsQ8jnvAG%!A<PHG0nQD(>Zu6v47N+UI4g z&aj#5dy^O#uCU8DXY<jbCqXtxy>YuA{+)L|Q}D)8Qt?5{MQDd@qPHu91H}=n2UHm$ zI8RQKrKMwPN`3|X(nFGK?Y@2%ks?v$t>nD@8flLU3W_Cd_};(!IAWKaQ+vdwgd^{q z`l8F_f!EO<=T*YXbwb|->`w<yU`S`8ZRC8(_P{m@*wn<TI5@Qv{#4KjL6A*3SK{mS z>fadGt39z?pziH86F%?^nRidf=9=LB;pON?vv&_1#-e}{n8ist;HkH0^^7efx%)!X zS+eu<nxcZ7$>>KCXepVDi_&&mkPlS<kTj#!8XvgmuC=_n-D)8#OY$B=wmtI}Mh)55 z404$^rg?YLy`kM=K2`Edc-1gysS_(U?e+rqd%aE#GPvgi#_zX>uYNykHHg`KakaF^ zuERUpI~wapMZ%+5Ysz7LbexJvLRR)UHkOK{L4qXs+G1nSg(YwSWE3)+o=N}OWrv}Y zSB}1T{SoH2=Fv7-zxpwo`)^?rn(Lv||6fo4^=;6URx3Op$*cZZie<!i!TX-aTQyCH z5FcofgLWVTqHV#w43k#zWHG<xnTu^xqk^@4E$F8hkOw9QIzP6JGuN4h`%4$(28R0; zFLa4QR0unE?Kb=Tk})(|k2`-MEhk(&4f}Z#naMOx#6LM@PCpLPVvsTMmxI((*x8zF zz4k?$r0P#X96-k^SA>nGq2l8`0`lgSS-txE^xTeX<oH{N4=N<D#SG0+tot`WK-B7) z(#1z*2*aWYN(RJO?J}pF-m@Y+GdwaWZd||Qh@RyH_A$1eD!7)s>cUsX`)aN@n>JH> z1KJkL7CWTH84mX0E`VeTC9gQ^!~Z?HtY?is-q~1Fn4Ls-Gj{j|BZw)Idp%Glrg%zQ zupW?J8(zOAb&JO^yR(Z#*lC%^YQs1E*=)*eZn05o_K}kExLlLg6Ie07xBy-nN?Kv6 zE%*K6Xi#7^smHyqOdg|vM)~iAGd}MoYHI{vK<{RW$y$|R-|~6GM5vWjAfIDVb5G^) z5&R(j@aX*BQ`h`#plEYCwQ=+|_bsg*tMod8Pn_r?o2@KM!pa?wa?3pNVjnOp)<RF$ z?CMwn!wLLyxlPHW|KQ1Y#tL6hfqpn>8lG@4W?l1z($jV(t;ku#IiSZH0;hS<*PV|) zw?b>>i^j}_6z}5rh7nvjKBMz(_+l1m<#@Af-09Z~Y-HBQS>@L%yYbG8jWq<G-mb)c z_cMKLZPzcCI=`p28WlcUDW8p;6TR9y7fq39(&}|)(&phZzDg(CA2HZ;j=y%dR=fad zR4XRZZ=z*wFb`?Q*lyR*BiqkIvQLnK>K43}y`9WGp7ZW|mwBPJZImqYoJ5sDusqev z!PYf{Lk!-MZzy)9^p-JSOZj{~W|^e?h-P*@@`KWDFHN8X@#s;4i>d~ZO+W@~3x(7= z9~P2-$7qo(;E8PJ+q(b`$I>hB{^rlh>iH8{>Xijq#*o|stXbXsP6|#{Q(d@r)o>LX zbnGPbT%5*U#VHdCP^_IQ5E_O`pU5!U?<-y#Tqng)MWUrg8yW-Q-~UNJ_M<q_n-b5- zj6s}M;o}2vJ5Go8ow<)EJc9bcG|l^u&J%Adll@01qos8g-cI*d)&xN*!U6Biy{a^f zyW)Z7ObWxHDY?ug874V*H|<0psUfIMw)L?;8ddTB&@t%CojmN&(dg4R;DC-)1}(Si z^M?2k_-z~Vnu~6HOx%EKwex)e6%$4;OGj$Ec^+2Kw1P41(g6vYpECk^{PCRwChw;a z3QZ}@f7|P=gk~IeYXQ^L_g6oRNn7hMM$+h|&@fcTPHj#LV`lGgu$m$jGSkb!wBuS( zZvtmj(PTStHC}j&(t^f2%+BvDGallPTS`bU;ym^Sx~R`SwAQ0K8zZqlaN+zL?*~C0 z+Uslnk}N$I<@>vKmapJGELpmkD?5V_I~X~K+f*H1z=5?YF3#HvWm5v6hDEkl<c2rH zT7Akp^h2pzN|Abz7@z<i#OcL|)=z4b3&qi35<>x%IyzBh!ngm_|MNtV40Jn|r(N~r zmupwSd!f6#X8gZ7Grmj^q)NP6y<?egxkC!H_S40>zC|a7Zb<Pk55H`xwnF7LQx<^< zo9P9!s$R3;0)BJ1lAVY;+|`A8_i{nOkaXs%msO&y?CghWgTt}IDA8<J-ZBzR*OT~U z%Xx<|x%HD5pR)v{{F$zJi5TEY9Y1XypT=G582T!!24@^GN(M~6nr!xKC&mGLN5E#W z=+ekx8^I^~0Pkh3BF;uN^kxw;+bZv7u9VL{)iC52kzKw2$Mci&ybtnBqQ+p8dZR^f z27*qks^We{i9w_O@#gSN`wumZ?OljLbrF}9McA}OdoFm}n>%NpD7CV5kg7!}nrm9@ zU*23-@U&mrn@9eD@nYT}Wo9je=Ose<VP5s%;9#isDQKOe3ntTdP()R6A6l65nJM4v zAdxWdwK6MvB}^u{U%U;@nF*Q>mYDV7>r4OW0!LMMTubGyEm4D25)ah7&X{<YRG)Vl zM_(W(r4s#}dEad}ft$*^Alp`v{B)b3jbLbp3gyvx+LkJ~@6;DPeu)t8qhH7Vt`;|z zhD^P5kU*eH+Pbj|)<wH!W~(x}k$RhV>&@FhK~_GLDFKZRF=`>eA)zinpp({aRt-$u z4+OvD=leSrf41w6jEJ5dy;7d_m~}D53@B?0-Lvs+Ph>2(=wmR-M6r5yv{I3ypBMCE z8LbEga3!tp|F&8sN~~8GZ_1U<qsCWL^adVadmZ$+?KJ5WD+vkn_hEOODgl$%KU(jL zUP&b<q`e%t_v%!C2HPPq;nZu33{wy!$rjAMXT1(odhz>5P36_2>%w12`?gHPwT0(J z_hr3@MuP)sJYzdsI!z+Hr)c^(tEDLOhHi4#y^!}M>(BU3r;X4`ZiWX9?0=Q_mGgc* zK%RLzHgwUYBUdU`;D=r7sBpZK)4y3RRw9D!%76lAqMLD-$N9!uTPNc%_DijmsJx~q z5N~EBWNxtDDAcQ0U%G^G{;K5RU*Hb|otFD4Xr@K$;<MNb2YXR}AZhFvhQC6L3QkZX zH$q<W%b!++5IYxVI^OOBZ<;MI59yLzl|76K*prwSb;*vDU0u22fpse+vtRQ0L&TL) zm((I@+&r))c9CcB85j9nGyD|Bo#{(t&glK^UePmC%0zffmGo3hUZ0A~-1!Sr*ngfh zQ|@eDjGq4fqH`{B%j55E822OvZQ<4d$Uvr);kjwP1I7PksqG9`((xGo7eU@+{9ayz zaYb32xuhe*G<D%ia>b~l$=B0uzW4^R26NxZitKpgv1CC+J{BOV{%)T*t+{hGPP8(M z-8I4!l##iSW^k((BnAjIzw{|%*DZD}2uHI>z|I21x6gHjTX|);sr@Ra<I2b3EiXAb z<1=@z*Bw(;^{k!fup&y0Nn}EkusFVnFB*T@Mv+;YpZo+ON586tB@wBO4s+}q70ej0 z|8a2h^>*}Kk<#x-7$!-W@?_8(y1&+?u~Heg$925{U1qB(IahqzTwb%5;huRaXX$cC zP3?H-$*f^N{ifp|?mtUO?~EdB%E|*ZCb+qv)bbFyUK7zx!agYqd2ZS813``2y^@5~ z|1^TdfOwN6mSb?zc>nUS?x@~VTi|apH!M-Y_@4mTS4T$s<qm}o{j@^s@cZJ1KWJd0 zfc9-oro}s0#nWR`yX$KAllL!XV?CX!t<Z-@vp+RSnz$c;!*>$ZWRM-OnTjDDwzBC% zL$mtWyiD|8HN)RFoc=7;4|i3gZ4t<p`l&~*o4FR8996O|cP4<I>a_$i@3e(HS^VmY zYK&Uk<nLWMvh~z*g~hzA`ukGk1%v0n?QcZ0U+FhF7E3><gMOSyMjq_{@j0<sT>@;M z&YuZ0%|k6R&r3XwIWP6<tTkGiiJjr|pqzDTtT!}@dI653&#h}8KuY%-&d`T$;QYFy zs#V??1Nx3b@<;j2)kSZu^Mi-Okmm=(@=^@hMPb{vunX5!6t?-_<c32M`C<RB?)hI? z*H*fpy!k~(P~lN|SyAZXprIJM9I4#m>MK}juWt_HmfuC=1;ttq4cyv4Z&=<HT2|Kv zP4kq0da%f$f9N(hg>OcSS$}PboM{(q@p|oYRy;KWhJCyC{eEb?8(W;T6-<35o?<%* z^d+x1r{X_+;-(ifwZ<53TzFE8i$iyTL7%h>xE|il<7>I8Fsd>y;d^8?L=4W8yHS8; zB$3&N{QTfr1*;+f&iBM>TzYbHRQ|J?Tm=Svj}C4x+loBM%wZWkaJ-9$Y&Go>ol9Zq zd5uG<V7Nm7<O^iyLb1-;94-VC&AaVla#xxjf1cahpk$b>-QW3BS>XW-OLEnir!7+{ zSZ%S{bFYJEj{o)K2h%ub-4p9pFUer0$T$dc_V00jsef6S6or!vj^TLY?IMh4rGROk zQ~t?uIPr<%e`3~(&3}0JZJ9VYb>8Abg2B?iA8+Lk-pVbtenlfR)BV)YWVu#LEk3lx z5;Bx#nn1{_msxjH#82!XCO!A(2&z4%Fj~W^X4|eUWW=0o)T(i(qsQ>#G9XPxhzA_v zC28p;BJt_Y#dzT}YV}W`=s13EyQev)_((ST*P3J#<HM)!nzbwX=op7P*VWiSN-Cfh z)SUv@i}p>_rAm$=KO4iayC?>@=}M{ed;bIi-Y#ATIzW3!6qESbAesO^=7UJ7ma{|Y zHnz^YszYJ|tkw$mqNE^-M&c5FhDUY|gdOXj;{yRn)do~71D$_>a#5rUKb*T$+#&)= zDYDHrAbs6%*j~?DeY9uG@AEVZZ#Pp+=?6p~dSxvo)^JLGFB4|<rTm$eA<F8@Xyv2l z68zwFJZ&q`gw0n4SMVZ)E{CFr(IrsS?b*08@4Z`RN+k{!$X2xI1n86PY=Xk-RW=T1 z(<?6n%4ZhiOI8xY<Tf|@BC$-T?)+gv;;l18Dg7V+v7h+K(a*mt3k8_3eXFYE{(O3T zWEd6ipa9&qQE2wWvn7Mg)Uwe#vVcmy8?7V)Lm^fjw)uAM=HqG>#Pr%Kna1-LUp?EW zR8i-D?06MuVyFix5>Idg8I)2llXWfNRS)HMN_eTcfQ^&6C#C*Ccvave{d%`lDVJvL z;V~O+;>j}1NnnjmW>z5T0~aOmdeBHbawJ1?=VM8eaV3ehnneX1Yh1TD-nd#T2{jT6 zgvm`zrDc@Rr4wa$q-ka>>hUp9B)ZFa4$HhZJkO(j#vNTiiRuAR3D?6;FJBiLZzX%s znE8#sX#~I^VAP+_d@jup__<I#L*7tOY6#=IzwT<Pf&AA|FC%(8mAtC}-D{GzcIfZ0 z<JMb)!6=cQ;==r3$rxj#Xq>%`60Hmcp4lHg22aKUCK%PG!1fm882)I64DAK0L!rf} z-;ePZqZJO->559yJuAuxh%__>^~YYK(h#UI?5nIR58qn=M)4Ufzq#EzvUrOP-t`ra zXHuvjOR(>l<;$Pge|jFr<<-?4B=F--_7~I!24YA$-vPO~2I@-j?0q;y$95nB%|ds~ zx~_2aZpG{ETtMB-POObETub=c>s!7FbkFwUnI8|pMxC6cO73u552o3!A1qHr;%luc zC&F)6dKJR0p~;37jl~dM+b>lSp<j8<?=~1hZ9B&Z8!MJIVXgepDMw>D50E5Hv{-N` z+s=V>9j-LIK-^Ctj75<3`Z6kE7$;<>K)0h=cb?9>a|5wZ+f8@bddP`xeHnfqLyzOb zXRg7oSA#Zr215g)zQPKtXC~M2{I5H7js>Ty#XtJ8a^eSmKmqS)C#MrDZs-Tsxu8}% zDWGNBc8YiPTrF2ych2SCbJSSijXr&oq(1PE+aXVz@`vo5yzcyqQ{Dc6kb>u?=11bM z5TwS4!{XRZwWqw|PH!#?YCAm;uoO)I>^5Q_Epz#W{)<kzZ|CUsUM01eEDQ9Axw-9M znFMlEg6r_Z_WV^&x$#JkE!JUxhx5@%E-Kl)5#mZQ1;2|`{7`-KOfkMX*~8}ahN^wj z-J3F`m-`28z_45^37+hM@&NbJ4dz(7VtK>qXC?OIy8i8p#3lx%I&&piPX-h9`9~Jv zY<TVazTr^IPK!K+j5WLXCbLXd^IuD9i^iC@HS<J-#~y{oy61f<SakIEd67CaA^?g; z!bR7^`5!NTaq^uQ0eE^0ln^xmV7ko9bn9GH!feL-iH&uaBfsBX$BgTQgolg$z)4~E zk=#WNZ>1-bQn8j|pZ5YTOkm`MrNt|Fp((pfC^{5wx_M)MNQ}V6$+#%{*m^4{VDYM% zvf%NC(iR2zOOpRJh?IuA4d;<REhm2{%tOg<rS~`$IPB+g^!f`6#ar;_{`E#!1y{Ko zhiakXdiI3bOfKBx4jx=ZI|J=aCt3BD1`hUCUvv!bV7$3;aQ{v~N(5O>lN<KGX_Y{Y zO4XzeSjd@zY-U<??M;o!T>GNR4Yh5CDOp!cajuRQ0Ob2m#rms(4`WZeF53)v$qzm* ziDARmdVeyVpnW`RU^V6wZNVus0hd`d+U>q$xUp01w)x!5wM-N^jiJ2hTxH$XgtD=E zs}z+?eESHlK8}t%n^Q#~d^qbu)YG>F1{UuWGOg7;s9x96!u7W;6$XXX#_V~`*u0DN zCZz1G_92X74#X@ezS;zZwfd|hpnVZ^f3ipeyvNRlCVa?TtHLo4SKz{rV56Pn{(H7s zhIw|&iwT@E3FOI5cYBwG?_kqeu!XmAv@jQnkrHvmy9R!daol<pSFSBaMMeUI+tk;; z<Vl)hy}~*j{%%$6I^mCTcT`VY<ZF9j4<J*XNcF-<lE-C*VrebH#8Bxx#FxCYCYySd zIs2NC=%4-~FeZ6u6LuSII~`CTCo&f0y|vPDVu-L(>`F$zIR{iM*=p=+3N20VehM3g z%vL8x47-9<yw~0_K_2Aw%s~SuQgw`KuZC-b-AdN789Qd89$pc}467DuMz$U($Y%a2 zUkzt{sa030Sz?$e(pjJf`MVL<R-(MuYR{rJuzHVbGLU46lgvLw$8(;!fOo<xP(KQ! z*d?)hEfE|UxLDbC{`L{sV|1EzxBsb32eX}T!uV~NG-Nn%k-hIJJON}3P!%Pqmzb?C zZ?NO3Mh6}YR2zLNQ01}b?GJg>+C|_jnrNJ9Y+9{0>LEEJ+`Uy&y0a=fI@WeM=1x%Y zO)^<UPZ(^+{d?~=v#(BncV);o^NR3+z+&|#Ladwd)o%mRV7jA8h;W;fPTt0Vyv@<~ z-2oU|7Og=2eR7pJdGh#uBKrSz3o$s)|J{U=sS~!$iyO2O9Y@SE^0kO(LhJYU)i0@- z)R`lQ*vPW@F&GGlh!^~fWQPMRzn#Hq4dYz68PST{Dt!FyaZF7cd4~r7!`^A5QLL^c z5*W35dcEvT$*?6k92BBF*EU6<>Xd-!;vu}}V<9Rf8~WAHjqdzUVANrrmd@ICFCpu3 z11`@_kKs}Vh7Py!bq^U3koUz*y}vO8LhbrISrzetdbS>PHbvU$lYlyM+J1EjpP%t1 zVu<Th{;fKIDAj>;`l}yFP)nxH+vajefUZi8IhK>n<0hcbeb{D_!}+F&f`_tXK3y|g zI3Ryj_`2P`Ku@r3iP<4t_fR9B2DuTfT{m>ds9@Da1{*2qU|bS=s1Yq5brXd%%JnWH zY@T^@&W$WyzPc9vKG(WHP+J8Cq(TPT<R!%<HnM{#^OhP}L?sf306OCXQG_kvVxRQR z+~$XJDd*cCuHilbRE!hjtPE9X=%<&15WEzL$T#6b%&T>$m@#j$WGp449;mSQ^>nRB z`!8QV&<Dd|QZE;VUmHN)?tj|0y6E%iIexrs=C`*Fwyob{Df$ia{uPG+L=~E3sH3)` zeMOpokl?HSz1ewa;6d8^_j)<p+8yl~Prn-_bnRYBDCfN`Q*T=QS*hBWbi7G6XvJVp zZaVyYTWCq4L*8XWK6ZkU?p}~y<y2E!0^+)IS&#<lco_Z3AOInkSCiR-K+8LQO%dFh z6>i>tgu86Cnha}uQ}I>v9XcDwDx|i%w~?{DRYM+Z)8Tl;;s=ahQ0*Gr8}ixiY+wB3 zKI@b(sy@B}S|r^v)&8)z=Bw!oNIwMeFrAyVICYr*bqMRqzaO)D6vaH>Obm~HKHB5C z<jB$#j-UwQh|X!#Vyp{H(xkUNx`v}~n4}yWUV}fLk`$;Jh}zA4U}tUrz=x8<?{)S0 zUPIyCepI3}eWO9gT7f~P_x(yS9`BfzK^pA`VE8TZneDu^Xe26Qoy(Slk0ZvBev5-& zwLR&$>1<l$F~Rk9kW8D_MqE~{KSDFqbfTi@&+5^}NJT-FCEOSht)}#x)p}SYm#|mE zxaGgejzRp7He+FCOwRfhR(<r=;-F_I1;?@xLo2`?tpRZ8c>1RP%gJY_`S$__2S96E zObUInJ{fCGsNCpqpD2=oiZ++5Wp?(3S~_o7atU-2bJzyU$^YhK@M~eE>?*hf3L__6 zPqN}$8wm>kZhBRock%nXW*lOR{(@>a>lRyd<+>_p3t?dtJ0(ap6>>AbzGCh0UdX9{ zbWB8VDzUPcOJ^~~sT*J45w98P_?^&3VWRQ33kzrpBdn+Z{Lz1mTUVVPi@6Rc!(j^J zNd`C!Nb5MNOm+~&v+sH>I{SbWRer}4&Y_8=@q>N#eK8C_z2jvGaCT4lnWjpd&ZLEZ zI%<$3wzR=Xe-{0_?ip;%>3iZjZVLWPK4EZO$%Z&xCF(@riQ?WT_5QoUO)UyHSRv`C zZXoOz(ILR$?VC&7H=%kwSRF?=B>ytu_fYZLKVk&-BLGt-nuaes6-V(2cjf(#C2p|E zWQ46Q_;`~nwVaM}IDYTM;)whNR9w%J#W|l06)nH7w|h-0Fy@<^&Wy^bz5>MGmN;S? zdeCS>7(8qWf7=koP$q2vgV5rc(5qnw1h<9rdH@%3lj=3^k~jH*AeC}KT?UU^!|v{L zj9K+I^5UV>_=CDcKb6Y2l>!hp48SBjZx+8HEhuznLp5LjyJwVXxu`wnD@$@@qk`Gg z%rqIvaFkV<bd}faJQ;|Ya1cfAZ(U))1)*-Nxw21k{iQwNGR_$N^8i{+e+uRV*KJj} z4+?HXm3G3z0C9TPG4=i#O388>^PinHumWXOlf|8LaP!~tc;qAqJ|js{z2JO$9{PEx zGxdq><GCN95$T`=Q0#K)h4<G8+2s$XMTd+T+(hU0b1ETUI#$H0<bUpoUgJOv!Nr=N zMs0<<Ozxja+RL=?oB7(A&Sa$NfI5rQu6^$2E$gZz<pvsx9_hp9XP*vLYp3G6t$Z53 zP;E|$lWEAyowQmoq|LwiQofu&*&J_vf3uCe+(HYY;0@3qoW~1oK1C~zR!Pzdhx&23 z-Ryq=u8IO|E#ixTfL&hhpcIV;V<AirEk7Y9x%$(f1nC3Wc=BSIMA5_GtA&WEo{tdX z)<rs%${}{j-*T0KZxR@4fIMr0{WC;DPVT@o=qMu|^8UWFb&yRHp<0>l39om8c!H1n zS5^tWRXZPqpT#GMqK3%f0I^!oCs3qRIB|evViJ;6+Ey|=<vMD)YwK`5M*{RGWIB@B zBqmCw(X4XU-ryZEK#mrujrAGs3#*OPH^+Sicuy~W2_MpLP9_SHKeBKV*A(yLA+l9r z0D}|!8z7ZP_~_%E%Rjc8{|T`d4iyWGnR|S}lh0rZz=mt~Mdsb(vW;(s+7bpnx!p<! zDL(m`NU&>9wqkkInxHVw)A`fpiNNt~8^221)WZllS$RLa4{*V>YtQWN7Zc%6mUr6^ z1e2wr<wuA1Y=_sCgm&fmPCeVJs8{agKmTsThV=;uG2qnHO24ZBFb^S$U{GgQh3SaM zBj5v7>kSKf;R_NV-LtEljN653i1xB?=ie9I@zVEwDOF=xjwfv17R^0SANJP7!J{Be zpkRbkykFS2K{VO_Bc04q1@XD_(9JP~bESaObXK8Cmr6ucG4$p3)!7+-z9P!0Gw5Wd z%!Ld+zOo<x5$2EEY;wO3+5Yq!-cdU9mHXI=@#L2CvtIJ{!$+PF{Hm+(_x9b*5^Z^K zLfHqd+IYL*pvbk5mB>e0($`tKxZiXmB(zum(~fa0_Nr^S+Sx7U1RnX#BZJJTN2v0` zSsE!t4vkcx4g(a=xWc@*SM%{`laan{6t)BB6?}n1v08sQS}{ckZZ(WSzl@62A2|b? zEve~lK|$&1=`8lI1kFE3a$iSFP1H5mZP{zd`ol2a?#eW)LOzAqt`VVal<)W2pENct zt>vVQKVjgq<a4^UhT!|e-8!$B_ONX);i1iHYqXn@`s6~xG4=sXmtV)qPa@C8JV}Kc zc7!CJE@mX)cYLfOjfB!)er?hUJ`=T{>+OCw3Tw<|XLMJ{{Hwp&`B$n~Vp2+&P6>TB zZFb>uGu50Fj#^4Qdn?zS4%eJcfGKu>PLy8eYm@W%CVtB=QVWX&it2OZ(!Zu<eR2^7 zB&uH$CK!k4uTi+h0Tpu<LvZL<{($%?H=9vrR3o{STJ%|$@+--qu(*QXu4%qp&}JNB zdssb4w__aE^2nXg52r16f3&5B&gWY6KHOB?D27EaM2=YWgktAUAfCWE>=d<{fpzR- zf`n?FfwsIVmdmfO7G|({K$p+Za3PPl({;&*gFx#FKH9j+^wy(uG9BdU?aM|Xp)x_* zcJ#{hTSbXq)chWcjug&=7Ofj{LJNJvNh2QroP*aV-ruR7iy$L)K2_}M_+&EZ%U;_n zH@$NQq4Hc5_FY~14X3wz?eOw<>Il4svZO)8IE8e)1#SS4GbV>xlaZc19Zb|$0c%w& zu1F8VG)yBA{f@vPU0|K?eEtGOMoG)fs@s?XZz6$7Gta>emJo|0Mn1;HVVjX5aSo_Z z<XeKhk%W-}7U&hAv#uDe`Mp~nxK4RRF?K+`4ZBrdXCf%-^_A7yNq`SsSN$x`-mZo@ z7ZWdkuKv%iaormW_2Q5XGM35`%CdZURB_r^sT14ws_F}9PrY@d!8xURtGVCMO@(T{ zbar=wDa||9hbYrT)ZU$IxPq>-9K89~BSTz>+hU@kxSo*Z&*RfCDWKM)+aRDjN{0fR zTB;aBB&qR!3acQeXeJ?k8V)Gq04(VtJsHU!a!!^R+x6)1((H}}js*oZRk92ZN3mb$ zjK%%fY(4&5_gudDlJdX6W(jcQsj(cZa$pjfcaW#pY$@R^=V7mDYdjtqwbGqyDjs{f zJ}=r)#QWk2(ny=xFgAJMR<_(Wdsp9QW$t696%%HPIpbKC=J7u3jOfJp3yj8yF~7P5 zgzN=2XKte+2`D!_ul98AGrXHGB5VewM5iqdweuyGU1eGPEeiTXl`qiuq*%f1Ju*`7 zlw$q8+)8h?K3Z1;9+I~B+Bq8Zy+H6Y<}caNBX?D3c?wy{0G6_EyX6DZwMF#>D&dV3 zi74vt8=7zI5**BolOpossXXc$=k*W1GA0AoFk<s#wRqu32?~UUCk=6;BlRyWQy5@P z&mhIb_^3Y7T!3oxrFWr`YN8@iom;DZk<9x@McQSn(a@}RBFgkOD(~%|3Lf<h*o7VK zHml-fVNr}B*n5N)<jiEtRw5vw)0o+7<9R(;2!F=VFTdAg-~KV|s4|+;b?Soa$adIJ zG*!M&$BUAhf5FGBLDk+|pDjo|EDb)A3F(6$HyOEIId%=|gq|EGH!rH~GxpP_iIxkM zZ^s~3G&;641%+iDH*Qpb@;zBCccaQC-<KSiuWxwbNM2j%G|8_{Q`TE=$fhTxB)#7C z5l)gh90R!z*5=Q&FrD6r)zGMB&LDF`55TTV-`Q&Cn5=oKx8}*bi4?WJip+bx1;bNn zHzc$~vp|c6HGAG@n?QB;othfXHqN_WhK-j`;CCB37rvi#))U6>ITOp!b-P}U0xgO2 zI93`&HG#)gL5kv<?o5E{XKv2gVaJDZonjzcz3i}|i=dKO^LM&%8jZv+x8EM*Y#ghY zP;Gua$tTOQv@Dv3erg*|zy0bNITO8d96f556>vR~`Ve%m7oZSVKd(3Wnab?uvo?VU zh94H@KQMjs<}1ON&Q!%=&(P$>ylWAEpGpZgeaw|oyEuw9i^@-$TCOlua!sB0PaCBM z*@{tp1$rkO%2dMl)9OX4PIbY#m`zFf%)d3w!!e?0*0}j{vliU8uw%V{w-ywXYZWW4 zDr<1q;Ia$n%BRm9*3)C02!h%%SU?kFm7hegf;RRT(wUn0;+GC+&ZX$Uc!QUOrHNly z=uGP%^P`gu>4FbxZeQc0uA57v>g6%^zOFiq=qV{4GhPqP^+$29>ERC*RU#89(74n4 zM{TvQV7|KEdq`YjpGJvcmKFh<yo^2co9(LyB@-~vU~Do{MJ$+I(-4IL)9TM^6x<%N z(0A9%AP<*9iq|#YJ(QDQCwK{F&NbGGM7Cw9_SjmcNG5i6)rUVC?y(kbwva8L*!8OZ z`~M?@;^lwTfGajzV()`8hfl(0ka1IJm%`ihx<6J+wZ4&Z4{Sw@QR@ReyEd#CctdJp z$3jvvi6n(99OPi+*%kZzqR8$cKM_KyeqKe70sr`Xu8)5!hNp}y?O#BDgMxO?DFp=$ zhyyBQem73uTHf<a%cH&r5xe&3T2SD9Wf)=9i|q$h-hvLoKYXl<WQf3PSo+~61kFPj zVqy59!bDT$i&ytPFGMA&^9gZJivX=%9pAq0IT0fH_B#t+g$x-;pWbiZP~}^QEsA&v z!iw6bS%kMYASH%tBO3}!DJ}XDKVwD^<vvwTBCgmj7ceKL*_}=h(beI@lGOEf5(Fh8 z1}ia=4@57eVJ1eabiK>z;SwOd?yj==@n=FWu0np{Ct^_ua1VtLR6yOof?V1up#&0E z#>f)|fO1j4mH^&~hPR3AiSyygeoHnAhBb~U^RWd+#5o0qpNpY7LO31q@zf8>FuRg( z<!(SasHBMqE%^WsDABdUm34dVn`H6+gD>9a*!e?eVCk2IY)xL7f6MwV_-z`rNT^!) ztPzduJJ=fp`_>khKU>iRwbYcD1B}{@T}I32qFYuPSMa7ijGpJ5>+eznb#4-I^_s*$ z^7_2@0gQngrFK_HZY3a1`v;4bLTQF=TOHcygI|`wqo-1ela4j1KSLi)D%)W;Z|w9L zP#+@v`qWtZ+E>iDf`iIIxU`_>g@teS@12qvUfCmeIhKLai!{}050L&Jon=CGa&*;G z?uem7$2tvPS&Ou8nzQ`3v2#q-<K`WIIAj&3ei<&v*n7Esl_uNme|rGRK2_8lppUzQ z>p50u$g)KNqUsQE(QjSLi=(=?IWpm`1G@xEB!MVCqi(9x`Xy8l++3YWX#=7NUO?!b z=WvlCWia)-bVD*1Ww(jB({F%~<>wdoQ+0;P*9W!*wvL&+JI~2E+f1XJkeHZm{Sn=y z*Q+wt#D-w^Wc|_Vs`vlS##=v#xJIwA$|X>HJzv+{cq2NC3wB+O?XVcI)JwKVlLXLM zH8t#Q1TzaHueJ0zv=oY}=&CmRi_Z?<GvBr7Dm5)#m4g3h9Qm#}%lA(*1-vY;ym-!+ zt?F@BA##J%ULIZYNXBF)SKGL$KC5+%#nNiE$$hu=Hl<JY2G#j)<}y^4bgiqn&6mDK zJG_<88NTZa^<Cxfg7;-8NTd}QmE#?iFeN_*!!HpU(q3{5JwFv}v|&g++@6NWOq^_s zyzpxykeiR^zE!B*e=a^^%Fq7G`~3`Sj*T>d+eeD>!1WViZN@lukjvVVQJnqE0u%g0 zhh&ixE8g^TQL*;X@T3oyzDOJ5ioA!qxo=p4XhIXyv1F9?&FtQhjwW+>z>Ag>AX;<j z+U_H4=qoI_25xyfq9kIN&oh<IG2N;eit<l>dyuC~`F6qEDwi`QBH1S=3)ojg=z?;| zu7OF`6&yI~J*(ZiGwU*_>oVpKTAIXei9LG6=0#~)4r1Y1&?;XmrD`bE=rBk=67<^{ zvRU`i)?O^VZF5OBxdIaqGKDs1%bcf>*fC<slb843Dy4psjFSPA@_P6EQg(6A)7i1- zykbqBpQ$Rkf-Nkq?7m}CNGI$J81trUX6uN;(Gr*`;=dZev?!dW%6+lrMClgzsK!+N z^~**`*reKzr;h03;rMw{lQ$yv;2ycYW9`Lk;`&NqmT!$JxDT>q)?#$551Qm-l6=Om zigDvs-g*fZ1s-_z`{a1}qr@$XL~_*%#D!wavu+N;?<!A<jGEM!be5M3+DmDc><3qS ze3$}!@LC1OWeUE|RExH(Rshnc**>2)t_eekcFFNI9C1eipBa5k>Hn?k)$N-e7${1r zu(Cvd*B+ks#~sTqnT<lZdNr5K6FktQp_X^kRSzfWYZnCdU8M2bF4p!40C|Ep!@OJO zb#T<Ldpr`wsr-0Lmdj3ehsHQkTA&6khca2;J9HPdZZ(#l!V{L<5415JV8t_!Mukd9 zB?0n9aWiib>YG93Q>#E090N$9VdXw%(6y)Ms8Av049vk(2IEG{k=v7`b23TY`kZW3 zt0bOIthV5JZ>U~9)}(iH<ww*3UWFBI_Q4G}0q(IkK?tLk4gPNk0O^do!m4q;6-b~+ zUya!iM1!9w|KknBc{h*rqWRo_9Xybd4vhtd!!4WK6oTbhbxXCh7Y&UJ+!<(pHu=?I zb_|E6&W6h%*<k?k($F}}#ny{Q?#PaQ7)E*9H%TyW(p@JZ+Er6zPO>WQ4SoLCVqZh< z5PDvakSd%Tr}BrHf!%I~R%u3xUL2%uwC2;Q`obr2)NX255zDjCl-zGHUE(42+cyV= zns#7MnyNqTaVs5*6#4}ti7Q_%?ZKWAaugRU*HAQc9z&}Y)2w&C>q9Q=lc%|9vdK;N zU`#>hC2t<Ys?rJzhMP1Fpn8WZ(ivjMDche7Q^*OUt(Ip1%X7MG`8el9qPO9kWY)WW zYULIy>klMOZ$p?!&UBfpcV&K<^zOC*YOHc@>rI9c`8$0fuak#)7T=aQM)2ZG%stGl zRsXuq%`jN^&<1J*o17A(un}L%(`S0F?y7aWG<@yzXExr<8!Suojylx(Es|gNmL-Q@ zQW`W}nZw!O4E9V}FZaN$QV2}#SwugbQ}+eeTm8orS=MyWjWO+F^UDVw;>5<E2QXf{ zkl${Lyyg!7*~IHWXI>QyLeX)>Kn76f${Q^Mr2Ovhlm_s>m7#CAJ8=~5N>G_N59)<J zEm||O6(z=GL~Gr89MO}xmaahUwX#0{!^B@)R&}!4S|VZr-=ww`(8qwF2b9&nbKpts z*7%KlPJyyUrm|zz<4x^_6Q_m8%or9cR}Z`~NxjApm!cjYW_gG;z4f#FVAbF#ZC>S% z4+~x#A14@@rhKd|x#a=EPadfmx!$h&PcH6P4}C=~S*I8eMn;6Phkb`Td6Rl<B^16E z!WG9Jr2XSsrGUA_Y6kcGWdfJiO8}+?xi{kCz4y?0>m%xP>F3oC6EjpHRh@hjHuS0C zu7(X;hKZTzPS#AOeC(c?LuJL~yq;mQe1PxrP1HZjifZ_nip>7Fu?j~UtrdS8tbs-0 zPWYX&4rqQTyFO9}WFocV@_n(yh!~)&j#4>a*IIC1vHyCAZ~VUBLAKABsOWGj4!M{+ z^HfmX!bW~t9Cfk%$RE&0Hy_1b3miQ0XhjU!>y5*HD)aCZa%7>E?ki@%cKS`j0x)Fd z4oXLI?3PLVz&3;&2j-34bL9g=?VBj;?VCm#P=<?{bdYR_lR6*Pv3dXLy^-(qK3qNL zEo+Srau6vGX*+clsPk{VpH=ec@U(8YAg=gJo0_eClKX5#v+mw8*W&N~73FVdvsI6u zuDHJhMw{Akv6NtDhQ%H%DGWt{+?yxAaw~py`nGt_%X4vt_0$y(|0Eq^^$D%}?dE>r zoS=E1nG=x&W>{FbN!G9wB0e5gN$3jmYG~Uu%UyRp#9|G`knCk}di7&wrfd|rO4>%2 z63ydXIO3pL*q3N7Y*h-eGG5%YC+#WVcWyT-Bi6BuO5nF){8hkj5F3)<TRDJN;h|WG z9-rv3^M0iB<1kh-R<fecm}YO}$J|1X8hbvAJNJd`dIRKd+euR!xCLTd^>c4(PI3z= z^0k|{dY8GQN#yW(d>TjIdW14zu~ovp)Qbv~8F2W<S=dQG9PZEsQwh<-5jo1=E9R&M zCQ~Gb$FqgxBad~c<t5e4^4O;t)Uz>pyTR}zNz|(6SZ2{Zo<BHr@8WTN;ZzM)v`v5M zG)|`d3#(|oJ_psVeu}XmlN!EXyuWsJMlcYwUC}f>^Qa3sa_&`+P6hWYEzY{sHr2(i zP?(#Q!%2jXZcGk&j`{!7#o1E^Unrn<)wowuNV_@pwX6%S<o}3==+f>c!N%sh)v-#3 zKtYXqXk}g2`RJuT8fHjJW)ZNEgv|>oz*j8Z1&)2@DuG%pEI?4+9X`Ih?cUQ&n?rmU z`3H3_;#x0-9oCVJ3FsD)AG1Lf?#Qb(n`$0>Q@8NFv1Mn(JYnAJ5xbKDgxlFi8x`~^ z40PsiY!n&kXC@}+2=B8es2l*g%23m$L)7v5`Pf{`{l#*|9^8qKz+zpv4XjE&*hjp( z((i2KX@QM<hg&FH?6Zmf8h8U5v#yj(v%&JY@A%oAF?F}z3o1f}d^i|g<F5X&;&J;< z0<X7!(Qi9=r^(XmublBB&3WTpnHP^L9Z#v5cc310Hrm#bJ^7sqFAZoiZW|^xz#k%O ztMY-vL#oz%X_0OU^cTD1(q3A`^d4eF?T#5)BlK@YvmnxG(b&(U!T*GpD$t8Tp`DzL zTfu@ta237{ydGYwQ;2c`7<FFIOdxYE1YK!ODAfBEjHSV^frKnEANPh+LF-5!WBHxl z&O5KljP3l;+(4HhzR!2Du;XUAO>*LkOqM&*0)BQfayww=%JYA|3RP9c@a36XerdB2 z9ph>@U$OkWMi=b?t~<Ct)4Y6_yf{5C{@~1fYn0Jb>(V%~X4{$qc7P6@FedXzp(k+Y zUbFMHF;JeUxl8Ydwg@65IuJ#H17uH5J+%Mxx9vmhnCqG?eyBWN0$*Ugf>usPh`Hej z=V3I(DzhT<_uF~iP4V{ZwrxdBq_4F+T_S@&T!d=2pEy=M0uvx>)y7ByHf$AT&7Uz+ zkAy?;5~k8OQI06cf0#~ocfNeqAf>TII?EdG?o#>}c3U0&6S+t9+NQs6vdy0BQ?fAQ z!}OTZC|D`Hb<?%fEJka-finwO#I4v@IBVx_nTXr9OaFr-v#_O&zTRulCAYe-`likB zp_Wc7yvCG%F(%eLf0Ndj^d_u8?@vCzYMb!dqqLLY)e{zPNfdmn>NTKqEh4^~K64H{ z9IpQZ`27I7YZY@S(H2$^dGWCl@+FT2R*GAuXSh$lts*neYUNs@-`;N7FAd@7s_;Y@ ztM=4NXpJeDV5Uut)fEFPO3=4)kS;9!0gk#WZiNG(5I!EzR8?1dg_89lv}f}6WHWLS zTyEdUzBbq_ulf|Jf=qJBSbDT8p^e=tB-)*yMFP}S=pl4ogpV>lwO=b9#=MX7KfBmX zc92GpIb)6Z?zWS@pS-V?5Md~IzumV%S3c^Jq)FPhVfBxA8Tj5|Z~=Nm-^=8<HbgzX z+BbEb5ur!si_vw$QmZU|qbd_#t!xjzW5(lHzlYU4q>d@Gy}bLc$gLw2^{PFzww|Hn zqYOYe%h3PN!8o)(34-HssDJqVeIxAe_huC_Oa5~adZ`pZg-0u_oM8#4b-w>f5<?hN zt)5>taL{8AEbz12=T9~34-LM#Nr)S9LuPR<XblBObQn<={9e@V^TOB4VRq9D<7n$z znnfcLl^xwE3ufd`tAp&;N>7h6JPgvM-1jSjgG$a3opx=1c)P7=A$`BRsn5%F)~o2M ztFH<(#6dDahD1>g(j^upij9_f3!y`SQ)Z1fL7By}X19r?pdJRtV>AJ!)b+6}t<#$v z{{1OQO#`J{(9bU{G$FiL0~)Eqp{IRi&1<h@E|Tiycl#V5!t*^0oM)<H81D^Ed~htL z*jc*0`SZ(SK0}ChaP%%RMGXo`%pNn5s^;qeR9hoKs3WI}f&Lw~ip(Sg>9-UR-Hs_W zpvtwBjTX&r=MW^0$q-U^j=eW~TKP9lDh$FEh_gz*N~Q~#%xGZcIoADUC|Mvfr1D!y zq+dkD{L4SMm;YvA#&KBND_57vjjz)&2&Wu*WezZDOV+HExb!TPQP4cqN-|K&V%e!x z>*i1xz30<#ZuT@CyHzYzQCwGp;b}sa5EHi)wesSWH41m2??+<art2y1NKrG*xx{r< zPpT?Fq98{;xf@v!t8YjyDqvf68ouVE*SHjgsTyZtkeH^Drrax<SWb-qQ=M|o2Trmw z4#O-;m)_dpX?SWeltYH*rqXzN?`4o6W_<3j07sVISrcu?DcbWk^{RQzvHBBLCMI%X z$N(nfh*1UTIQ!(Q3YL-65CScxYw>OEJdRrPI5_(B_-U3@u_rJ5XA=9btELbWZ@+&} zDyQbI3~})M67gE<!zkSVz1O*@nphx89OI7%cX-{ZswU~&N&W?#zx`Fjluk;+YWS*1 z`S;)#1u?cMf@|EAH5kd%<H<;+nVeG(JjclDro39trze7jm)@6EJ0&N9N*#jGSc_TC zybb}bxH6R*c!7t2O47pxweEl=O-UH9?3BJ^87zhdrC<6GDlo_J>_WY6yNdR?G-?~l z<3whQFmRs4rWLhc+SiwgKhi{*%BdQ-=nwWb4*=RZ=V@Z^*xdn3)$PCg!M>%eB=td( zhELQ#sg~Bd<KZt6pUDZ8MZsezGzSx;GmS*mRD<XjDoBse_=+6%VXBEbG~0WkV@;5e zr1WbNcq<|=hIchE6^EMVow*N*i(*=7E0tl+GHK<tmw%#vbrsagZCCv1sxTpH-=M8y zKaPssuy`lYf9T5Et3FmT^MYnJXM*-ZD+<3w=T0N=Z^YibnfTS{<X5QgK|gxpmtQXH z@v4PWxg4H|9=gs06a>QW@1d_i@e-%W=1wzQRQz0LWMDphuk9(L=UE0Hz6+w%e3!bn zf}m&1Q_jBL3V0V8pPauG)9Hkpk&gA0zqlhGWicEOXX1QR9>sB1m%G@{UuQQzWioIV z?P7a2d=ZO1YeHk$1zb-qBRg=k42SX5Es}voARmXLh6XT~j(BgI^T!KmXvyqyhsP?Z zy;N8}_|CH;B%73n*1V$~w7%@!dFn?NIOOE3Ar7h$Na~yikdpa+*H=cah|3Ert-ZH! zJOE0EC?o82FPfJ^00>!`F9Uy0^3GH*gVE|@yk{jdGj(VxO#Zhm{gtqn+50~GYsd-d zD%rFsTf7LhajcQTsbJ*B#9v?!n3_67r#!0~JGX+!l0o)@VD4St(u8R~d4-x7PiEl~ z1o&%no(5l#IKrsXZSdiqFUG<NiXHKBIrcG51!W(h%x(XOivkr^zte;Kd+k9Nt(#<# zcR2@pmfiOYCT^9*P`;^3bdUM_21}N-W_`4xzjvFm1Q8#enE&>zbMTzw1U1^VLXkra zb2S^46sJ^RHD2;DB${|2_a=0_Zv-|<D3E1FwI|;)h#@6siAtG+X~LAsHR}9@1oAGg zc#MDs6P*MomF-w+;*`<xE>=^It3(Cbmn!B-MCSkQnRRp`?9NWQU|Z7F{aLeTSeF}u z_Y>4IO^(c5%ChUmjMVHdH0hF4X2H+H|6~^oM7WS<Es?EC@}Z{IL6HvM57McV=rdlr zIC?*F<%l(;LWJtz^1lr4$9SjS_ouy{!P}ItHyUh7r-qZ|B1uBc?;~!{GX)dLC_)Ch zF7-Tm2{!j6PlbHR*XU!Kr(Cv(yuIHFXLfDobOE@<g$qAw>Mi`%Z;pI0AACV4fd6d2 zICg1g#1X>Gcodp8;!FCLU^UkV)62ta`Lwmjsu+(WvV03?aMeVUM?NY_Az1#1_w(A3 z3Taw*SO2}N-pjABV-;gTVH#b26p@ow6zdu;qXRAf+jtxYZQ9%9u`^OH?3MJ#bfL^m zHzxaIzQMiqbKXpCuZH*qY7(gO^iQzD6k1eMHK|O<lysD*JDGAMpF)0nx~_fl<@wJ| z_6INzSUQjzE*hT0xMSy+jE>I6==dKN%_ZLE$TlANOk(N5PVAk1BWaqTP`PG$C7P@_ zJ_js2+i*ykH?)R&Bje-nOw2=Se^m~4kdeDnD!YB*9i{tqFD7|rnM>xfB`~M3ST6Ms zF2$#Ts@O!2fnKxSUUif9$?O#9Rs`k8yR7<g#W=Pmk=>A6q??m9<HL+(nj>(c8B4Xo zCTG#28L<XY$NJNG!Y6tkVp?^$u?&we`st(pL)SS6XYy_RekOJ%wr$(CZQHi(i6^#g zJb99t*tTukxpUv&#d+^Jw`$j}-G6meFI4yHwZ0#H21?`?DtQjG>S(a~ktTDg+6-rW z&O}$|??7Z|Bc7Uh<cXW(p>s8u%9M29T!`Bz)A5>K4i6(^{HlG$QX_nEeR7J-U2}ts z$&LVNwZA+_SvX>Vuq=D&{hd`gI+_`kQVvRh9wi+h`{=0j=(%>Wj>}0pQNAO9cF!_f zUBln#>O3H0$Mg=SMwTn8nN&i6PtE2>;<dAiAi+`C#4n7!ffofb8?<DzauadhTkFE= z^r5b#F_di;-xM_)Zz!``-ire?RsFSkFOI#r>y#*wPE@oJop1mLgVAl6y!)LTZ=CRH zPQK=^+MVi>E%yRCxcDOq=3$A>0OkU;v_I;%+ZEo;QwVrorD&<W>ey$-B9z_5^eKln znMYos&rG!ZTZk@F;y6m4Uro)^0HG361Bb}lg_PTLRc#&kUbCXVJ2pab{&36qo}osR z;6>6FJfwBdr$x*oIws9)mc~D!@!Msv=kMu%mQ!RB@FdWN&erwRB<Nv9&D}*piRDOf zM_}^)z+UALNrELZ81~b4fkXVNcT7RcGn~iKPi_G1PY=BK_J;^zWZRICly`#W5DV%@ zuG^{J!Ujv<{fW&A_gB`<#hS<Z7r$Cr<yuD%w+7U|YLH(V`a$sH5afl3ar)!mmVy8B z`;LBMp4UoVKUbNkEM@0kY(L(b_#;mBUS00S8b|vY=TJb(Asz1)dT+jP3&B=os)Lq+ zVeT1tw2V@Js$ZDrhRQCA7ocFXHayGvPT6BdrM?xHyZF-1c0Us}??XQAVt(ZHLo5b& z@~VA<vs8oN2a{kGCZ0BL6y7Ot=q2O28_L*CZH@e|3UI}*B57*hMHtYH(0xAPQm&g5 z%+8KS<XwKaxsM3Mt822i!*nB_3+}E8&hBU+#;P@r@YwDiRpcOs;ChI|8cS9(=bCFv zPK1^<i&{12Q=K3llQkqa0HNp?DwD-!-=X-{o6hgw?=Qau^TJ&kxWrd8g_bC@_py^% z<8t=vVQ-F~vhvX0UaO468#8L2IM<0tnL5$#b&=R>_Q9XApG9MeqC7WK{bN_97Ts%| z>qK+SuZVN~&G<Q>))p}ARI;R|+(B9lOtLNtU1A5*&$V<R{GQgJWYZcie)ZG*DqXY6 zbO4r+Ht=TJtwFWrOvqcWPKT+cb;vUC?PdQ(#~|D1jxk5{Pb(aAa?9y2KkK?0JTdWO z8IxgQX`@E{ojIYoIpFXW$aHxopOBN<!={O$J=TgGJo+HJ(-CAoF)h-Mq%lu(0@SRL z^TKO%-61Sr59xE|WEPsmJ$QK{d<oJJ9JLYYYDRg_wVcQItZ@<~J$U)F6`7g%H(Slj zX?!OjH5$b<cjNpJj@``pAr?8t{Hw)j|HKpKHjKEy(!MCC#7ZWBk!5-UK7A#kgScl8 zFAqFVpEWIuoyAex4@o~5;}4>WixK+f-iu>QBm5QV=(6X}^lt?2bL{6VIWYng^|B^2 z5>`O<^J~X+RFoZUH|IUv9Qx3~HE0o1(lRWPNA=9vnxxuXsp|0_HMUQle5KD>qX<BM z_Byz%f(!E%A?tba1+$MuN&nhaVfU+g(#gwlZV#tE69@Stll64~pX4o$@V`3y|0S=) zxLKS6ehQ%P{Su)2eU42#D<^9j?r0cdc{LVDa0)5hsie}ovsFc$5$MC9AYfA5$dT3` zVl3C?QN7Torb5<qAFis+f8QN37;yX<R9{dlVwEO|2uZKOgIF|2Fp5AW{fhf$TLrNq z?rsV<S(HmhXj*8xry(tw;}vH!EU{}K0Gn`d^6Xci@4@gTD`tcd`-yva4GI}x^7g?f zkdYYPz!S~t367`zjMSw)$N|YLu;PAH>E-MLk1Hq8DU_<iTa-#s+4wX%+2kb?=VdY# zh9MB1hZ&Q%7|X~usWN!aBDuE1<osPyqO*6j&pc)cwoCU%v$ed}Sr^V4@$WH0DbG6G z1MFi0?k3$2b9z>>OLOF%T;riBP`edjksWggyiMNiWGugs9<l9to`U;G(x<Fwbpm86 zw)jrP4t*;9<Z*qUfk)V08U;>C|F)kOORo^yWFH~DF1x7ih+}65h0UBi8WI#%BL=+> z*^(YlaJL%%C3|&a;-$l5b3HflmGFDZ<2?lSZ|EpLV?has@L!WaXLKS}Zo%YUCC>#y z`{q8k+-nO(M_xKPZe|9;IG8e9ZVxEKLTuIh7=l+<d*?~{mbUnHoKloFQ?|hc-ws;Z z$EUg${VTSRm_`IHPE-4|R6XRj*$vrRO20ir?k@&QMe}rkMw)JL{5Ryr|8<W}H)H(l z<q3Yei@TVJpH+!=u%X0mXGXjWve!)a(-Fs55X9xgxV_YkE}Ybh1DTv$izlKH5Dq+; zvvNPBx$u2W`EIc@CfAjRr6aczRlmvcdV)27*rekRhgjUij%S2+Lb6C?8+$3~$Z4C+ z#M%t1+|*&fn--j>`v`3&HjGS$&(U1JQ3+m~TKJp?ozsE+Ion}E7LK+ndb8|<8{a%P z8~HTopn{ch)bVZA?3fkCAIt7uY?}nNZIbS-t>)(YzNyOkNU$4IZyOYfMGfPC0oATk zvCZ+p46U2ZwAr-XXtwoN06;pSt+E*sTt0Tr!rTh=6RFgrDwIx21a&QV%APyk!0@)r zdwz?w3e+#(MLQouO1FYSe{C#fpWHSfWFL$ZUYdY?R6VKG&f!-?7mQ>e4_G!aj>0^Y zXJ%WeU?dF$?_|WI7#boK2t5m!Zp8@FwYk3T{`z%pzL3H}+h<2*HW^4GLz?-NTE?x# zS7tF8q&ycc4{b?7{Vn85@bxhl{HTm2CFm!_JNV`|7n0KVbQ#MR4NsJKT&~+vufm?j zD98b<9`7Zlfr5uj9vCo0JvJfGMdqjJ0u+qi;4%c${}0utt;`-C_OmT)cV%h&iV;44 z!^R?y{5jluL-L?~bPy>ma$P#7&tH`Y!7nM-?}r@P_D?mHX^Jz7rNt4e>wUDgW-E>8 z+3hl7hMZ_O44zRsYUFj?8v?~Nh;(Q!sqIP59uz)CPIU00&XCq;ml^N9E(k+MCe^u& z*ons}hnK~-vZ_|8F}D)z{feRSyrB>Mbun0-l0jP{k%*APmW|<OMiSc=&v$mvlH1^$ zU4#CIb)HQua*ewd7s7@!!<7sp`$dpMBmN`pY=Ob$v_Gxxa<ELrp>SGL&6YHpbKFro z;{e${`m4QEOvl#}b&*83?(J<yX5c&}$MJaVxyPmZWs782X4Cam$ojwxVc~-9L*91_ zX<HRn88D2(3U2;;aV5}fPWmk}BM_wt_^#z;?CtWo=5L<51?U!1t7y9FW!4~Fe~n2^ z7`=Fo`n~OpVcnf=l<Hib^jjAu41n(&r`QwtH{LIE_&TZ|*FofkK#~f?+pSF^^Fsxn zG2xvB*ubN@(){#`U?VgtM_n%5)(hg@gmL$sq9&=x6E~;9nzaXBr{OqoR4~K}XA7ro z?TFeUt;G5~W5~vTN!kA}v;Hf3tJhT9!a={5Z3{<NfcCYN&tRtRby?*<JSr(u!2$J` zjYD=NX&?f-3O&MTyFZqgg!mc@j6)V8UakxPS-))z14QNQS9cfFKsEM;i{Z<ygP*cP zPgguJ(J<S?f|)m|!)ESn@x*1Q8U^Wj&Q$@KA!+Dp)DJXh09rpqE++t!4^01%MYE?n zuQrO+Nvml=Y48+DyE>{*E2=jdirR_G#-JOh%X7c&vJvfVd<h$xe^ro9|7^2QGlkQM zZN}<tG7IdwdNP9B%6Xxp2O@=>EFv15cX$McHVtlOXI=CY<_a6ZOwImQ6t#A`e?`xs zBK*LlGBixj`}L)lG;`M)PZo=V{A?OFi{Kt|8Qgw=tNItVmXo7EfZCPqVmNDq8WyLo zF{-^^*}8?oc;OY<YVYtSOVXfur8uvyiJhZqzk&goc8wy^?usb$_h-O&B%~(^4y#Q1 z)@0`0hF~C8pffY6-v}gSm2GoTm$g#n0PIp<jV5%|mAeLSqG>tb2`C&}(zz_1Dt&&` zFuVU(Tt{BP^=bl&0taG>2mGv`lniOCTC$yq|05lJ{`Bhzi@i|YP@Kud!wJ*PxV3c{ znD#gFTyCfHHcdR)22id414R38sd>?^5-M_!0CvB1#$IXrv89vq#nkE1XxG%O1!pXr zChS2l)p-lH7KiUoM4!kv3_c={pS}Cy34Oo>lxm~p9^H0X?1TFgQI(fCsCL)m>$n-W zx62736B$p=Z>K6y&~_`tO9hskYEie;zuR!J%Kh+s?2=UXki)Bgyio#zZRAZ|gy0MM z#Ep?0;=xyUvBnJ5bh@>56u~PBRp5<hl$DquT`d)2JafZ_!s#StbK-QAwxdT)&~AX9 zPP@o!SPB;qBmHP&dua?idfjsHF&Op*KNxGt8wW(9Oq%Ki@L7xHq-Qq`p-~fl9ayik zfG45BA9d(`8>G-=RdXv)BOSEzG<@<yaOYCc<-I<x1~o)j{XqPudOMMXD}hv7siP)m zi{wstm2+M7oDZNA4TXP%{RJhK54jx(syTHD!VYqQ=&5C62Iu)=!6<;Z-3KFfjm%Bi zoBb$iwiw_sRlPsCdQH@m#>%o$^vT>r-PBpubBey}m9Jn1Y{tn$;LnqO(&aG#1;jg$ z4Q-VWvYJpknva5E3-f93d0kKaOd!qoekQ-M+-r8n|2zM_pC#O7M|oo1iYv$WvBBl3 zaB6O$owe=?8bNuizc^9byuh6Vj~!EZQRq;!k+5&MFg?Qnu}tyYm}FN8EE3;T6h%&^ zs)tv3Q$>%Ecf^q*|JCkdTQ9+OR8fsHZz+=jQ+7*Ae|<t40K$@FKpI9i<Nem6a4~i8 zwSP1VFwygNfLp%z+sbFvGY?$4+Wfu5!*R9Qq2(RrVLua8BYqps9B=cJQqtLwC6*q3 zDNim1!t}r6bN<iO{&NB<gC49L(Dy(aGt85=&qka>gJOld{Y4q1t7Hr4D3tjP<327( z=3QOK;$sa#)n?J79geRv-k)m8HvdRkbpZm(Ch}JHvk(y7SSxEjxRr5cdkKPFLYJ;Q z|H`(`jXFDi&Q{|iwPV&C(ZnAP^_BV6Ckw4`*u+NQ%{ddTLXd~CVn}B#y&YnfWMb~W z|CK9h7UZnvBSkY%nZ@KdxI|DcY_;^B#~@h|cULn0DuA9UZAXG2EUD|{=rQ~t*(%He z=0xQdbivGKhWOny>|FM=N~yZsY5RJow4|xvJJ6#loWZT2u(C+R`9|41shLWh&{-M} zT1GQO|Hev65!uTaltx*)8hiGNYF!ppTT%d&BzH=}j$w}Tp&XB&m_*7{kA?~nHQg-G zm-~<mrj9C>?y5xB$aCoR%>MOuf$$qR>4Y^qa=fIK>V;Vw_rh&&sT-$fOFo+dY*bx^ zL(1lgie0XI((D{}Iw&_3$&PN2X@`)L53sbwnturf=b-UEfl(UaQDHYztP_n~ANYyK zMoyX>P`9tS<4=|7thfnvq%Ybl?c~1_i|r_WM8hQKhnB%yYXyE(aUuzRgpT-z1hGke z&;eniXjjXVy}6aluoWW@vEiKI?QC+x&88D$oi^q%beHt%s29?TSIJr^kZOtj^Zx}Z z{o@hK-=@j1rqfqCs3&O(FtF}ti!LrMZg--p+mF|KIkBqNXaY(VXY@R(&+8s-Iz3a} zy@;kv9hkGq>5DyS1Il?#I$O8OMxtGWQ}A>;Ya`pjL-~zlerIwbyT2K`AN+Pro+xoP zQ-EI(1v_e0hgLjG#j-OP2d-^%Q}eBM|MD^W@&e&ZuKdw#CIZ<I<;GVI@f{b3QA31h zMx6)d(@m(bil&XWL#N)I37kV?j<0xCiSfWZ$!5pgx(e<zzQ(2Y87-JIoE!(Jdzfji zJ&k95Oj9w8z;=!%d#`^{?q(<E1!lISB$)m?F)mixAzynM{%w)7DQHwt>4kfLaqgQT zOI)X$=9)yHIq3=NqcpVy`tKb^<`cBI>9<!9&lU~S9KDFa<!{I5s(e2ViLn4_(?R4( zk(K>cH72V1shl;S6Snylx6$FFrA*c;0>w&77U6MrVyV3vDl@S}l$UIr50j<??DAhH zuOtw}R(^UutQ!%u`E(@rD$Ue_c=1PMgA;tVTX1;flyi7X%>Nn3(exb#7sp;^<)Jq_ z0z!+PmXH@_4E#fn*Z`%ie+g$+I9(DtY~InK#<Pz6tdK>a7_aG)va>4jQtzSG1N1ZP z04|*t=gKAs95xuu2#NT5Nd8__9?V|?X>?ThTkv-fdzw#8Z<I#W4j0h*pak^!nLO8A z`kwpx3x;CLECWQAxW#}RW@vO1<)g88e$ZyNLC)UrFKbVxC~Ur23lVF}EPT1I-Cc0s zg^PIDfK(p~KW>9Am2N!;q4Q6LVrU(2H^HXO(D!f8%|tC|w4q@hnsY<w$G;KOQ*@7w zh4ccmXl3aXbp$m-;|P3|nV~>ks$H`MP<5ZuI6*s!nMZ~C`YQKbj~&RMM$TqmbH;yL zNEf%_yAREC>YW){2C-m*hg*HG)4^Xd6tN66>{SO+cR}E+7S-9mP=-Eru-TSjHCWRe z$HS~MBFCW>h?Uk5*1#Dp{W)32pZSsFeKb&v7uvEzjM0;XIRfKZ8&1!T38~H1sXpz- zMY+BrwdV>AQZlEBd}9l7S(Ka62dgTsbEll^{cGn3BfekOxq?BV-M#O+2l*OyyS<be zH+G{R+n=W1ICw1wamItf7$Sb+?j?a3_#K@bTTgPDU5(=^p-apbcolcSuw`l-N)^() zPX{?ODK>xG95a>?J1FKer#jb%o3U%C-o!6<;|QW_i5jbEOr4+9Yz;`Aq?VUXMhn-9 zwd}#KQdB4*+p6$36NK!&aZ{;xSpLL#Sw>b4cKkP4iS&P@VnFS)*(Gp8qVj0TkL_?k zb`7qscTiUi<AWo&jIO5b);uyXlwt*wV6{A6ZFX?q%jbRcg?<GU-W+XBs{RN5+W%z# zq{Au{vkhWHa&%qzchKtF=~mw6B6#%EIW_shX<&JvCC%tL_uI6KpRH}R!!Kcc(ZJ$3 z(k;}ks-$clKto#%cy$NDOdM>isnsiTSLlc<XyuA`ANk$mUskz5$0LvO!4ge+JttE8 z8?$_Beux4k*4(srq!u-XmY$?OVsr)KPAS%E5$Kb=!}$!>e5mQX5JD6@wjydYji-nl zZ~SFLruo3uH@0}d0xE}=VI7renPd)mya_QPg4muL`f-0a!S9C0RrRui2qYBd*<*DW z_5k?NLgO>BfK|$P*UbVd0vah)yL~iCRiAZ76CcBdc)!KB%IF}jr<l*NsHE8(jUIBT z4M>AH{29>Mu94Qqn;3orfb)x?D<={{cvL&|FZrUqFAg&0ZoNBm)W@?;t0<<2_PFe# z<JiAHvfDz7G`#oDY_{p}xTfhBK8%2bf=y-9LFxQ9z0UcDTwt#V{0=rqXSlw%Lj1~q zLVsMD5PpWemLTK3Bdp6j2oZwTns_$BRnYWDA@?Yk;dNZS8NG{uU&Z^yCXD^0$KQU# z&w<n9><jdfNN_phKHsSOMy)UG#{Z6zd?bkX0<P(&jT3ij0NKdcTgFyG1W$#yfW(Yr zK&3DCv+_%68Xfog;JDxjY>Qu+k&6Rg=;vtE*cznb?$!|Z_leZjPi%;Jj$y2+y>D*~ zt3yhxN`pmMH*(zKxWomY=iw>qpb}3zP%d@SD7@XDi&?JKgBD=4N4Fe~>-DN9xMYo& zZ)pSCkyTV5Yy{N%{Hi;gv;<|vN=F6UP*R|NuS8&?Jz^4de*x!@tPuV3Evh{O^nQ`( zxaEw;Fw%PMA2|$t1cG3<)Wza7?ggwMPW352+2?W7Pm`WSxsI(*uE}dky}<;9A~(43 zry^aUViP0q1L&{ZIH4hl6>b_{ftB&kOe5G;!#_OQ{x(F!DT=teln{$j`v&~pTmxgc z1xixqAeu1WV+^ZmP}ei&BIX{5a(2KYfubv<!{`ArU=}S+?B=ceNDbiSuw4ohWV?8; zrct9edwf>TihBEUo>9a9{~-g1ZRWSC+gDR~zpsP6-r;pNIf0TP;IT9NEa?$4>QQ5- z+^vC;A624Tq_BWyq+H|k(EyYOC{z<u-a@9dD|ju^L`JRFzV+hv=ZHJ$RlV3RACX+n zTm7JTZ%Cv+B}}S<%M5w5gIuaD#kf?Urj1i$Q9N6*3FX`JEHEZ?ye!XbQ+5)2k#0$= z-C>_<SuV?wVIDactU5HQY%%-_m^2Hc4_$08|NGo80}$PogD3kW5FI>@xg`f^uoOdj z6en$m-6f1(pK$`nvhnT)Q^V)H*cBZ=Yua0tX`Zh=Mpv*M0(`tbqNH8(lE_!F{Z2!U z56V(hb~dpyHbO55q<!OR-x40d8mWCkjUP?iidi=+TQ%HJcj6~)*e3$xb{Re6Bsg|S zzzZK(Yn78y+bTqg*CCb^g+F2NHu8PmRpO{IN-{g)=ReDhm8=IrmrP#jzRMVuEDksX z`nTXL<ad0^aVI`fvkS?XSBD=h7ANGvSv*?GaH4@Lt=qhrGn71C>wz$-x!QOulRU_+ ziBZZV`>+SAZs=uKq%Lx2TjHGR>?$OsN~JcNUe_a6{iW%a4rl!Y&q3Y)UKa&8nTZ5e zP`8iVJ<-?GS9Vez)!7Lrj{GkY(|^4{F@=5o9fA7i2M4JH(%-3pv<wn5Y#F|i?!p&p zmutV@F|63j4Buv@&o^9z9qR=fHTy+`UA|oen-XzugC;e2EtlFk_TAP`^y#BF^?4AI zFgGzb;j^Ss7orzGPuMGHc+h;MDrG1wsC-3RV+;KN`>z$cFunR3u!voQ*Q7erP3G`^ zK9^-IrNFNjc~`*9FW<)RB7>8)O1H{ks_gC@MHV>lDp1!b{`XVK`Z_Uee_^xjjhz7_ zkz`$eK{=(}`eB_S?T3zsfreRMDyH6$vCQha%F}!T8gJ>~$Mro5)>61(q;FFVxJa^< z$;nmKH41wAnO_y(v%6w72i&Lw!Wa~?>m`rdk#~*7Bm~Gl4!!a1l?G$DftoA|09|HU zY9WdN8gL^s<}|1U>g}I*(0rHhDP#ke>m<%IkywNM%S45sK<4Gc`mJlY);($7pT9z+ zav^&u=I2wE2J8l8G$TsDC+u8Z4=%WYN=ng<@9V)BrTA*o+>Et`+*h!&&3aN0=zu|` z!Om1&YIumaNV<?XofnW3<fIkd9I+_w4sp@2^I=`%v!31zzEjCy;M&JYus90dnvwG! zI%l0zK7`fTf0XR;l`_Wn(ZyBU$Tk#oFp0x^!DW$g(E$a*iSc+yE6@2Dan%^T$q{!| zp)`FyzpDO>JjG^oL|w*+A*#pzG|FP`R8@ISBD`O_z5~Bpnf<yn+IVO9S9rBy^dCzi zF&hEy<4|iRoyd%LY%>2IsI6XmzZ>*(b=-3+Z|Gfr@Jm*YEQ>xB`wEa8vi1_fjAcwk zbE<t6{`{#LB2uVe!vA-11ea~z#AXz@Hp%|kwU_If#_v(&<gZ=b<)tgQkms?`i_Dn2 zG~z)vtbbO!7_|RTjN@+zCDz=|l6s6RWO0Rv^{+8d`cuMU#D36NN@j=NW3T(QMX5q% z5tKumP&l))u;I|c$Uo+$Dd_6v;ElueDgAvsXuaYfaXjs^lTL93SJ|PJOUA>ow%)XA zm3Q~H>QBuh$w0cGW`zHOGCp)O`a9IJ*|fpw^=oGRU2qKi@42{iikj0CbEw^}vMk1s z`_fC(6kj)5$;GxgDh-d5X<tDvroP_`AMf=h#kH5oSQ;Mt-w#sw@y46XrxCR^o+w2J z$&Xk#nb`^od{BvE#M?(&G>P}NX9s=?!iaDzcbyDGw?c$p;^7l@$$Hxf5%k?+#}$;k z8E;4F3+p~OJAV{sTBej<PPa8w0FK@xwX3&lxP#ueUaK8kf2#O{&i{$XK$j@BH>v1x zoW!arNJo_@L-X1gf=<_@hIuz+HemG3E7RRD+WkXL+U&M=t7X+Zh&s{n$D4^<r4d}i z+u5xTP1OAKjgZJA7wALL*$IsI*I}|o`<1i$fRgobC4v5V55i=|z#oVz@AbdK_@7|@ zuibN0v)mpAT;XMmuwnVVbjL~C2Gl9IX>#xsnuobV!gJdGJ&t09OZxRwJ(b@kO&aiF z9U=uezj&7=|0@w1QX+Pd!`R7wQTTEsEWGscdM-hHFP5O>_?4t;0mzl@?lz~rc%-|* z{i`zr#x21Dn^Qx*yvHE+=VtAo$tnE=2DdJ9Zza1LXd)w9I9%+Y{jys@GLCM3kBZ|) zT!|~##`#$(YwUxH<>WHZ<mTdX?HC*nKo0HWF(VFo&r@M=_6zV-sYv4$$NWoz0|3ad zzV6${m;F0*>aoJAJz@kAo+b2bF^JvUSy>coYMVKcqE63RZqr5E&(@>xY0p{i!gAIS z*wFKaSjpje_cAhe!!JqxYIFa2DSYW)@;GgAV8Y!I)wmHNDzysODF+D1j#XuLNgWBc z%p;C~j9ytnz`kM7U;Tk2*|3Q~f3t9#*VNrqqdH!BiY!?k3&kh_RHgN;i+FLTdt6TZ z_JEi0@C^~U%j)_-nEetFY3$Sbt-t?zZr^E_aaF#dpx+~%P}O5`U3i12Zh5O;;_YFS zjqxw0`rkRYEOwCPr(@EFQ@W^e&8A-8Zr5ONs%GojFI&6b@{2PbUWOrg`Y^it($zKt zBD#;|x+elPGhny1R_u#d#wsC)(z0y{^)Y<S0ZB%yZpnHZV%eV&9&?yF4+2RPSkH8d zO^iVEzp5h9nYB6RX0$Kko9v#zD8AP@bBFT*7K?fa1Nlvg+!3IP8K%z_b~0HrX42cE zg7qzl45jftPnv}~6E)OD+2oOtNr5~uXAmv7d|!!lK_SQ30<p`ZO_CRT3SjVZ;%954 zm-FbA+#(QTPTy>6aJ45u{g0LY=x5k$r7!PwVf^b8eF^;AK<g?iVCK;$y+&GK|83)X zIZ&e(+Kp|Gj)qnrWQZ7j!P!VdIf4#%SxDT8zUIU4V0)R9RuP*r#t6@E>&k4atz;?d z!OsM{V5#r(r9uy?o1jS(mvQ@p{Ax#G!R^pNx?_3Kz$fe}LMqd${ae@JmA5>Q!|0Pd z$4zq=FeS$Tk4R8c^yqkacp4iCB>jZQMib8=e9F-1K3I8@{8e%N!GT6@aLktR;nUgQ zh5*3s#c3%vCo%8+kh3d%0$}4^fthdTO(^rG)?c*@Jt+szJEBCjz-_l;UayOF?<6Sz z3%>x@^RWM(XM0s3?9CDF%`a%5qPYB~MSKeRawXgbDt2kbG(*w4!W-1)@^nlSgB430 zJ3v*sr15_%kK!K7aFW0wiuFKU=u#pVl^9iV!3w^(w&wuYGObaARc9ioBwI05u^wH9 zYY0o~mhxA%Eg#uAV391v>Yj#Bba<Jk&w$E5vcANql9W9AB+F7>J@<?UI>eH)?T4k$ zo}xW;xM<7aK7I4fynIR!`Gr=?Y#;z!obn1$?g@85ZrddE8T$Ztu+_d&uHV?pq$Pj? zgfBLrHG637Jy%Y95PK*_hb{>?cuiCS=#k^lwzdRHagg@`Y{X7WMIn!8c{tL+EVj5S zUj>>^i{thY5mc+vS@jniMGs>j7pQqq$9sb!HOCow?gH(G`ZoUH>>kHcG-Xe^m5IF$ z)4B9vaip@t0!=%<0#8I+Z?qP45AKW%(*ybUEeX0>@AmyQ)YbL$5e$-Cpep;za8~+l zGJFCU+X~0~85QvI-whB<NK2m5T1X4Y#SoUTb^&vQUWDp1QEgtS$%gY<ebx!j9sRqd z1U~zT-4kM6C`wP5>gh>U>6+ja^xbQj9sab;gWehb*6jJRy-{{uEelPCn;M9?5OJFL zT6Q&L@=#aduUu8Av&MJZ*#4~Pm!ism`VPmxNmu8LDYy0t>UNsWubhw?5NH6rh5i9? z74;P$s;I@}+1BTxSb3j$6v!w;Pbstd5XY<jHJK>N=38~f*-yM?m(siKRidCQ<<=)o zuU+Q`^P6Y7iscw9Y{9H}p@gCy7=N7#FBhGa9^Bv=ZPGxrrs-k7)eZmT$Kgq*n7(zL z&3n`Ik$CH1Ff%_vzhB?a)qg>pzUEt)+mAZ;Lyd_INT{mOcD#Dh8wc*V^lg$}!sKAY zuZiAkAiftz?r!4|PZ=YD{#C7}+XxBvT|y6Gtp(2cQl_AzJ{guLtF}%~3SSP2aKBu- z{_OT`KX}b<8upF-*-y1ghR$M}(qY)lC&NKri2A6P>4z=jPxvN4LiN<N&QI3CKc=EO zyS-7lcZA_BRrj5C(j!J<*G^j0XVQPjOUCQTfVi^1o3ZtpSmh9(z$KJWS0DcpHHv!) z7y1JSXS8JK9_aRvZlUcFBbF|NCvl5+iWnt__}&=)SC7zGJZ>9WxK;}ZR-iD59EY_) z-EP=pW8pUwP_G~`OhWI#c=T21AB;3Z5O6(-82UKkggWSjlJe)zjZlbJrfO~UytbA% z0l~$!r&yl@BIsISuU^uTZK4djuLgHdO+S2y=JfYIHw;22j*?Rh<cuu@M%|DcLUgNF zIW80E<jX!rPcHV%e>C%Ed!w}|OIuULNxj9Q_^_7XMZ7T1eK8zHB%jW$^)B97JHUQ< z$3v2JVV}4yI=~w27o7}bpOy#b!k6>E`dr1r*EbTiTG|z>&Mx=3=Xrh9f&9}B^)I`p zgOWD2H!knCkc*7x@2>0}p(fi;f#i9NIgFLE`YCj1_W4x0hu-KF2$o4YqxT|TDtNv= zixlaCH;?;3s2e0CcLMU#YwL=OKN#@|q!`p^%aB`A3<W>aXEv17>rAH<0Se_T!vT{X z{Z$#Hc@taY83fuw%IAD6pG+T@DpeKb>{EwVy?G8gQ~|XChF_PMg|929(eL)?q;0R? z35NPq?cI_js#=|EpFIzq?tdk$g6dmWEFigEJ2m-97D1yav~;e*=KlCRsGEpq)l{Nb z@8H7-sZ^8Nh{M5cd3B)|wJCzFm_8y<7*MC^_<<eiH|-nq;?V7}7p-D?a^La8*)CCG z5)pfL+9I<r)t%>UM6F4Ahjw*<fj_T1yVd_hZ^VL1YbKgu|64=R4i;6~VLEG0N9`1K zS##2u@(3CR;kk1w39U?rNxDE|#I0(cIflw-FA2LEW(a|TD=|Uo0QBmdES5uos-KAz z7f_M+DQwk0>L^?Q>dE0Kdogz4?KYYE@d8k?ibd}6L*wyppdt)kz$J5A(2XiqvGy$w zLTPN87Ssd`S8O70V7T5WKB+3U=Uu<u3OciFEZaNjxGFH4-;fNMFeh+4-WrqMc#B$O z4IHnm&|FouAb;FFoZ8EV$5aSsc=98*Tin|{8tY$R?olE>+B>_w(S+5HFo>}x;yJCs z{)<oia}4wq(#9cqz=GS9H`Yq~uC<~)X?YzVR8_){`qWRbQc?(9vlLUfXtCq9+W!#P z@c6W!94%#kRk#)iSl}#Qe&48JxOqtdml5Gg@6+L-aDE<AQcqk{`HXrp<;wzYbvg^G zl=k+0Gx4hT8lym2>B^fV?S3UPXfnLLv>!IT<v+ZAw2)$@bz$3&Vkn#lElTje*7xl4 zD;+bG*`4OTyeWN@!gok};B+{=IXuSjfOW`BDj5P;i`f%27htjKbcsv{_hfBs%V}|u zmF&AhIFNm~8hTjgrfPQ(4G*0PT<kJAuI1k$;b@g$;ZdpA3}91WfSgdU2}GDXkOT7N z<J6$g!+G3&_*>L5;r4XZF@Y-w@;Tz~@h@^k9`BM7g&URJKBE<zF?H_YRK80x=Z&A= zj<Y6_UQ&j1(BEE{kb#4H6I3lbH=C$tP==XC!+SORA3YmweQ8z*0T?aZLwla(K04D8 zyFq{oOJ#4KVfjrgq1*MhzrWUvLCR}ONAoUGnpn`l<IQWk9CRuI9%F;5qSqTe?sWSW znk59TH|IAoI?Jtn4op~UzCQ}#yWp&gy5X7rn;E~+O6EPzWfK*&2H19AWAZ4V<eKHN z$a(5j**Gbz8>L4t+B5F~=551e#Y`{$vJSXPX3NIL#twM~t2b1klSwqJK0a@65l!Qb zMw?_dt<yySN;c<vywHHuI}QQ2?$fW@Bny_eA(KJ-s+Upf!{&W~Nda@S6I#z|Xn<a| z@&R>=p@6a6vL3o}%)%#0{EgYcp?v#n5lv)~zQ@+|#6)JpTiHw5j~>O;uL*fVtWGW3 zn+9_lHUoZ})yvu08X6f7wm`@3Z-Jxg+Gv-52nRBVcr|3Cu9k1jZ1&(bnpJReV>iM^ zCRM4TBuvjIo6xvSAY<_0r=Xbd#wQg@DZ1Aa&F$Bqu{#p600&XA8y0NN36hAP+9YlF zM>sV_XS3W!`|)?KPT%~rFV3A=wK!%t40G6>$FwV1g3IF8y#^NgJ~=2-<n8gg8Y|t# zT3LPrl+Dk&(Gl1AL?hS5-kN~QR6sAg+D&JTr?M0GcoV(#qW-o-)ZWkf*J4o^9dUvi zC&aN?;377m7)Q`%yIhsbJF$Vq*<m_zRe5a)+`ri?5ZpV97g+iNcX(<D!CBPd%_XvX z^Bmfp*4gcH<^3yRjSZ75eEyPcZE{G?+*iCJ?sp;<%PP}L^}2L2k5f@KA;!i!ZO-86 z&!*P{Zj+Ysvmv6tQwFPmj=ZF(t`?UVLl)^IAdn5S^CGc_w#n3BQ<^}HdFKMt`gvuP zRPFWJ&u%y7D1)!Y^iJRwJVEWLIf18Fsj6>Z&T6co`OoeQYOEwKTZ}#6Xm09mis|li zsXNub!N+-`<9r>Ez=4W#dOQe7^7XhgA`h4w)IdlhA|qfb8K&2*eTV+zLZn@WyD<qa zH>vzo3U7w$QX^{zhm$zSo!Y~Cm4QjU$jm6@v2Wg4u<HPySkziayNC$Pblf8ajA&yp zP&;}u)eSmmY;F4aME>HkI$7Lgm%=a@1?m<n*sje2W9waqqDs+Fs`l4Ev>mdu0S49@ zi`Ky5eD4_XD?wcCQ1nwuG~H%1#OcCv>$0>-?bS^MUdJaCGxtk(-Alo6ud^G~F2M?B zHw+Q2vNYhjfq#zPezcXiEua&?P;b1=Eaz^oc79Zf^_70X)<Zj;q`ySKwt*v!(&UoR zQRh(DiNO4C#{7n!BJ<33dg3t9`sD?swCk(?u!!pD=8!5^hx0&5&Z8c!Ur8s|>INu# ziPb(6zbze~O&cjJ%Z4{10opFQOxpjM&lFb#IkTurS&1`WpWD#N>CoYK8|iGj*oR$F zK-{6RHYWFIb4Gu(^J$~KP}sOQKHoT8&?OhBgWIgOwj&z)*f>{4OBG5fa@dsBuaXa> z8Me#mUq*H_7!)q=NjI2&WN@iOOmE{+x2L0o2yGl?)swSNMIBR3ktuH87TZ%p+tC6` z7Eo%j)IyxtT#YYajY?ihu?bTrDyg#VCqdROBhfD>4&!hMUE*G{MM_0<4P91m+KQI= zV{^7SIm16X55z7`T8<oF(OG|lbZ%wc=+&#{<fw!jxslN7{OWG7uDz<B>~o-N)pOr6 zbX$3UtzETVRJ*ScuBd9cOuFq~)JbN@JP$l$CZcf}zZg#`S>p<-!`I!vU5dZFly5h! zQ1<Vep7>ev*5*}!R^H;|)00Tp9ncHsG**6Ba#9O;Ku%|70KJs7+J1tCL*2kQt=|kh zio>(XEUyjz@4*-Nl>1K!^{*BGXB~Ad8BYvv=xy9V!OrbToekV9Df8)_#%nkW5w@RN z$ZHqAs#V&63!v4AbE*H+5&D;CKkQBLQfNLU^>$9=cd;L095_GLEn~sHzb)~xY`Aa% zMozY}XK$alR+^5+xlXR$JAFERtb6Woh%m#Aetm%#vub0%9UDleCw<6_3|^hcY%nc* z4drt%k(8v3@)s*Vrb<|iI=cDH>0t3!wuK8rco?inX0F|JDFS?tCTSc&rEJalbf)@G zs?VCbko0ZR=~FK#+tYG{M(FuuJeQO<()(LG5RHl0Dss}*w3!#BYe&h>SCB<w`rXAr zoGeM<F*K$Q5|bE}bXk?fh`jD~eSa(wNgX{Yd-<C>7W1nw+f%L?$o4N8eZGDJyi^cA z%Rh=AzWLLY?|&ws^5EMXrXE*m0oRf#)5z$}WHM&CSyurW`3Vdu<>!*L!ib3*ThfH* zb$Dkjy-EZDDLx0}PG+PNsDWYU!p?TE_OZ$lmSt?!SyhSaa-a`Rd(+#bC9CXeQ3dj@ zyfnrQPmLFA4q#fNFLClyaU+?U_E{Ilnuol|b{-^TZnkUIeLf=NiZNC*C1jfs3j2u_ zy89096N~ML$cPL&GoH&>CQJHO+Bsi9O;lFMSpMSZ&t+VQx$ptInSd!Bx+O{;JI&al z)8n7c$sXynY8O`ew10KFA|G=dYd1^BB%Ns-4eRd$&o*v&u{3m68<DD}M-IG}&$LP6 zU~gytB%^VdiIrvUty20SS5enid6F`aj8Q3M!dR<WzL_`Nj!G?lcWb_Vhz?0s7RR_U zMO2oo(&wShH2Q1ze_KRCJQVd(&1KDrmDgD>TiQ4w4k_7LBn`7-<sJ6bsBWsAG8SO+ zF|Q8CIojv|yfqmdvYCd+slhce^34z@<<h;>ugiWr${`7~%o=j;2CEV(GEpMJ)ES5> zdeM^EVr;!@U3F`>ohO^!S}Zp7zddIfZU)wBWQ9oq_mvnP1G9{qS?XN;1yqapqUP0# zjjFNPF+5&4ViaLwaXjrJs;rwA6NSQkNOs`yah0!x57^KVtE`o$;9)7XncbivlXM)D zDw1}a>ZCC4z3KMuy<S$?sA@wv@hJK6)|bZ3mfV}y#KFWdqc(PxlI)V66%)Nh9oi6L zt#C5fW^lFO^>y;pB_Z?V+Be_R+4&IKVyV6PoK&sv#HnK_qOH$ftE9-97p7zEuyLip zJB0^hFax4d6--e)-Y3#fTyl~R`t8Dwa7I7pRxkN?Yh8XG;Jc0+&Qlnbh)PV)9~qi= zp^i`zD2X2^T%7+jUH5A8vnf~j)dC<~&P_x~A7g~;`}c)<zT8k0fK)V!I{gc3zGo1u zU_QXC_4tWoCj4*R1&MZL2<la`ZG+aCfmWv^OE5C=W8*dX!`)e^iZj?x-C^L9o&TzM z;2CwDn(gE<el@@V{0qmWu9D`E{^?3M1yvgd%e*l~48I##&j=tew}_)m7K4mq6$w>Y z8?MfNYW8vH?R6AbhkN_ZVTdnR5^O=l)|Wrm2e&o*a@?YD4`k%w=>iW2jMcpq?W*S^ z>5eTjqizf@hNP}WZ$gORoY<C}7IxuXIyPFF2sbR%S}#=_CQkbP88zCN)Sltl*{h`x z<D-ycL3QPZJ(<HW7x>OUs?b}uO`j60%_4`Cz>vP9kCV5HnSijC*2LbsQFU$A4k#Zd z{8hXJ5~K60WoKe)t*Cgp;#7sKvLH}&9Pfq5>*{;CgnAq}sqqaC#_D&<Lzn~V*T(p- z6k>ICgJvu6$XVkhN<78Ej!HyTyjy(D@2?|LD_qB$#LbQ_F=$n8i0ey3wv-#iZHU&< z%g#@KKGYKrK|rlW(Lyia$~CCiM=9j<>HCE|zaeOMpn2A-{G^2abfoOJAas?stxshh zY~bNwLQbcyayqH1N2YFh*>H`HZ)hue4;Hy3=>+@IEZXCQlQ<6{XYC2Z+I?^`L3K&d z28o`oUar(J--Va9&SUKa*E1D9LAvx=cWs%yY8!$)kfR3~h&Jlbe;>wAWaZFr5D?MG zGwbtPRM=`6#SJnrMcIz;jF(3iV{xXSBWZ*gP;c6c)~q4$gjw>lw+p3!<7`JhiCcSD z^urU+58E`0I&@c)g{4R9UJIK-!dun(q2SKPGT<YTIx{R1a(%2a&7SX+?2||QpZt;W zYe<)>7Fpw|HrQ*kdHpVkZ&LkaHq_>*@m%Qi^^72Vst?0jJyPte_JQLaUv@1Q!9k+2 z<tCF!yWx)_wL`k(r^s82Nh=PMhBTef@~>Waf<H%d8Hx~3-Hf``+yXL|4VmBB!-$zT zWL++i^Rj;Se8!ycU!3i~1YIN89sN}vkEqkxe_vz>auL!?CbhD0;L{QLBkVzP_F1^( z3-)B9t7Aag$~Wnq7<X=~M+d{wyc)ruO}$j=%8wVu(5G<<pN@%VUgpXthDJ`k-rmOS zRNG6!HkWMo`)n2rr`gA_uKSLg+n;Ue)zev<WKcuq4o@B}R9H{jET3<=IL7a(?`o+q zcP3;}+4KOO-0{9`3z2Vm!4>mrtXBywt{`gZ4Al@{DV=W%&r+xck-=Sem>G=D2>Z}7 zY1o%2VUVnjm2b8q-^DKm){Vhn?e=1Ql+@2u7u*l1%nKGlRA$xYB$E$8s@Fe-!`&?l z*U_e*%o^{|1NI8BY*l)Qt8cHJB-L4zAbYY?jy~qhf(p}c*11;b=o8^Dt&(s-a!l#l zw3h@*?BG@P6E-BGuxe}c_!?U+>G<!x*&`4rp6H(0+hauZ5bR)DnAD0HYp=eAOK?@} z3_F}(+T=B3*LAVXSdBNIFAe<`=KxQ>MFnmiFd3B|K0NCCox0)vhxEh<r&3Q?iwtP{ z)Fz%?0nD7m1&m1y6}!lvrm=<m_T3nVrtf!ZXB6B52Yz(gMF^4AiKmR#4c3Y$Cb(hl zPAi=wzmXk+5ZELwq@Jm8C9gXLzvpb8o60bWFLjD}YN<Yi{ehNb8!$3G4ia~0i`KiD zeLjD%9QDWT(xF)SEB6lkdX*)A&spM$xqI+H#p4+x^dO^>ZaAC`$P+nY<L+J>#O$u( zM%y(l`~YQJk{N5O(RK9;Xe0S6vw7kZ>&YYI;)gR+pT<)pzfI{|m+N~Qbt7fT03#4v z@Pq@eCO%>^4b#AlU`sOzD?J{jj`CpsW}h_>99Yoe*H%nDMTDOlDr}6x!2_flnRJ{q zeDkY^1a39!ZW0A^Qmfv16qKjd!bmtFTL0nJMZN6GQos04twVy{t*5QQk#k|QGCsyv zFzp<+|H-x~RJ?A_V@xpV&@*NCmq*FJyD`H$V-$xMayzp3I)GUD<mKO<`r&EpOEk25 zT^W0*0D}L+eyw1Tj)=UhgOVC8?AfR&Udr2i=Q{_vyEH>@LcSF!g;h6>|2ZsP(Bi{r z(nEL0eD}vV>2qKH1=rOd2!4Zk1v_<j7hL~qR9?J^L!f4pQ;t9GWhg*VGRgvGpz<u~ zrAZ;wtTE=A6E_U7Lve6`E-)arHT6CuI#J%G$UD5;_L<kLJhXju4J!z6cM5_Jv(%Dw z$uVYZm#DW7kYeFV@%G0nWh7`{9O%{C%L&a5GFTbTE2$WxbMO7k4mId=5!K+et3m&| zOgs&)t<dU^c?*{tA?8obDq#9gspp-eq5iEhtcG^?q}%R3)F-C>5nZMvC9(A4n=FUj z*jWH5Vu&A1mi(W)YmoQF&vyj<a}pKnH-^Wai1cl<XV5N?UBXyx`+C#N)^Y)m@E4eD z;R?wq%No7Y2T_#acg!A6ZP2RsZIX122Zh!&gRuSg_!6rwMwoC!Ykjr*qW6`>2Lt6S zHw~oxrkwfx_XRlQyOg@``gV@1t>>LJCm1LsqA@8fPB>;M=khzp9{X@z5OpDv?C}n! z7L5<*&39@(A|8Dv7rwGXGO(WpdLEtZ6UWt4+6BEl{`4*YL$R$uj+~gXVn;M1y!RT% za58iFbPH*<AOyc4@mzRLoGR^{9!SKFJ14&HQEs;NUz8{IK7l6d0^7P|k*RNr6V2Vi zb|mRvp?5Xb@RJJGBri=hi8ZAQHXt|5n6kW5<s_Zf6&yAmPQc;hA4wLEX;r#gsOM8= zC*A5-cIJ4cidFh*5MEEago+2d3*s~Z)l^)qG0Bofw3fINH&#ricQvjPthKXU_a5vM zX$gONP9<<NTJGq696>(g-kIKAlaFc8=LW-Gv-09Y=U2T6{cr%S>?9jE8U`k26OY=H zaGk0ub>f}`mm<Z0CpX6s(^WFsZ8cbbA#D0S$tqQ~>k4O3{Pr>hbq{Mz=$<;K?xRVU zo?2_^rP6&0gEgXj2+rxM97C~>`e5z~i4myo_1FPgx>Jnz`0;u!<as1<Ovak)i)ckv z#<0jdHh6?9WA?ehCYc$WL;KL*BrS+NU~HFSRo#Z`jh|;}WoYHB7)T~q(#~iOPp}+8 z-aLoAwnKWx8_~Rxt}{1rx>WgPg9d;S_rmRS<&K8hm910HZ@*r!(|DuX=M`k*TvSvH z9&psYZltz6cebC6N$JYU&BXBm*SGz2d)9mPgwE@fv(hHkm(ADjX82gsd2L5hcTH5< z)3N&)?LPnMlhM;jz#TxVU8zj3#IEoPRs+6qC49ot_zMmbYrQ~=3d7Wm%d^`?f{~L3 zGI{=CcQ;0Hc4>q*WH3>XjFm$+j!Y!R6;5J<i0YSAstyyaa5<e_U}>_kc)OQwnB+LS z7#n}oIGV4J@#*HK0}J_2J<odqgL<M%D;`rh9B;#THBzzc;%5Us7%dSq>Sv>0%&B&M z2Ue9`ZS)$Z%WpC3b@Y9og0m>6-W)ekLn&V^)I6mqc`s)PC_{?sFYs5kj*U-lWUGeD zZ_azqI+c_X0*UZl1y#;a;6ZWdc8*&be-*xb^M4TwTFcNX18E2%W}9IP0EK>=I;nIk zzkOOk5V4t((hqtLLQaLiW6cl4?6Ed^2quY0RA<Ly3QD#fT@5shJ4$$BJYO6yD=9wZ zt9vPS-9`8-KB)&(VE8(SzDN<v%RYP{7wVVdpNl%qTr92YpDP94U2AWU3<2bM-+3B- zU5(Hnubz}_b}X(Fm{r=iEL|V3aC`FIZS6x(-N>PVLTR64c}cdMsn^u0*~DJ0R&PBB zRIwddy<~f<`ip$0)AoTV^qg<?rzprnOo`|-7m1$Oj8I;l*q<pNy>!ch_%<azgXY!v zxo^-Mh$azjeJ_vJ0n3<L@OYqZq5b&1shqkBcok25{Lovmd~cvQ)~Lt8pL|6`m9{&b zSZm+w=~hqD*_^d}{iK-m+!#DsN4>S5Kb1?K<=4*gTTDGQ!R1J&4P_<Hn3~>F_U;Q` z{nDgk#YdBEQ!CAUJ=^H#GGvMW<{D((QC6&p*LWUhEdqKoEB}K(>Xw?r*i}VUi4@H( z*NN7j@gTSbZ_I$?d!wf4ZjdH+SDWk!yu{1$VkVbmmv%f!zFVgNwOq+dy<76v(`wMA zCKzm*t2bN-gOk4seAP@7H0%kuVR264;1H$QpxON$t0H)zHl4$g#v;B*datDN3&Nn) zLxvKw4Fz-T`%eqvtq}H%2<3CL3dLaRy8-($r#4X@e|0#8ck-eyZe2^e&n;vH6a`{Y z<_Ibh%#O)$!?Dn=5>lTvqw~s7Jmf3#DkVPNC$_9DZ6Y&E?mpe@o1Qe28RrS^rBYNd z+tn%!nGxD#IXyyrR0Xau1XKz*b4W6pa8wbv9UHfo@fQ?p$EFik`+%<tWMy^Sz~==q zAnc*nIs^U>k1H6I{}>q|f7<ng$iBM4o6`dz&#x|4woW*Dz7tl9U9eDk3%Mg`-;Ju{ z`4Z@!0R%z#;E*ke7E?6S9mDk{G-$x|?WC<BSh+jth8K&b-$NujX=Tu?kh9LxwmJl6 zWC9SQgN&%`F$6To&m`HN)vHHEJ~u?1TS|T!DZIN7P!Jl89LXHC=*NM7KXi|u6t_l& z!7$@UZOHeot41T?N-`D+?zOD2!!+ZEO}f*{g9`RWooijp(jZ`C-CXLOiPKl9u>5&L z;3+S#seG=7ubT(J#|%g;5mBi8D2Jc{aaW+}W&S3p?a!y>i_68K2<I-Q9|R85;YhNw zC=VNBDYzT0O-8^!;KM+&g_e<WuhD0XvCGfk?MOQ_{Y0wy!Vgv<e!xhHzScTOWqIz4 zOg|>D2NNXd%vjlD1%4POIbbHz0j`8dOhsytHbA9|aUESqP$#&dZnR%)6X6eETy{^> zaC%$zIp)FA4ihAKw;`zaS)Cj4KNx$<s7RJ&Z5VeQ+y-}dcXt`w-QC?`a0VD`aCd05 zad#cueQ<Y&kA3gC``)$BdDr^tM^|-rWK~5}Mr3qlL_AsF60JKzdfaRVp*|**(oE8N zn-z<L&~t{n#(=M8S+XQISU=NLVUetgaWs!L=1Z<~V&k6EzE~77{OX@J9uVinK4fGV zk(}$INEwOk2{TDwc~kx&l62gm$Z1;CiB%Td{fdw+NT=*8zca6$shg>LFI-nm#5V>R zjBZCF&tUk>6f8X>wO<atkQ}*@E_Q{8M&*!${ObG+k;W7mT-oqDCO6yuHn(gICR`mc ztfc_e_oQ$I8LI{_qyo`3*cNHycKgIlaTZ|Lan}zl^wD@%wwGh;+iK_B9Tw;(&n9~p zW3&rh9*yyUU>FKLPwCHEdC1N_^AmIljAQG2TJaGN@^O&T=I2I0Z+4w4M#VZ8^Fxm% zUu$eZI-e^Zb%ddvO<=swfIJ))g>Hp6bq{>QUL$^n0{G-RSLLMSOwdp2*UHAdT=;MK zrzHR1n9ToU^?}6i$c-C7yz*Shz?vK3M)>71df&3m9;}VV{(O|=uHux}Ne}}9)10az z?)Ph=vU?wkIUMqoKT*0jYkH=|wA>oXovbO0G*U#bzrK({9?zpcZC!2!<l8O@8~Uqe zshPm0Ckm%F7YEL*EpK88Mo%J@O+a6NuGuNzg+P9Z*1@aZ^IAl2uN*#Vs>s8Kd}0{x z)0WW01mbBzqhdocD3=PMoP*|9DI4l0p3R3Qpj6|{?{|BubIfp@&_(E2S8*~T6U}p; zx6@>JyL8Z?nb_P}?M~Hr52h{pl3+2SBiu=3@aN}328Jyr?!0DNJBsvV1|XWARPOwk ztnW1=_%Wa>xqhRWMFSaKst-ZG2N!X*f~r8WpC8u}0G?vTb<!=S%Ap(=qh{%l(UF8m zEBeBV-3mtUd?5rH!VLbTJ3vWw3;9@FCQ3>mB}Kw0HYWBeujwR05OO-dgZPx_E!L5= zNN1(Xekn`%?b(g}G@%aehf)ukAd#}iLI|?b;GUl$Ocri#$-NvlKc~-0t_c|>oqB36 zXBbQcNp3hhq|UI4PFRV`lDAr@w5wBhH@OUYXfm2G!;$WcJXCBIRkkabFWDqrQG<<D zCHC02&bJIA26Q4wNoKAF1d_?q!A5Ui?GOq_l`79;l)UU)Da~>*t0S1I;GQmqAOhKO zA*2KGNjHTr0zETsI1SrIAV@CAYrb(V?fqG!f28QDe`^X-9if^E5QahTf(-rAmS8Rs zI4Chz8sY|6rn&v>eYuj>p$idZzgbqw(uARk*?hzvn#Ut+V8FJuyKQ>J;G^jtm`1qH zl|=SYKX~mHF`*-R#L^zo43-WWJ{oQ=7ODR_qp2;Y*hiv#N<9-CYfDxgPHx4gz=jzL z+1%RY!9X=1`Ru7DGiW1_kr>iPPmEy8Mo=BSAzP@VHW`6TWUKJ3Kca=5da_tU33<ya z?D<7ma}DC8NZwauQR%A&3gE<1cFBz6tXRI8V#0;zx+t_h_o_$DB=Q8$Jp}oj652A$ zA*hYq;QJoT)T553L3~>hrrs&<V%w3+-ha+Didn@WYGmd4b99y_^YHQ(bV}MfX^GKH zf|q4<NNqw)TvEoWnBgCKP=ID};vea%_brEn%?7?)RmZMb4zldf6@^HnxDK(JY-~1t z%)vupp}iToelQ{XeQt6Wu#!R}sGAimqo}k@O=HJ*ydXZzekM#HyEOu~Iay&d^Ig6V zAu-mMuOCeacyn*oL@t^~HJtVw2CXgjc5mOmnLUQ-*5pz*!ZSN7Df~tKF=Mg;R*+&g zO60VCvMK%*PFz&|#hY}Cg^Cx5F&ak9=pO*5q(S6bBMUHTk{&mVP8>)WC!QhC0>W)@ zX=X@rcFHxmxE6uTUNf(U8nT!_6F-ad6A~3=C_DMd1?v*Jf8sc`+aur&r~5Lc0e!E- z!w=vreeuI`h;RE`?KlX8iOh$zHtX<``lv}^`O-}Ce;G#<Q1~MVPG`$6n$*VWp-a4~ z|AhFa`priP+0jxsDwsWGS8CWs!OZGUf27bCEzTXmnaL@579BT!k$4I@#0E_&F3t<9 zgEGx;XBe4prp_#FIL%@cWL|6u`vpf$BEMB}-Hnfr-!V&FPbiJhJ#w8?*ULqV0F(O? zi5K2LBO5$c_k8=N`bzr6P=fmKZrzv^RlucG2F;qo3(O&)lLA11aYw4<>S>P6pwSn$ zk)@UVqg*Lzd=?0aboodK!mb9bNG;3td(|ZuOM}qlbV)BU=l@|=IfwYHaay59y>@`E z1mCQj1WZvv5Z{0q@&Q)cfrG?&c^r71RaJ?7iKv+0PUv%uLU&q(M|;jTK!)^`Ce8M^ zHQkl<RN)PY2q*<EanmmW{>2^clk_0l;*fFVsu@9kk&~<zsI4$iy|O=AF(Qpy|M=?B z2TNw94PURp;m#6<=OogGlG`4h2Gh<zf!F`hgDAg@uU?6vl56`x%EXQJ2qQ0B2G^&o z2a$S8Y73e$mZ#Tp!gPRPE=jj4=99M7J*??UiA^@m_hqdJ{JRSl(TnB&OyrLrCrI=g zs?^7N>sCj%6$0~L?>XW0!Bisf#_3?o$U#xC6ijenG{(hRp>m7;D?~8#Lpzf)9j-Ap z_;N<KD>Vaa0|6s;Lm68!eV{>;T{pn)lPZB4njjNGt?|i|4xfje&jc$T1<+zR=#<2} z+?!>KdOr9kK$p-GnThGELL{)*_r+&RAf7vNw^@NF2ZmSYcep?1OoNVmX-XH4%_BNa z4iF99H`0xWS<%7F*6z!m?_y!35fOsVy$ay;%=kx1=JZJ-%i!siKAB%hTChqKtSG}p z@U(fawY7i{XqJlQ;!hr4cb*ABZZqBLBKkuS_%{+O`M9m4FC>d*BL*QXh9<c8B>v8g za6lAbLk#X+L#&H`w`OzNuK;oXuGN^AFyDjVH=4adRA#GRoae?0*9zR*!fX{3X-$A1 zab?Tpo_IIVkb(&SsaOR%ji%}ZcY^ga1*MGQb<?N^-xFER#t7BYPL3s{;9=cDJVfjA z7+$cgPOO6u0u}P^jy!lpjzg(I{cqdep^ov>%ozXKM|G-r%x{+TE%U*Jr~Zm{p*Kf= zBfbIguhO5N$Xn}!7=s7<&aAA_s7kpk<~pVE#xTpgad1meuVD0sq~UGfAi>3di>pJb zfM2nGR-mag<$?@mQ@|@}oGrFH6@OTFolO5AtFhMHgwe}XtYh%18IQN{<RTl`#HT6x zc||iu1rShLod52&P_3Y^B!PDpvmhzRJEMNm>KhgPzMWq;w7N@Ae{BmVs6e^rf<1kI zd3h9yAW!J9Ofg!4kKZAXwWGoO9sAjQ-`2X|MzKWH)~0m_ZIzX=1r{1hi~Yvd+~UH= z)U<uYAVHpO%qVTSW^24|lA^;GulchaR!y-zN9W4kimp_(Lbkk7y<3n~<+8t)%G#>4 zVR1E#ZOsO){!hHl{=GU`zmuKgg_Q#_z?7^ySV!hF51l%6%cY&}VT@jybrTi?Dxy#0 zHO+%w(^KRX-1CD^MUK^go<Jq4!%X5k+Z(rEnM3iD1NL!b!uEPTA#X1{!}o6Vrzgg1 z)k_`C;D;mZrPh4dN<@dn<ojb}v?B931_GA1Xjnhrk?0Q&a~ZXzJ6A5s-j-=CDc76! z__rdbzU9y};SO=;dS7)5J2#>1Y-^t6Zv%7(y-D(oqT%X&);I4p-{gf$b$CtcQi~CX zXYH>9H?%Ywyc0zWh7)yG<C?3Z*2=SO<@uJDh*v9b%7xWIbrKdbzFd1A&AdX%)rO>1 zbuk{iyS_rTmWh8O__|*<MS0Pqk@Z$S6kWJq2h}paFa6~Vm(`XPvtCf)mVb5(_F_RF zscH7G3*B`w>t+g|p28bT#3Q_yew_e)uPUukt!uTfQZbzk6=zL6Mvptm(@uD9R>@H& zEvXYJMv@>!_T`^DhYH@~R_}mz#C5%#p3%O_QFN3W*<XzdD3%&FCK0N+3p1@jEFCHk zq~Oz_1U>e5G#eU>X9Gg!=2iTOXXd;C99ar-i4~Ylaqi!Lzw{#rph)Wko^VJcYdUj% zLJ(&q*PvJoGA<=aOHeicz^&C@pu$7L2RF{ggFKRrdCLuS?@)>xryjbDl0};fy#I6N z$>X5FB-vt+(w}e#iz^sn*V^GO-AU+cnC)?orO{S+JYdt!+8tN9iM>7yuBYduzD;Fb z*|fk6_C?<d0F#z(a4VCoq`K(~q40#MaQ~DM4>ue{qTyB5rIV{mC-28{-R<}F@QiEM z31qIN@L`O)c&I3M1G8<UdP1WWak3VR;bbf^#WS;b8^a~^28>2l2HSGXlQdx@uGs}* zOG~e;HWP=a2B~D8&|#%USko&#zx{Ew!4oe6d*f7vnKRR0U@x}RVQc*O>w?mTyl(eN z^oqx2Fg@ZWf?!T+jF|pd=B&$)z!s;MfJzP)#HWaMAD9S%gL;qI$%gkkOhow2%&KQ8 zhV;6S`yvZ8zX<_f0Ax}l`IW|5ID|(W9_G)kEYu4(U=n>=2h#WCg7~<GNOz9R0(WlY z50_!+<LqYuJcBl0p(qOO1f%sEJ~9g_@rPXPEJNnukO@%qf!xM^*R93=KaPX^yw;od zJKoeFf3zC{BlFYs`66A02%atTt;$B%PRRI5HgUB#x$<K>nIJ(uViZ#~6LVM>6g@Lb zlFN4iV%m@aCEq{eegp2RbhUZ`ki;1sDyUaY)mLMx<w#nfTunw0c>yBC)pNH{eT(J2 zdk~1gvzE;ETu<qEP6LXr*`s+jQQHDKgmxMD4`&%tH1!oUNrRFmpY|hui60w2ZxTmB z4z2`S=IAjsmyOhdKSFqZ9ceGs1=T>KPLGl7943%@#O9rI-HuFZkKIy-ML>CBo$U%* zFlk{(eB~1`i}Zbb{s~TZ`1W>d`#eNrWZWIYlBCC67chzVjkVW%TgImP3mfW7F!}Jj zi>Ex&NFSKakBuoFvX#_RNz0}}t@6umIMzT~MM{1<Q>nDEbSR|yeGj}bGmU`sO%bqI zJ@|dxnvf{3RBG#H91VRFuxt+l`jpKZhLjMujgnud&yrkAZRaLaE1(9D4UqOt+$Zvx z=EDikNR#D~9U2m<TbY=8LtM1htXbOQj3Fd)Xuf4QSU}@F#ilKriHZYu^vAjsWe4#- zyv}UQkixIF@jZdgIghM)qGNbA@8jr@jADNBoccGuV!*sQ*z0#=QG@UtNTp{auIw7i z-!J^QxB4s0znFLV%SYWa;`5wDRT+x`1!YN~+Y@5^(M3BO=IA>e<HJF%a*Y4ULXb== ztvA2#$~tcIUd4FeIhIw2vGMa{P=xczr2Vq#8fWLU3%bm5pX3>vP(uwfe-f%tp=k<Z z!GnT}Wb`&zju4>P>~wQFI=^pC?;sK83SP(VmK&Jn)#R)}kf9FLn6030tpZsemLTKb zFlB9&6T46{o%e?$zMk)lp~jw$BQW5v-&y)Wezc%<&ZTZ5<+h(+{mYk4c(F$D_$v%Z ze7RQQ!+<q}r(%Wwg8*{X^i%EGcC(q6NnX#@leW*f6v;F{05(Y@U1X7evtx#l@^;d# zZdsmhXdTy};YDM0&*CeB^F<E0GcxEKVI>5H&6Q7pbc--uF_iIIJ*M~cwfu0B2=29V zduhER+v_f8#<)|wQAGxhPWYP<ZP~9zoU@zAd6d8m`nn>Gk#TD5F2AbP`qqNlq4Pd? zU!9x!*h*?Y#^2T)*CsuL@qIun_20o)2wKN(1&%)(4rQgAv`Gi%ukKB&;@bl!_kcZH zP73kK2l7f7&aOr0^O!MUtd~G_EuVL2|MErlb;<e3TtXrV@NGe!8J>dGLGIby)kDN$ z%em(c_c?EZ!N33xZPlbmi6>~Ii|hC%KAD~93G5*fZ=`rP1c!JAHllws|NmtRIvNF* z@qJmI^>IdUDX>a^tfXZGB^N8KF))ujmfQ~Buh8BUZ}f@huj&>u=7rGyVNQga<YIsO z{h~}7MJOrL-n5|qvjTD`;V{9jgC}?8!9h>AwJm-#xckUX*Z3Cr>+Tf8s&Nyjm>R-N z7Y$baEHiJGLl99gb-)63Dw!OwPaYSvcc)V!P)=NE!FJubsqX$W*`Xo|ncC2PZv7=H zr|GM=zCY|+jU8NCd}Wv3bL1R`@mN&NXo)SM!rpTOW;e9Pt9!kVa(jl?n$ZW5R@K!C z974xM%orA<BaUBrORIUwlM%sTiBus;_RW;#cbCg)c`bt4Sct~b3@RIW)oNB%(q^Jn zrQpUat+)k|>_64o%PXR>bu^TgdkyrOd4XrkF!9%9-)C;({xl*61<!+|VI3e|62-1) z+OPwH)Wd17F4oAJs<@G-&yyeGn{tAJ&g#yiha{-(mN8?h7WxhRoFSf{oA=+l)Zsu) zfGh7+>;h{;sE%6@WxHx~!5dIIVWN2-Q$9soO}l!+$o258PVrFZskU^fRmhSkJIZz} zt-l*6SHH6{^%6plF~`YETyqN$)<|mob2k5%Y5y>=*0i?6Pi369mrE~@QQ_polN5AM z%{?Hbcn<&NbSBL(Z6Rmb)UP7>dUp3mR$4u@QlrJ()w33-Siz$k13k{x-W%vzHnqfs zEh{U*fBa{c-;+)6_?zEw3d7wNNgPhmJ##qJ)C2&HuDruqoRNSwrOXap{j-!A1<i}z zQklLYGxC+Em2GeJQqx{lglvqtG$N!l?WOk&Tt=uK-aRDXJ4%kVLc7&D#BL|Tcc!N@ zkj5d$CsI@6&#XLA+LqtzxHN+nIF#&&zXhw`-Bu>3wx8;MCz5*iQmx39wUsR3)wb{y zp{k-n<6^0+A2Rnk4Vru-?L0LE@}mcgIZfCYE|M}g&vI?N`}ZupF(r$vUMgeDdh(KW zk;33=+WRCBAa)|s2gy@fc@0i;XTWxRm$`N4QWJGf&=X1RyhOa1ayVuMWjfX#nd6)V z*JfCTb1i1Z!%?1^7l8}MER=wNa?cG|iOAVOL88LIgw_u07T9P%TXcj82rCIYcjZuH zU@VZ=@jCgf3yd2YYiwSS>?9gD_h!9nBuqOgCg`mR+s`Y=(S%+(h_2b7IraW@9aSP| zvsm5pifkG{Re_3QQ}#Va?1awU;6t%vAuTP8+adBieh}~SL?^QoJtcO%MPq_fR)WtC zwCKwPXMLXDEO7@6?s>A)l&il>A8X(LH4ZNFKRy#V{)$l)wqN5y5r^c$O9Zt(LGw!J zfKHO<OM)K<0Vg|=`|)i&(z(J&Sw*%gf&}lCZtOk)*04qAw?+cGv{p`$5z+rbMwAGV zHE(4?fR{axc6R;DC^UUuZ+o1I9*k7?$SB?4)HtSkb=5s+m?Wc`{Js?u|3N^(5(ymx zc7f~!L!KOYM*^jCu4w}1jQCg=SA|}vg^js&R7gY*_&u7S;x^HH*&5u?EfQ}^sJ7V} zWs)47Wg_+FyIIO$AY}T}*5tvl%vlwn>}emgdETU*+7y{C-lF+53;NL!?Tjbv=-0ws zPQ{8K*whnb($)}|bD?Uhld`4VhJU`ge!0mwPjR&p<$_W(i*m7xDP;?cwT;FoQOmDQ zUn4QYR@=?3b8XM>s0@81rQFmElyzu^`6E#;QML!Dt9O&P(Tm)0?$5v3E9GH}*41N| zIf_+7(IB5UGOl`4YA2l`-kj)AX_Xd{BACeS_85@-rUaN%&N0Hquod~1B7&8>C`f8a z8m+@~q-$015nO9F&lv=NiKTv4_^{d9po89FpY`Ius1^MW9QAghIq>~{FL0Op*T;$8 z%#Nq!1a90uu(<>O#IFV6w?gw3M|?0WOTFK;Vsw6&krw~q>z4w3piz3@!@HhqJNHE_ z(%06TzY_~r7CtU#powWCXx0d7&1a4&chHmXX!EXzs6VB^!|?wx{uNd5R#8Q8vuybR z_cfxu{5lrD8NtnQbN(o=5u-IxEMv0T|3oLEZn{~0mUhg?&EmyW#-=^ff%`$d=D4n9 zmgkz6(^~j}Kl*1Oc?J*igq!?%r?hq1NwOtjnYbb98G5olj{yC#p7Dspd|`v^IoL5# zGOy|P)eg<vn;$hB3N^sJ73n+o;V=I{)DVF=ihTCIa{`DjoK8%|VdK{4^neSr-p%0= zQ*XDRDSN=q+?j8uD3o<AF2v~(DR-DbGf-GK&FhClMnoKUD!@&%tIH6>{bnlHupSo> zHBppRS5eqh(rr_b<e+)|odeA1E1ERqgjTe?MZ}g+kyP6p`gl84*)?WjEC8)@5;it7 z;GN+x%~BhkiF<=3E0R^Fys$CfETJe;dm5XxSbV**NSY&2a`)$yU^jDguRG3hzB>>A zTAdMG4^H6?KQCXYSgA?<UVF25H7mg&g%$;gd3oXR5cmha(<iPw-!qgBDi*@&Qhoo) zXcE7q88x|)Z<|{s-^7ozlJ;exG7*BjYf}wRM8x&}n%SrI#W63)d=Nn#2{j8v5!cv& zH#-V79E{$jr{zhWfX=~<hcEZ`r#tgp5n8lnhY6F}7ttwoG(zlA=3RX<1a4r4Wd$O= zzs5f&7k1;4Wfg4tAF*y8(LIgyqob&%{Y>Q?WuN;*Z_62NuZWVPdecq%Sxa60a-LIP zcliQ>)eGA_hIMsb_cWEL#id%p)rNbd^r!Z|s*1cDotd)?MM&Bnzt`(&VxD4_E<}Ux zn?C;>+9)E!Is>uNT(aCzsC*#=t4yfCq7hxh+oR-#{HZfH9b<Zukj9ZX{^AwdQ^<t! z75Fd7Mx)lE)V!>xA$bG9$?VXG@)<b`OBP8feq8TD#0>Fu;pbwkR8ySWS|5bqkvKcE zD*~i&z4o6*s_K&teg@L#yqBT-hvSH6OG{vU_`*Aodqa`m7bCwd#Op+6IXzMEx|^&o zi>q-5%c<D8pC;=qTiun&O{M$gtgQ9>EZ4fIF!8!ClfKOzS}2}`1T$=P_@>xc5u7e* zQ8y==x!ZQ6M*AfaVnyhlF8yw6(fdRVM<Vq8Ph5-3!)^=&ycO*a9fg0j3d!7@B1)#A z<FC)zbj(r_An5=Lvt)9&CA{r82s07ZmR)}mDLh^QEo_|2sxbm3$!BRW5zJ=b<sd2l zKD%6thy@{p`-1ajt;CGuXaGb1(^g)7tv`M0w4|;8o5P**gU&X?CqS}eG2r<41XuWL zB9Q+JY9`DlaN`GlVA~@^XB5_k&vw}M9|%}OB7wko6r#WyGCdlSdF#5*EZiV{RMxAP zmHXS<n7h`fuEej)sj@-T23!N*H?}jKw&U3+wJlOhN(u%1{CXI3qOYgA!lnJNvF1xs zUmud@`-?3Wuy@z56)PUQ-aUDW_GqSjcRd0=c7LjlMpd;_JUyTP{E6(vO6(wAj)Bo6 z?}1!KWM=UA47--7X5l+*BXx1mCCIo*$F3?YbA7h^;6T_Y4)agd`J*wgGM|>~|G>G< zA!rfA-A}<xR4y;mgRWF3Zc^zcz#~)1%-}7%GvS*%r+_0|Xv;>_oMj>$1u(-+5Te<y zof9gID}qu{ANm55z~hb*Iu~DJGRP{1!Dm?_8hUrGsR|AcKNB9$jw98FtGSwSvAA@I z)lh4(C{N@sWZ!A<O0}#&q+9MK<_OjoWBWt(;?t*d*PGcbG_Kd)ZyRi}^x>oQbA@TK z%9+7E92VdTt;9c}&p>cBE%7)GhF@Srv)rUXyP4vabf3UqXG8B2Bv(WG4L4R9D&ZPX zH6IG~T!>MqJ+Hl;>3nqQ*I>#>Ff$_vDeI1X|DX^H;`{WT(F*lXiG;qE_gC$_UjI(T zwbbVrSo}zxv*TsA$uAm~2!MEmdXG~+DulNnZ+8OPaN-|Q`P-adm_U1(2pk2ed<YQm z!sR!01^5{Wm%mipm?GQur|ARkz%A@e>hIc4)Z>^(4}6Xap#<eP&>|it5m{wCn(Uz@ z=V_6p-V|;V*_g_k{q05^(>R_0M;FvZ1zBhBFDnOI*mcef1&r_~^1td*C)tgEa(Gpr z#jaa}QNF}udDSV(EISq(>G=<GIi4JA0Ax9uH4sA2o>TJ#$mRz=qxoOVXr(Y-eZ4<! zG9`2VF-M|^Na0y5@SZ;DojvgwsP%Isy!t=5W>w1st6_O6Ww6biryRWwaF>_$d&Dz% zHgvcNoYr%!-|gEp1LNDP4EPsl8f63+4KuSjv<1r*q8mHqfJ6DEoqM;KJFYKqiKhgn zo!^@y1y9aLeWVecXs1wrWvE196)f`)|4iO{mgAgUx<9Bis-8*)&#G5vu~37pAMksT zlx?8yST(Tw0MbpKrMs*B5;q23t6jtwlPGDHHN|!hP9>Lz;>`VWSpS*qIab?bz08<L zf#9bIj6o|}UasYn`SbSn%thZa&eK|cb4S8XTzjuAr_?cgj-r~>dVZlpt)OKF#-35# z#qZwi?p@k@e(L_RK2mrJF>8{ZmvsmFV8(gn8|?0m+xif9V1s#K_Z9BO5h#8G6@oCc ziRsR8V}FHL))oLYerCg9kK<;Yri{FQ=b$zJEjHGhQkE%GauqP!SVavj=9-pXE%x<# z0|a!Wk{FqL&l)Z#3`4!N<xY2z7fW!B)_3)*&A(|RSs?2czS`>f88Yfmg=*sbmOV+e zIn9&PXVAkUVa1V!Y+Fe88>T>dH8tORHSIsQY&Z17E+H194dKTr8vw6Y)jyaPuyiA5 zi1GV;z64E^kh?xDUkV!3da#&OeW}Xw6vB8KP}P3k{7KnxG@Mflh-z?+olUNwx^|Wr zY2st?LQ`0WmT9!&rjajUWf`$MNoX(<k!{+ortzEIW!nQMZ3X@!y+~n>f+o9Z4V^yq zx)~jSDm8CCcuLhHk*Gg_`*{Pa>(Kzbl%Awz`sK3+%ej$pZog?Jh)nalbLbnAed(He zR<`pURJ8_Ildj_Z9mujmWnG!j%i23`4H<$xD{p~^zFQu_`+22swRK1lH-`OVX@O(8 z(@S?Qi^8dt3GLJx4J{t6>-i6_kD_<oLt!k&?`oriP=p>)^EKrzsAVf<-hZ05Wa8LH zQ-z~iL$hr)VDFYv)GWs#2^*6JKdavigC<^5I7>M!C65?+k^Qf8{$EE9F|GkvHWbH9 z7#<$b>m^CWho(tNDfAbY3ZnKQxQu>QMa#;H%LXzo{RPU}va9;$%IQT$TAa?bektFS zx5_zJ^_ELb^C}qmJ#AHIva5;gd+(n&xQ~{7e9>r{qW(;j$)?&c{=TA2RigK_np_+X zs58Z2_+sVT$H|rccnTf=Myte*tnn(8!l~X^Z`YCdP-(F_P8x=3J=6;O@LrAI@BwCW zx*T8;TX@d9@QHV5v8!(N(=VW1LVn%lPY71Rsn#xr_D436XJb$!wB0J{0%zd}US0mz z%dG<5W`EhA-x5K8IiDk+f<22SyGqkG*I&pGC>u7Ih3m`;cx`}wnJTZn+Th*%<y?-i zShlH`^czmstTl(^LEfn`vMIW)Z1u-Aw3FAgdG|nucHNkY1|}mG-JZo=)Z~eGKWTLe ze>F=F@Qf$^h@f65Prq-jW?DX9N{ul!!g7>0Bnm@@Ezwz3T@KKU<k)r1ZI~D8%>B31 z`ZsL5$|(m*Xco;To$lp(4cX=&@%HW!cvFv#>sL#%44J9y!kL_CA+B)ySW_*1Z6^8u zet<vdMs@f1?(cCM_wpLYS6}i4^i>GZi}u}44(gIm0<en8^h}R5!i-g;ePr>#Th~<l z^)NT7VJT7uL+85HMJ8pKjRr1;p80I$uWix4+3BPVB#Xm^xNm<q@jVQn$H6Ki@bts; zE*?&!fAu9BvUgn`l9Gu3nc&GzRI)VyJ>$G8)vQK9H8uyDQ@B}@XWzlz2XF5df~I1= z^R4_bT6Qd)a+vKqnjbG|)K^7Hv8#utZ}j4+54%#T_V|qG$<+9i-U(0CuMd#?aRM6~ z8zoM%ch8W8-d_H@;A)N~{#^50c&p+dQV&&63qAZ6(rJi(>AajP2uGz8+hC--0v{Ww z8c<@o_M%izCGXQDvxJw_ws;p=JYvtz6Fqzpk-KWZ0FlA;C7wbr7XGG?dZrG8jZFqZ ztQSMnyP&UW)Ki1+T95uq-&Oc2$*|K#D-ZCUa^3ol;KEWL7?TgDC~$r=#x%@JrR1C@ z7t3x5j?Or&ZgyIyl-N=7f0PSdS0pw4UM^B^-?<wKAIH-92YfcnlSb0LXux-5-^1U+ z#ntQ4Mgee{t*k|FRyO#MQ^z0%wlAU%c>dC^`QUpiDsPX^T(|q7nf|pM7ov<0Y*KD@ zdm^r705hu)&Vou6H<PK*^hgq7Clx7#<u$nKjLPSwiCuUyQPnOGGqP4DZPH`eTadxD zOHtD5(5FPTSkee+UY`6fY$CKx2m`9b<-#}QTVk<xPkF7b_+sl*Ta<G>^T2NpLC>u@ z5eYz#SQgAw>93^KK5vCw$JO)uvq%F@A@*!%h+QDW=kV_tqZ>%glb!|%H+DW_UPY}2 zrCH4jK`ouid*HBISi*A?&fMCuEwfmSbfP#Bn5BB~4~oMo2qxQypgrkJbd^f*_DO@5 z#MTO_W<=wWS&?yXmbBj25G%DBk^zODtdAhoexZp-Iu_|aNf>9~GO^l38aU%-nro3& zm%hvCz+aTBOU7kFk55Dr61!X1GyKu5gx5>3JY(1$5HQQtJER_n*Lkr`xY_Bm@53yh zkL_$nLpanZT1gdQ8O$TrU)@7!2MJ*B6iWOzH((eo2j@r5R`KXFQD!`1;pht4lAEA& z60X`NC8_$Zq1u3yld_z}NomwZj?shIpYImWSLJP#1o}a^(^~nzYOLk?6e=6bN=WRM zPIatE^hc}ybmf}#QCI|n!5r%DQ`A8J5o#YL#jBwe{OKRAl2Ej`*b^zmpt=Tih}2-V z3oD^(k*`2eTdQSCc+ZD2G~cnfo;A3=N<cth<yxVL$tTK_y)JTu!8PfJa<M0RCW(ji zBgF1lZzHP(u~Oh}P{*SN+*|)*eGbgYc8rp@=7l_#l}6esty9MWXhTEZHO`G`eddGd zPI@OgVk3&>@$6Ip>~8pu0Q1T-t02}o;ztPUWY@O;RjXFozckX)M3jJjTG<AggZZhe zY#B-FO)Lc?dvRAp!_=;of|0-GV7yeYkO$`&`Bov!5?S=uWw;(4Sv2au{re{VkpFY= zwD{!meiJ`+%GG0v2038%Rv)04U1(d~lh8gdvcuolv-%=^dt;2`?GuDNvxe{(yftQ+ z#P(*e(u$1*i%L0C)9_U89rqR05S)Er7OFjF$POG%w@d%LqgYVu+o(a?X7o!vOL%Um zU|-_J%4K_jDNrIdo9rPfRX^Nrqo}smEfY~&H!SEbW$a~ORB(kWm|(-g<Ah8~QusNK z&C&DZ%!slTx46QjB!pV^XM#q`ns`98tDYc&j}C=aVe>{Jmt`B$(9R#qHs_<`v1>@J zC+UmjNOc7ny$>U1K*+`!uYf5u{hS0K5U*vr&9hcu{Od$Qf*Yf_h5z#qL%tsPO6;qk zE13G%*AB)FrXP-a=MnG2;sjhcNE}#ic4*5}P2N7MJFcv1|1=t(e))CRADj1IT?bP` zPMfZQim=>d?jMbWn?RtAjF@yiIZOFu&Fa<SS#wucam5QiW+K>i&<Fk-ePn*Jp9sxj zkeUOSOUpHf&w?qW+sX9IRSk9HzH@`!{pY(i2I<ivW%m*~w-Q8EPgv)OGwu_YYf!i$ z9qwPV>Yhn<{ikZRHqyCY?ae_rn+M^BK5IskzHq_mJ|sJ}3fi(LX?~>a31^(>Aylpv zkAd$M8pm^r%X4EnH&D`y-}G73NJA|#P2~JC6HMRxZv9}NXm4e_C}{}I-t3>5vq;hT z4U<NP-kOupYgn@k11Q%C^<0-hY*wbtE5@nn5wpRRNhEkA=vkCn<zC?2O96L~_qJ<8 zy%-?t^ttr1-lI_d51-|)uhKgX|H`M<iOXQZmLQ0I=!#hu^8oq8Gt-h_`60Iv%^dpJ zyB9PiSME}&POs|nSX*0m3p&_NdN7;Q>8I0DUfb!nT2Un+plEPkxww!8Xyo*{@Yl<! zIs(#ks5v+(>?WtaKYT*UD^w<Fgbd*fsSB>I$8`|R7(n}#y7?S;J`!g6o~~)!0meS| zrqgTS9>|%y&a1w6fZ44LY`<$4>6NRiJJ?Y=DXhMM@7A38b<F?LP<3oHp1-}oJTY^y zG1GHd@h)2O;{_h;r9X+ByV*s1DB3)b?ruy(FuwRyAnK2>|D@$&wX>`)aJ`c6k2)%E zs<4*-ERDtsh{uDdn9-aguSI?z>G+U-5DaLYXruUkxgrJxA5^rQ)jO{<aDgb+=MFtW zm%g2qV_8SiFK9J8&Zf9dz2+%S(ivSMef@y=M`3~PkBI1r__8;WmN#a(>-om1BpM+M z9(g=d&tiyp_0?OPD_z&l6wGxbMfk!i_5#NBvI$#TeKmK&!Kv?tC-2O#6QW;O<6#i= zm48xy9p2t(rBze5P3w(*SolRLymM(#ZU=e5g@j+MKEf(^qAgr|7d0nUy|VO+_MU<Y zxbkN`fJno=!-cRFwUO_qM@lg`H>WskNwnj1^mwf4peF0fbY)ITJ@HeUB{A;B-b~Ev zSXH=96s?ybe=ftk122eKq1Sp1OV^=j-X=w7g@diqGl~);DuD;d*-hs^I0d;pv8r_P zdSUho5EzO5raef0@!>z`eDo7J8qN6F^>?PnDCLo{vfbd>Lj<^%{B7~8)l`~DlBLcI zD_)?6^qU2?xxqR^!m}ie`Loh&Rp<EAX<P5|{Z!@nP*_;dHhGz*mc+^u{la<&v=t}c z6w%3Im@#|mM7b(6WmWh(`-)Ro2I>iBi|-`&@AA0`nf_Jw2Wi|rxXnuZpq-v%jn|Sm z|I_tFE{r#n=r@@|4bhJ~@{hBerfy)W9B=86r25MCl#12VquXa%I?_K``}iE;PpX&m zcc~V2faga(KP^J?RM`WT(-kbA{dS4;vy28S$Bj~z4E|_kiC7i|G$>y2nIgJs7JwF4 zgw2WtTzy*oQ5R5&ZGSD<>Z^FN31+QpUS7Rnyg+!aje2X>jN6e(nL_OK-JJRLE?k+_ ze$^<1ho^tio;W231G``J8skaXjQ!yFHN6W2<gIxo_fDRAFW=!<>M8diuDYBj{y%Sc zOV3f*^MT{Z!H;D<^r`s5`KegcSWPQ^fk!7th1W+WY-U+O6$fiD)}D$UK`p`g>iRd= zF2D@+2sP{-%p$M(o_L0>Ap<`_BtuIlQ7^2$hlJFP5wZ|V^2r~+RKLQ2iepH;f1qaU z-vC1cIfo>tWtWlUln4kgd1;>YnZ97#F%ZXcU@@h@wJ<=QN1MuxaeamoWw!Ak<1`Nx zj(t-mwqdzC9@n|q!u>2rhv=W?sn3w|)$xK&bIkKEzBU2_K0iNSovkrD_bQ=?2}5>% z4ER!icZc;0)obKEQRKuKp@k(&6dw8)k}#RC|EupE)>y`YuA;jdy@SCZ&uFToW|m&& z!bCv{5HE_C^CriF3b$2;@mwbCq3D2f$FrS|;1$+8n*q^aU@S!P4dZV;W|B8A!pO*H z7lUSa&*vSw_p?|Oq+vj=>ulp{d)uD<{ImAJJ6&aP@)FIhS7Y7vgHaBea<%OII9k7k z`)}z8CG4|nUcB0l0~p)#*4%l#H5jU*DR*ibIQef6NjqHjG9I(Hmqhq}yiPV1{{1W; zKeRRMNf&$xwu4M2<e@JMD0?n=`!?9K+xmme;wc@X1YA#i{-(a9wcBmF4QJ%hTyxFg zb_;7eTJm*mtLEd>!~XhIc{Oudr>lp^Z{1$=Kdf~V`hE)RFS+t7^a-JdDNA1KFXQRt z6&O*zs-Y``&?><7w>hv03}s~~)(x&Vra}ffE1ul*Z2IYijO5rh;T+zZI;d5QJ+zLF zHtvm{cR1TUNHlY`rqV0g7X+=5<H-Dt?A*QCKCiIuejj{svU^0zO(D4XmTA|u!3xg5 zwA5s$N5}Uxf@>q7pSf1HfYnuyfc`gAj*V!(!*j+VJ>jtXOeVAGi;b;SL*?W;_ym7$ z60f&vtcyPZy#KZRvBeCYD!EoaVd68e&1k?aP~51hLUK(!h|v#7Mx!p){vSdRq3@}4 zfz4d?R_yju@lD_kqYBTf$4=$*6Dgb}2hi(K%YRdLcS+O9R=}q!c+W3)>DjIR0*b{q zbl7|K?~QB#*_3r`J3e`odin1)zBOXZ5GD{YVTgw=?9_4*r6|(2nh`nj9Zs;hPFuYH zJ|`OQ{k@>)L~Tx&BSUgKCfdY>ajuu5J5uYg^3VhBKz+K^-$DavH!TM>HQ~3G6KE*q zro)BV-%J?kwEW+DBT0lG9$84aDmq>RzkVLna+YFC{LGm9*Y?QUlV#>Qha)xbzE-g| z#^0&A%vGa=V370)n)9!%JL$BX)gW3d3d{Msq9(30ba1S)o41->C*uE5fc(~IX?$L+ z|Ete`X&_uT5sKI}z4J%(o{D-8P1bntbGDy=$Y@Xb?8X7_kl<Sm9ApiZI^UAg+JxNy zo+i+L`pt5R>pnQlg$V1y4T_Ze?<;_OCa>E~Wo|3@*L%I2uUh^~P@lgC!Unr6g;Vy6 z*5dlr9_}RylKpR|e?J1yf42Sgg8k(i+6d+lGzpBh#(G6GEls?mmng~?A|aws;CXAS zn$7&VVi^c&Ap#C98obBHlaIyLEqkVyXKPYYk;;J%yO|aFlmEV}qM*V<LkjtSj@S5q ztor}QxUT=($X@=E1BLSct9QP7`R4PY!T|SEgF#j5iP>t0h1Pn&z1Dh-V%2x7y>dSl zTEEJgwwz8?nun@>pP{?Xq|0ivi{q>6kG1;q)8ykKpM?&zgPr<sjTLT-*Z#TquR)>n zck>_R4+jSCiyeX=_W`|iFyR@7TxAZ;kqDI1;RS|V6%Jfc2o}=eN&DeR5PeB5t5us! zav|HgrAA%zH?8&t%^LG$TmE-8TiFulE`_V>AP?eitLsAH(S@s7kbQDVK;Gyz*3mcd z-Gi}ey;{ZSp}3n7ejqKOLoOZIC|oXCC1rA=4r5A%TbnvhnU8@ht-@PZcBd@P3EXfr zj8~Yd2u|+!ajFs&j(HyfxX~4@Y0bxLD6YGfU<%D%y>;!WWUi)1`)cK4R`dnBo(aCH z{264W@|Oh~&IKAs+FQ`;TJv#2A~UW6Gt1vXMxxr$r3ig^RP=qnIjEIpAerQxl3hWK ziW&eZD`AbM3x#(aY?x=(Gu}?{H@B;)@izBnE#B&`Cq>6rhL1b5m?R|L2V2p4u%gk= zclH$yLoY8Ed+@6s&CI`*BOvMf-GtV*#dIYjcnhDo;4FP~@0`$$&a8|G8sSf*jQHR0 zpJwY`maALc>6z{?r~QlL_<Q|PV+GL%rV6*nI!>xR5S<_?VKqHKZ6ZS1dt%v*LK{If zZS~%vdh=t&uGciZNGplE;c^g~Kx|-)!W3{wYl~OH*u}rjKWfUyto|hSTieIuV7C7j ze(RLsu+-lyk25o9S6*n)SW#$TWfV5Wg#$n+$rmtb8?u8-=U`P`?`J$artl{=ns79k z5HmW$aLk#1*A*q4WcT&>@dsJ?xx)qs8A8U6djuV&Cw_If>M@x$m4n)w=CKaUH`j(e znZ9ULnSZlfbSEfrKGs#QqTL74>V^aif}99sTMn2^fGp6UEg<x27a3K7E#RUp(DZ5- z7@2|6`tHy1sbd<Q{RR|+ocw^bfiogV{KX_V^3WYMS^><3{Z`fu?X>&=qMm|BYZKZy z6x(PK>ee6YW*W*4rm3T=NeW{l3r|Z^KjTd2t-hCs!Om!D^t@xVc1j$`J{ikyADRqV z$+?CY+UqUaJL+Vz7XxT&scnh{+&9<W#{kShPBhMqI(nazLz8y~WpIq1q{~2~nJ4lS zRluD-QA#T>$soWn>D3az>6$Wykc`Y40KJReH~`C=cY<!XsSF^94Ybj8;t|}5UK?N| z0g&yp_>I<DRvaFX4Zbidb~_ktS-IzKM4tq}1c|o8umLriR<A|JT&2Mr<RLMl2glSY zx4|)*W^sf&@%ubM5+GZ1ad{Jip^`F?J+$7Itn$v?s458$hLD!;YOxne#ON#$5Z+Q7 z9t-dXp=*NLfesb7AwtL00S~IRL==OAbN=P?n-4*AmaLN8zLK1@lFqPWFI$ba68LAD znpS-hh89-SHcRn~(KJsEtbHXcX(d@M|3TaWgdsnrWHg3NFN{qhp3Mx5O$wgP0*nnf zV5te!j)-oBBcG2`eFMfujQz_RtYa8^Wf=PcLnZT<1qQ=f@<ex3O!|aEz|wuYA>B%L zDyn7MQj=1JNT%GOZJxTOtxhTP!WUQ@1i(^C{vZmb9kq-RK?D3rU?@AJW=#vA7-hlc z%K|><LME#E`SbSH*jR<IiwrGe*F<ciT_`((rY-EHQK-0VV7!w_ERGRBcqKm80&8e8 zsS(DfNc)68MaqF+YH0_g)n3(}Ha_unY_QCllI=DgbLbG$Y<OLu;#??2P08WCOGOxL zaVdchWLL0P(E3Y;P$1FtXB>e5ODoPW_DzOLuP^GjfF+eytIx|FRXdwh;Tk>3D${Nx z|Iv@q2CXE6wTZ>EnSimu2Q1-6IQ=F1;+ERtSU@(YdbSV5CoZS9rY)^0c65`-emv1@ zGD6c_1g@}YqY5cpwA~5vV7}cOPD8b###1c34GMq*^n{bX68Wt6IT!Gi&3B_7rgGIz zE0*8w!|CYHw_5vvss|lEtfrHcN!!JM?fp2&<9cs}%&2em-f^@W7HyT12joCcb*Ji$ ziTf@qt;h4{QTwa9+j)U7A0fGoA;E=AYyMH7kKc2+OTKwd_@jH-L-)M(Hs)8t{sEHp z^jay&ft|J_YC-Jnn!^T1mLh<9BY@-6@Co}j`_VOx%n|kG%NKKiM%xKqQ}pJaNvcm9 z<6Z7pPD8cRXxqLdI5k+lB(Me!EI65>EI@zxZ|%GT1H5nbdItgCiE0)B#<5~X19zV9 zm8_dy{Mjq0zZQ?LB#5zX#o3|&mh2Xpcs6`+wAK5M>3t#x^Z1QVRk^J8x8|}M4)3m- zbo#<{_pZjZbLq93ERo{HtR@M}kzrlM?GEe|<-8=A*5p2fB}2Q$wNSO1&Fi&?)UR$< z8fE)bUgcnQxnS4V8BZhgI`0FlCB_Dik}dOHOF?v*ggKY4i+3IUANZq9)M>vP)VCUP zya33X+GwXTcnUA+lHqw7=3wEp`{A?_;q``T3!Ita;Z|92IW6lL0#^rZ$nxqB2;}%y zFhiqfNJHyDO7<bQ=!Gsx`{SjSIXD$uNb1w|?5(RouLu=Suqgj_r>`yF_tU}RrQp^$ z?+6pnS=I{YBKHC}t18i;;)k78x!Alz@x>^831cMUe~2>a$aja<=&^$)m8kwCYj*I^ z6_?I;wEf14orMz@R_fT_q=SYMAMD@89)ti7H6;;lsOZhXqRdq5(S>xs{o-qK;ZK0` zRmpmj=#jup_Y6;LJC_jg^_s^M_2A?%%ew?K5cvy_<WVIk=qfyt4NUZXa32NdLNV%s zNw@K8#T~X$!ZoC*P_p%6(!ANN>D}ZD_|8+tdFp{aV5bgBl!}B}MoeE=%-(CEn{BMr zxHebKYFPoQC)r)O?G0Yiruq$@KZoo${AB-^{`+87iSTl3+&^fJS0y7(>c!iVDu)9& z-+sRfrb`pS1XvN>H&G^Re;7bpav|I_t5)Uv=tB%OZ>w!#bvvVKg~yeOcw9fn+4Al{ zp)4>I(Z5m)xxugYe!t-~yF|tXZ_4=<xtrb3OcR&)9Ut;naF`I$h<uO8PvWAj`=YIU zIQyKnBss`ntBoW%ab+c$8zC9iayBc*x$+H~S1If8jbo(}Pvj!cf+)^g+Y2FDUM!vV z+N#q`>7I#@%?yRi(8+>`_B@Gxc)h-W4rlm^x_2_wfgKcMX4%LAmj3*{CJ(v-%^$$G z$J*wOk;wm9Q+iRv8^Rn)P1GfCQPDZtC{@<(#^yE5XuLwZjBXNwi3d~Le1qifCoT;n zJ*7E%t9a(TWo&C3L5Q64UOb4IS~|5%&@GI5e7UojOi$;(0k{p-RVtQKA9OA7pPXAA z<h$6(8vqUDv~s$v-4rJocpN5cCKbHTfF0B}E5E!?UX6O5-coOThMwL84?HH{fH|j~ zfOi)!|9OE9`;JpJgG>(tU`^}UNr2AmP*(Mg#_Z&n`$zK4s373nw$Zx^dLd+Xa_?kP z?WKIN@m$Bl!{<!)A%3%C_i4)moxygCgi+7;d3)1!YO4AfVJ<9aFgECAN~a{C{l)j8 z$|v>A9_Y4kzTxuzCyw0TzIn~hfBW?ege7JEL%6uo=U_dFvkHhb^pFGY>HPk>=XOwj zQ1ZgayZ^fMcI=>^^{^s*rUEU7n>c(xIF|#gt`;glhe&dO;u!V$$o9B|4Rc_My_ABn zkE=kX3zK*pKmSmEB*dNy-X-mJO6ql@-8md`itcsd{cE4mdu7!>9l!exZYV3FfN+Rl z<f=ZN@8jxVK%8(`9Q0bNdl+g{2!;Wy$AYRSs?~5nk%>yhJZwWBotj0(9CU~uVW@@4 z(HHyX{q=@(BL;-61dIw3N@y3cAq{TmiOKQxLNLIGG#20DhQ@ctXp41&EBeLh)sx6; zzSEQ2(Uc3D>x;Y=vJTed0Ux(V4p7lME9oFhzs8085EXy)@wOhCO2=uviHJV43d86` zGqnoC@C4heqHtAxWJ+BrZso#)a^c!;QrTNgb|EPn7IQ3dU>tgVcJgHL>?EmvQvBt* zaMkAS-PR{u8tXIP{vGSp-Ow??-1%qtNcuVx_nfM)csJE-$qua$Ag0<u;7h)I`13yL zR(@o~{>W67%0vhuzTSijWPx?|ft8xGn8uB6oHF}VDrxJl1Lv4>uTK2wdA?K=)rp(E zi0b_o{7*W@A%d{7h4$`N-eXmpuW8Ezm>arxhurhuJd^OJ!+<(d2`!frVCeARxg+Qs zQuqgb-3h=;i5)a#@SOi@z#@(Nv6~M!RK(<Hii@413R2VyV%Z*)qOzTa1TL8!L|oNN zi3TOG8(SYkIMf|%svo#kf<<;C<VZ-asftBs48cE!;e0yV)C?~9Wo<`60!WXI44u~Q zZQ0>7hrdZP%H@$SfG*~~tu2F+P)B6Ext|^0>8lJyXNwT6)?+--f2av5rVfbKVMu6? z6tfi~i$C6~|4Md<Byd70RoXp*Sr(%m6q3^!9Qi$1ay{3RsuV>UjzkSDk_<F~rs?+l zOJoWKf04%sY6shqb4&__A9sE#g<jnBOd+G>?M&eqv-Ypsy$JnZuG|u`NuBr}O!yX% zL!}ZsT8KaKrz?Vh*`zntM6gP92!Ry!xKcY@givwq6+vVIS4@}b<JLrxyT<*~4(vbr zov0D;(>1`Q167Pb*wW{Pz6`lyb6r<MB|e(=c3ZG~c8QC92(UDhubgLxNZ=PH<IVl$ z_gubyc1P?*@&iGD7p)!l;e0*x`LjMF4^Ps41m4_ND-4nrCp4TXYh8sfaV-Fo^H~`} zMDDrr3RC)UIAKB_^rS8s<Y(-V3LsFxF$F!JJRICYdMiH^Hk93HD?Ks@0QE`zCk;)^ z{ti8|C8AL>{iXl&;jxI*efdij{?HpIJofi}-rZjf0}%xVsL}t;N3<rHP#F`*FS*YK zW`a+SKM8W=upi}$BgA(O&n-8BF|??|>-R4|zx3oAq7MAD__0=kl=zphh@`=O!hMb< zghaBqqt9y)kV*TpeCk=caAN;7f0)}=`xjt3so#&El>JB$(GbT}DLU1!)yPmc%5++N zuW_cdMXTzgQwxA$Cq43s82k|uX`@<8j%abX=$K_X7IaJ#9myPoXu6bvyql<uksT#K zgoz^j*I$bsD}j)$7kq5MF0Rlw@hv3-3?|&x@MjvpJkc_)uT2S*PH6@Ix<w)BSaVB- z?^mAu@j=_3-rryMVD71cws}Ym5ju5KiFGXkt5`-Bo||o}3f!C6!R@v^n%Gf~^{Es? zTboW8vq5y4b+~6*?Rw}W*GISGl7}W~&D2xIYOgf`Qp%cz6XppLVK(C3Tr(KepN0X3 z-{H4)#j%Br<{w`N98QNH2{-(18(Vcut{X&JxjAC~fSAuXGNJ#kt*eh_x_#ps3X6rz zTWI2mHMYD(k1UFcJXt;1nwQO}7$Q-tHil6~OjxDzSb1y1kP)6}A|aKK8Ijk#MBa<o zZ#?IBp7T5B_s@Nu^EuzoeP8!|U)S|H=RWs+z6FDop|g)kFkg>f$MK8<ckDkW+xIWS zJ-jPc4=BNZFV5m5kL^B^OMg_MywYMP+G{znZBpp5!n;q&a6(SzA*Xte)UFivzEA9W zIE`FB?88umHCjmS0@1hQ7`Y>U_kV{oRxFq{txiwG1f5a8`>D*h2HjRCU+fM23%(9P z^x`PW);wf=4)Sp>vLy$}&aG|D0j&a_ym-55Hdss2`L4AOj`cOYkPv`N;pow6V1_^W zWzz~5ez;GgdJ1(w7mTZo^1)}m0W6^mz!+0Z-MZ4f$EC^K=c_j}g^7|aX{GgT6VNmK zqOkYrk}<VQuIxe;eJrVuH|NNcs|r#{3seagLZO0G2=d24pgaWmoroeI@yaw(o3q^b z4A(RisB&2t4M{F@?Fa(KS+`|u|Ct_2`z2>MTrSvv(?4y(ZnokYBj(s|a6qLaeLX19 zGg^NS$~{__y*uWj2p0ul@6k^ywCdxHrUf=!7AE`@$UVw*mn18Wj=Gw!X)r0y&b4hh zpgS_EV3S+VzWK$Rh!wV2<O#tibsrSo4aOpFHCOIF3tF(3VTGHoL76rueV$N~oOFKM ze|nRrR?t7te$gO@Hg$Asr0VUsKc3i49DOE;ekjxCcCx~#`_@3<8wU?9_dP|a8mLU8 z?wgj_{bFzT3~s=hVwmwi@aJy1r+s^4*&xl)r2M|U67=xx^h#W4OKm5;Syuu5XK4Me z==iunMD1U>Sp)6yB`yuG?Alw=$DeXjNGMafbSquM2p-T&qIR4L8LzL&N6qoM=qM7^ z2eKzS7z|WnhBsUD5n#kI7ufLUlsF7*;B(5>IQy=X;E;<l3AA2hrx{&Z+`dX8@Zz_A zeBrnmNsV^O%0R2+D#a2BW)ceK>lJvn0WjLI)d+4;IS(kv8flLwmDs)k*86N3l}?}~ z#umTz*)lXo{C6zC`@;32@Pok0UFEm%9}st>Jv4-`7W*#E%y#9I5A<HIp?%Ey(jGsi z%tMs8%;#$=0z>YpHL(1DqvxLWpcq~VOx9p}1J;7hdfn!L=9LP>F}!J7azO4<6^3hk z9_G2ks`O5J?mgH>bV9~Zr^G&pTf=#SdUPFWX98`NGh61@t7SNc85;BFllNPhVupXA zw<GD(?YL^V!-VoQ9si-CbD_**1p&Ue5U+jrJM+9X!geDF+4;U3(tqNO8>XVLG_^1x z7^_mAc1Qek6<5pCSs^M4bepM5GVWivU+azILsS^-cM)qhJN9}Y`7F>+<su#YhxlKz z?!lESf$qV_$^1}?d)7D0+K$&+W0A1oa;?Ve+XKJcu0Mh8QMhW0jg|B&g7eBC;*Kq1 z?Q3&$y~o;%+2e2-GSB((=`5~)nmsZ*7mh><M-LaA>fY7F0wE*iJB@BYhPM@KnO+8Z zOJFtiu$e=p_UNKea!EQZ$0i%r%0dq1>2$-0ZIh~#Lp^}7GL9^^wl442VQhFGZ-T;$ zdw0~+JFsC}!6^e9?pI;J3dVSileNyZL)TU*YVNoMg_%Ut@T#%rB!GNnAEbP4jh=OO z+1L92nxo!sL>!D?^NJkq0O1;{0iT#{WM+aR&#@{fJuNU@ob>wyPrve9)eFTJQQw~+ z+fi@Z>qOMX0<^@-NBOWUxy;rStg+Bd$IYg+|GcaEbv0DpcT3n#GO~yY!$neI`JbfZ zc}fKxa6*rdZN6qi|4RUlS~as9{~JA4PMj$CZj#6nXKO%M{-{=x=)9Q(=)?VMI2=sR z72Q;Wn5sdx0{MNQHM6^O(cGGP7HA$oUXG!bNNm~`K6h0C=fRqxAX21T8Jb|KpOP%$ zyP`pyiR`m-T50(cVOMHu;cI@^?P;=JdzV6U7bh57=E(Cc@jJydLN9giNxvd4Q6ruY z3Uh<8&idH?3EpC1s?nA40r!^T#HPy2-}k`^<dcjF|KGaImYE02EoaU*XPO5w&Q$hG z(XAuo&hP$bZYTuZeizqZK!>#IpZKH6>7U6N;Cvwd=U{rBJ*>J;uyi^vg@iF<8{xdb z{v^zBn^*~=H<W;}p#*?dr=37`S^Y9}T_p@Px<9TY$|~CDi_PO-!Ri$RR~z*;8|R)w z9!u|Criz;bR#c4F67H`<nd?upC@!#~d+Kx|RGj-7Jc7!o{-sqf!I2n4vEZl}lkYNJ zM54_@``&xlQ^LbLXa}S_QXF^cL3b!IJ^qr?Wmu+!&?Qi^I|4e#bQMpA81qX|Q*u4t z{pOw@&nfi?7XQ%R<)5x99BUDj4XGnC*VhXLlbEI7EtWbL)d++eu0K~AKRF~MMVgRJ z8&1nttPUK^7`h&q>g@5u?Lg(-620pmpA$az-6oh{8*LeCL=PHX-62|6v`&l^ZP)&B zqrO2ab0sY1lfM;tqFQp|PQ|&Q7t`2N>v~QRM(<3q8O&j3qUr33(pz!F>O&Tx#Cf7} zU{%ny#f)z@5f8fNA0{q}5~Q3WYE~Zq^zGB9h-B(s!7na(yiVrqtLb)~^}&jt`@!Kn zs%mDos-*2i7~y=Ke1pey{<!<)arce|cGbd{=e=oG%>6C8)=UF9Uk^MuB5kcIov50A z_1czq2F>&U>%XHGSy60v%$GRDaxXvX3+l&r<L&PX#+jGLnH>xAp5oVrluD6b->P?p zP}H;%B4Vt(#11AD*A!7k9KVjut|frQ+eL9@Qe2&p3&^=$l571b^T<-01)T!#&K%I% zv5EL~;^e0z<XaR^y3K+&%li{cj4tM5vb_@A;i=MIX$Y_3!EyU(bNG6{>O!?*2|T5T zp6GI5uv}GrfOa&wW5(f?_KDNTJSUxVAL@MZ=8rIFS0SBM^tZv&fBobdLl#@A7FwX^ zAsqV1)rZn(RYuvFh&p-aaFkC(2MaXmgUK~+gaNt6y34F5L^#gVZbGwa0q<$&2eFnF z&Nc(AnL-otjn<kd^T7uCa^yJAs9JEou@phLasj4172_Y)b#1TA`MxWY6-6`EeRvYh z1VB{BePeOm@=M&(xa}Qie|^q&bMOt(Ah)yw{r$%fm)|s#1f9Ennz6S&n(-Q+Q&55% z4n?a6z|=^)+%hzP4%+c54wT408U4%zYjtp<wZcB<B<VfL_02AXmrX+(-5};HIhYqk zKbukbw{jdJHT?+w?HR(`eRyYCPB@ff7*%deb5&Du+d>OJo)oSo%eI7abmfQ+xXyg> z;k8?kjN9WN5=E!$LES;V!ti&0JF-H)&WU@MOrU4}a6wyNn2IZQf^wqksua;o1CFk_ zn<CX*4Wey!Znj)`znyt@u<W8%nqkc%!TCi-{z-u{+L>A&%YTX@bf$5;q}=Yy5#@0? zD70n=TGJ8j1R(y1+;4_6+5$Tw$2Ng-nh~7UnFvvTM1@q>OBc@0>#Og>GPQ(`rJ=8< z&cYU-e+WC2JakCmrK~nQgeTEP-Ps0F+KUklT6k1rnK4#Jg9HHYLU+7bpdh*~z!0yM zEH|lkNO2oFuR}TXW;m1<ZUN<(E__wTdAcM&f^<pCP3|%8IwsYHt4JMVYt`iIM(iVH ze+Eww4bHUvyyR8L&^T$Oif*e77-6I9^CSSU-mBauW{b?&tUYza@$C=<EEoWmgv885 z*F8P0I=_PrrP+f?H)-@6&N#;3ga8TP@@=c^#)Imw2D7|3YmcM^GTOYl_Mo=Je*n^u Bao_*| literal 0 HcmV?d00001 diff --git a/src/main/resources/translations/en_US/events.properties b/src/main/resources/translations/en_US/events.properties index 61b9590b3..e0039bbf5 100644 --- a/src/main/resources/translations/en_US/events.properties +++ b/src/main/resources/translations/en_US/events.properties @@ -52,6 +52,21 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>The Halloween 2025 event i <br><#ff6b25>You can find your rewards in your</#ff6b25><#ff6b25><bold> mailbox</bold></#ff6b25><#ff6b25>.</#ff6b25>\ <br><#ffd580>Thank you everyone for your participation!</#ffd580> +feature.events.halloween.festival.start_message=<#ff6b25>The Halloween</#ff6b25> %1$s<#ff6b25> event has START !</#ff6b25>\ +<br><#ff6b25>The Witch is waiting for you. She has some things that might interest you nyahahaha! !.</#ff6b25>\ +<br>\ +<br><#ffd580>Hunt for Candy and decorate your City before the end of the Event !</#ffd580> + +feature.events.halloween.festival.end_message=<#ff6b25>The Halloween</#ff6b25> %1$s<#ff6b25> event is now over!</#ff6b25>\ +<br><#ff6b25>The Witch thanks you for all the candy you bought her nyahahaha !.</#ff6b25>\ +<br>\ +<br><#ffd580>Thank you everyone for your participation !</#ffd580> + +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=<gold>Value : %1$s %2$s @@ -73,14 +88,14 @@ feature.events.halloween.festival.button.deposit.lore=<gray>Increase the advance 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=<red>Reach the %1$s to unlock this item !</red> +feature.events.halloween.festival.shop.lore_item.lock=<red>Reach the %1$s</red><red> to unlock this item !</red> feature.events.halloween.festival.deposit.add_point=<green>You added</green><gold> %1$s %2$s </gold><green>for %3$s %4$s</green> feature.events.halloween.festival.deposit.broadcast_add_point=<gold><bold>%1$s added %2$s %3$s for %4$s %5$s !</bold></gold> feature.events.halloween.festival.player_not_enough_item=<red>You don't have enough of %1$s in your inventory !</red> feature.events.halloween.festival.shop.confirm_lore=<dark_gray>■</dark_gray> <yellow>Quantity :</yellow> %1$s <gray>(</gray>%2$s <gray>stack</gray>%3$s<gray>)</gray>\ - <br><dark_gray>■</dark_gray> <yellow>Unit price:</yellow> %4$s%5$s for %6$s \ - <br><dark_gray>■</dark_gray> <yellow>Total price:</yellow> %7$s%8$s for %9$s \ - <br><dark_gray>■</dark_gray> <green>Click the wheel to <dark_green>define</dark_green> the quantity manually</green> +<br><dark_gray>■</dark_gray> <yellow>Unit price:</yellow> %4$s%5$s <yellow>for</yellow> %6$s%7$s \ +<br><dark_gray>■</dark_gray> <yellow>Total price:</yellow> %8$s%9$s <yellow>for</yellow> %10$s%11$s \ +<br><dark_gray>■</dark_gray> <green>Click the wheel to <dark_green>define</dark_green> the quantity manually</green> feature.events.halloween.festival.new_floor_unlock=<gray>New Floor Unlock !</gray>\ <br><gray>Collect %1$s %3$s to unlock the next floor</gray>\ @@ -96,4 +111,22 @@ feature.events.halloween.festival.last_floor_unlock=<gray>Last Floor Unlock !</g feature.events.halloween.festival.player_not_allow=<red>You are not allowed to do this !</red> feature.events.halloween.festival.floor_lock=<red>This floor is lock !</red> -feature.events.halloween.festival.mob.zombie.name.0=Receptionist \ No newline at end of file +feature.events.halloween.festival.chest_lootbox=<red>Loot Chest Loots</red> +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=<red>This will delete the current loot, wait to get new one</red> +feature.events.halloween.festival.chest_lootbox.prevention=<red>You have close the chest, the loot is reloading, take everything you need the next time !</red> + +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 From 84b4445e671ee3b9972462b290756b5cc315eccf Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 16:49:08 +0100 Subject: [PATCH 33/44] L'avant dernier commit --- .../api/cooldown/DynamicCooldownManager.java | 17 +++- .../listeners/TerrorHouseListener.java | 23 +++-- .../festival/shop/WitchShopItem.java | 4 + .../festival/shop/WitchShopManager.java | 53 +++++++++-- .../festival/shop/menu/ConfirmBuyMenu.java | 2 +- .../shop/menu/WitchShopStoreMenu.java | 12 ++- .../witchhouse/TerrorHouseManager.java | 4 +- .../witchhouse/advancement/floor/Floor.java | 47 +++++++--- .../mobs/easy/HouseSkeletonLV1.java | 8 ++ .../witchhouse/mobs/easy/HouseSpiderLV1.java | 8 ++ .../witchhouse/mobs/easy/HouseZombieLV1.java | 8 ++ .../witchhouse/mobs/hard/HouseBruteLV3.java | 8 ++ .../witchhouse/mobs/hard/HouseWitchLV3.java | 8 ++ .../witchhouse/mobs/hard/HouseZombieLV3.java | 8 ++ .../witchhouse/mobs/normal/HouseBlazeLV2.java | 8 ++ .../mobs/normal/HouseSkeletonLV2.java | 8 ++ .../mobs/normal/HouseSpiderLV2.java | 8 ++ .../mobs/normal/HouseWitherSkeletonLV2.java | 8 ++ .../mobs/normal/HouseZombieLV2.java | 8 ++ .../registry/items/CustomItemRegistry.java | 32 +++++++ .../contents/omc_halloween/configs/items.yml | 94 +++++++++++-------- .../omc_halloween/nbt/candy_brown_nbt.json | 24 +++++ .../default/itemsadder.properties | 2 +- .../translations/en_GB/itemsadder.properties | 10 ++ .../translations/en_US/itemsadder.properties | 2 +- 25 files changed, 337 insertions(+), 77 deletions(-) create mode 100644 src/main/resources/contents/omc_halloween/nbt/candy_brown_nbt.json 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/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/listeners/TerrorHouseListener.java index 8649a3cad..5621047a7 100644 --- 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 @@ -5,7 +5,6 @@ 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.Floor; 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; @@ -20,6 +19,7 @@ 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.player.PlayerChangedWorldEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -39,12 +39,8 @@ public void onEventEnd(CooldownEndEvent event) { public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - if (!player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) return; - - if (!HalloweenFestivalManager.isActive()) + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) return; player.teleport(SpawnManager.getSpawnLocation()); - else - TerrorHouseManager.getWitchHouseAmbient().apply(player); } @EventHandler @@ -93,13 +89,17 @@ public void onHouseRegionEnter(EntityCustomRegionEnterEvent event) { 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; + if (event.getHand() != EquipmentSlot.HAND) + return; Material item = event.getMaterial(); @@ -115,6 +115,15 @@ public void onPlayerInteract(PlayerInteractEvent event) { } } + @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; 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 index 64d72fce7..bef1c30af 100644 --- 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 @@ -26,6 +26,10 @@ public WitchShopItem(Floors advancements, CustomItem item, Component name, int p 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); } 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 index 056add42f..3887cc32d 100644 --- 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 @@ -68,7 +68,7 @@ public static Set<WitchShopItem> getStoreContent(int page) { } private static int getWitchStorePages() { - return (int) Math.ceil((double) witchStoreItems.size() / SLOT_FACTOR); + return paginateWitchStoreItems.size(); } public static void buyItem(Player player, WitchShopItem item, int amount) { @@ -89,6 +89,8 @@ public static void buyItem(Player player, WitchShopItem item, int amount) { 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), @@ -208,18 +210,53 @@ public static String getHalloweenPointIcon() { } } - //TODO mettre les vrais items private static LinkedHashSet<WitchShopItem> getWitchStoreItems() { LinkedHashSet<WitchShopItem> items = new LinkedHashSet<>(); - items.add(new WitchShopItem( - Floors.FLOOR_1, OMCRegistry.CUSTOM_ITEMS.AYWENITE, 10)); + 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_2, OMCRegistry.CUSTOM_ITEMS.KEBAB, 10)); + 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_2, OMCRegistry.CUSTOM_ITEMS.NETHERITE_HAMMER, 1000)); + 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 index de46d04ac..5cac85a38 100644 --- 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 @@ -198,7 +198,7 @@ private int getMaxBuyQuantity(Player player, WitchShopItem shopItem) { double buyPrice = shopItem.getPrice(); if (buyPrice <= 0) return freePlaces; - double balance = ItemUtils.countItems(player, shopItem.getItem().getBest()); + double balance = ItemUtils.countItems(player, shopItem.getShopMoney().getItem().getBest()); int affordable = (int) Math.floor(balance / buyPrice); return Math.min(freePlaces, affordable); 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 index 3c53fde0c..b23e7fc1d 100644 --- 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 @@ -10,6 +10,7 @@ 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; @@ -23,6 +24,7 @@ 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; @@ -90,7 +92,10 @@ public Map<Integer, ItemMenuBuilder> getButtons() { if (hasPreviousPage()) { map.put(45, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_BACK_ORANGE, itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.previous_page")); - }).setPreviousPageButton()); + }).setOnClick(inventoryClickEvent -> { + if (hasPreviousPage()) + new WitchShopStoreMenu(getOwner(), this.getPage() - 1).open(); + })); } map.put(49, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_CANCEL, itemMeta -> { @@ -102,7 +107,10 @@ public Map<Integer, ItemMenuBuilder> getButtons() { if (hasNextPage()) { map.put(53, new ItemMenuBuilder(this, OMCRegistry.CUSTOM_ITEMS.ICON_NEXT_ORANGE, itemMeta -> { itemMeta.displayName(TranslationManager.translation("messages.menus.next_page")); - }).setNextPageButton()); + }).setOnClick(inventoryClickEvent -> { + if (hasNextPage()) + new WitchShopStoreMenu(getOwner(), this.getPage() + 1).open(); + })); } return map; 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 index 167a8460b..712d5ffe0 100644 --- 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 @@ -55,8 +55,8 @@ public static void init(int gAdvancement, int fAdvancement) { currentRewardToReach = getRewardFromAdvancement(globalAdvancement); // Floors - enabledFloors = EnumUtils.getValuesBefore(currentFloorToReach, false); - finalFloorReach = currentFloorToReach.equals(FINAL_FLOOR) && currentFloorToReach.getRequire() >= globalAdvancement; + finalFloorReach = currentFloorToReach.equals(FINAL_FLOOR); + enabledFloors = EnumUtils.getValuesBefore(currentFloorToReach, finalFloorReach); for (Floors floors : Floors.values()) { Floor floor = floors.getFloor(); 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 index cb57cd9ef..32ef862ec 100644 --- 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 @@ -12,10 +12,14 @@ 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 { @@ -25,9 +29,11 @@ public class Floor { private final List<BlockVector3> spawnLocations; private final int entityToSpawn; - private final int RADIUS = 5; + private final int RADIUS = 3; + private final List<Entity> clearLag = new ArrayList<>(); private BukkitTask spawnTask; + private int timeTask = 0; public Floor(SquareRegion region, List<CustomMobEntry> entities, int entityToSpawn, List<BlockVector3> spawnLocations) { this.region = region; @@ -36,25 +42,34 @@ public Floor(SquareRegion region, List<CustomMobEntry> entities, int entityToSpa this.spawnLocations = spawnLocations; } - //TODO marche pas a fix - 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; @@ -63,24 +78,34 @@ public void enableSpawn() { int toSpawn = RandomUtils.randomBetween(1, entityToSpawn); - for (int i = 0; i < toSpawn; i++) { - mobToSpawn.spawn(getRandomSafeLocationInRegion()); - OMCLogger.info("debug : spawn mob " + i); - } + for (int i = 0; i < toSpawn; i++) + clearLag.add(mobToSpawn.spawn(getRandomLocation())); TerrorHouseManager.entityCount += toSpawn; - }, 0L, 5L * 20L); + }, 0L, 15 * 20L); + } + + private void clearLag() { + for (Entity entity : clearLag) + entity.remove(); + clearLag.clear(); } - public Location getRandomSafeLocationInRegion() { + public Location getRandomLocation() { - return LocationUtils.randomLocation( + BlockVector3 pos = RandomUtils.getRandomObjectFromList(spawnLocations); + + Location newloc = LocationUtils.randomLocation( LocationUtils.fromVector( DimensionGenerator.HALLOWEEN_WORLD, - RandomUtils.getRandomObjectFromList(spawnLocations) + pos ), RADIUS ); + + newloc.setY(pos.y()); + + return newloc; } public boolean hasPlayer() { 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 index b0cc88d55..ec0dcffa6 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ 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; @@ -36,4 +38,10 @@ public Skeleton spawn(Location spawnLocation) { 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 index 3d55c063b..a9d750990 100644 --- 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 @@ -1,12 +1,14 @@ 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; @@ -29,4 +31,10 @@ public HouseSpiderLV1(String id) { 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 index b5aa4944a..645ce5c29 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -9,6 +10,7 @@ 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; @@ -58,4 +60,10 @@ public Zombie spawn(Location spawnLocation) { 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 index 3fc4ffbf2..351e484c3 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ 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; @@ -45,4 +47,10 @@ public PiglinBrute spawn(Location spawnLocation) { 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 index ce6edd376..6352b4a03 100644 --- 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 @@ -1,12 +1,14 @@ 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; @@ -33,4 +35,10 @@ public HouseWitchLV3(String id) { 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 index fb100ee69..9c064348a 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -9,6 +10,7 @@ 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; @@ -49,4 +51,10 @@ public Zombie spawn(Location spawnLocation) { 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 index e0676422c..d4f632b08 100644 --- 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 @@ -1,12 +1,14 @@ 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; @@ -48,4 +50,10 @@ public HouseBlazeLV2(String id) { 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/HouseSkeletonLV2.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseSkeletonLV2.java index 346c171da..05e410db5 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ 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; @@ -39,4 +41,10 @@ public Skeleton spawn(Location spawnLocation) { 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 index 489873edc..cbbddfd40 100644 --- 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 @@ -1,12 +1,14 @@ 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; @@ -31,4 +33,10 @@ public HouseSpiderLV2(String id) { 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 index 3a4dec0ae..c79455a81 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ 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; @@ -64,4 +66,10 @@ public WitherSkeleton spawn(Location spawnLocation) { 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 index ec08afb6b..613de04c8 100644 --- 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 @@ -1,6 +1,7 @@ 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; @@ -8,6 +9,7 @@ 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; @@ -48,4 +50,10 @@ public Zombie spawn(Location spawnLocation) { 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/registry/items/CustomItemRegistry.java b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java index 950c220f8..832c14375 100644 --- a/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java +++ b/src/main/java/fr/openmc/core/registry/items/CustomItemRegistry.java @@ -287,6 +287,38 @@ public class CustomItemRegistry extends Registry<String, CustomItem> 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/resources/contents/omc_halloween/configs/items.yml b/src/main/resources/contents/omc_halloween/configs/items.yml index 6be1cb188..7bde90dba 100644 --- a/src/main/resources/contents/omc_halloween/configs/items.yml +++ b/src/main/resources/contents/omc_halloween/configs/items.yml @@ -63,6 +63,7 @@ items: material: PAPER lore: - <lang:itemsadder.omc_halloween.candy.lore.1> + components_nbt_file: "nbt/candy_brown_nbt.json" # marche pas j'ai pas la volonté de chercher consumable: nutrition: 1 saturation: 0.6 @@ -93,44 +94,55 @@ items: y: 0.8 z: 0.8 -#recipes: -# iaa_crafting_table: -# fermentum: -# shapeless: true -# ingredients: -# - item: omc_daily_events:golden_wheat -# amount: 5 -# - item: omc_daily_events:golden_beetroot -# amount: 5 -# - item: omc_daily_events:really_golden_carrot -# amount: 5 -# - item: omc_daily_events:golden_potato -# amount: 5 -# - item: omc_daily_events:golden_melon -# amount: 5 -# - item: omc_daily_events:golden_pumpkin -# amount: 5 -# result: -# item: omc_daily_events:fermentum -# -# blessed_bread: -# enabled: true -# pattern: -# - FFF -# - XXX -# - XXX -# pattern_2: -# - XXX -# - FFF -# - XXX -# pattern_3: -# - XXX -# - XXX -# - FFF -# ingredients: -# F: -# item: omc_daily_events:golden_wheat -# amount: 192 -# result: -# item: omc_daily_events:blessed_bread -# amount: 1 \ No newline at end of file +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/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/translations/default/itemsadder.properties b/src/main/resources/translations/default/itemsadder.properties index 0c53a6346..6ce6a55c3 100644 --- a/src/main/resources/translations/default/itemsadder.properties +++ b/src/main/resources/translations/default/itemsadder.properties @@ -191,7 +191,7 @@ itemsadder.omc_halloween.candy_red.name=<red>Bonbon Rouge itemsadder.omc_halloween.candy_yellow.name=<yellow>Bonbon Jaune itemsadder.omc_halloween.candy_green.name=<green>Bonbon Vert itemsadder.omc_halloween.candy_blue.name=<blue>Bonbon Bleu -itemsadder.omc_halloween.candy_brown.name=<brown>Bonbon Monstre +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=<green>FrankenRoot 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=<blue>The Mixture itemsadder.omc_foods.the_mixture.lore.0=<dark_gray><italic>a mysterious mixture... itemsadder.omc_foods.the_mixture.lore.1=<gold>No Side Effect! itemsadder.omc_foods.tomate.name=Tomato +itemsadder.omc_halloween.candy_red.name=<red>Red Candy +itemsadder.omc_halloween.candy_yellow.name=<gold>Yellow Candy +itemsadder.omc_halloween.candy_green.name=<green>Green Candy +itemsadder.omc_halloween.candy_blue.name=<blue>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=<green>FrankenRoot +itemsadder.omc_halloween.root_plush.lore.0=<gray>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/itemsadder.properties b/src/main/resources/translations/en_US/itemsadder.properties index 16067ee42..0d75087d2 100644 --- a/src/main/resources/translations/en_US/itemsadder.properties +++ b/src/main/resources/translations/en_US/itemsadder.properties @@ -173,7 +173,7 @@ itemsadder.omc_halloween.candy_red.name=<red>Red Candy itemsadder.omc_halloween.candy_yellow.name=<gold>Yellow Candy itemsadder.omc_halloween.candy_green.name=<green>Green Candy itemsadder.omc_halloween.candy_blue.name=<blue>Blue Candy -itemsadder.omc_halloween.candy_brown.name=<brown>Monster 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=<green>FrankenRoot From fb31ccbd8bfe65a478c64db8e5370c9a9302c98d Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 20:34:44 +0100 Subject: [PATCH 34/44] petit ajout et fix --- .../witchhouse/advancement/floor/Floor.java | 4 +- .../witchhouse/advancement/floor/Floors.java | 155 ++++++++++++++---- .../reward/plush/HalloweenRoot2026.java | 3 +- .../witchhouse/chests/LootChestManager.java | 25 ++- .../mobs/normal/HouseMossySkeletonLV2.java | 51 ++++++ .../core/registry/mobs/CustomMobRegistry.java | 5 + 6 files changed, 204 insertions(+), 39 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/halloween/festival/witchhouse/mobs/normal/HouseMossySkeletonLV2.java 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 index 32ef862ec..63fc7b043 100644 --- 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 @@ -52,14 +52,14 @@ public void enableSpawn() { clearLag(); if (entities.isEmpty()) { - OMCLogger.warn("No mob register for the spawn mob, spawn disable for this floor"); + //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"); + //OMCLogger.warn("No spawn location register for the spawn mob, spawn disable for this floor"); clearLag(); spawnTask.cancel(); return; 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 index 21e4663ea..111d8b6cb 100644 --- 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 @@ -8,53 +8,140 @@ @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(-57, -59, -58), - BlockVector3.at(-40, -59, -63), - BlockVector3.at(-64, -59, -72) - ) - ), 0), - + ), 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()), 1000), - + ), 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()), 5000), - - FLOOR_4(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_4, List.of(), 5, List.of()), 10000), + ), 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_5(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_5, List.of(), 5, List.of()), 15000), - - FLOOR_6(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_6, List.of(), 5, List.of()), 20000), - - FLOOR_7(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_7, List.of(), 5, List.of()), 25000), - - FLOOR_8(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_8, List.of(), 5, List.of()), 30000), - - FLOOR_9(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_9, List.of(), 5, List.of()), 35000), - - FLOOR_10(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_10, List.of(), 7, List.of()), 40000), - - FLOOR_11(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_11, List.of(), 7, List.of()), 45000), - - FLOOR_12(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_12, List.of(), 7, List.of()), 50000), - - FLOOR_13(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_13, List.of(), 7, List.of()), 59000), - - FLOOR_14(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_14, List.of(), 7, List.of()), 65000), - FLOOR_15(new Floor(OMCRegistry.CUSTOM_REGIONS.FLOOR_15, List.of(), 3, List.of()), 100000); 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 index 08e09d5ab..408c16fbc 100644 --- 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 @@ -2,6 +2,7 @@ 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; @@ -41,7 +42,7 @@ public void giveReward() { OfflinePlayer offlinePlayer = CacheOfflinePlayer.getOfflinePlayer(uuid); if (offlinePlayer == null) { - //TODO problème + OMCLogger.error("no offline player for " + uuid); continue; } 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 index a3d83daad..d65e776ba 100644 --- 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 @@ -57,6 +57,21 @@ private static LootChest getChest(Location location) { private List<LootChest> 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)), @@ -64,8 +79,14 @@ private List<LootChest> getChests() { 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(-58, -59, -67)), - new LootChest(15 * 60, BlockVector3.at(-50, -59, -75)) + 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/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<Bogged> { + + 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/registry/mobs/CustomMobRegistry.java b/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java index e84490b28..163b891ec 100644 --- a/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java +++ b/src/main/java/fr/openmc/core/registry/mobs/CustomMobRegistry.java @@ -157,6 +157,11 @@ public class CustomMobRegistry extends Registry<String, CustomMobEntry> 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 From 22840f66fb7fa7dfe0f29f6e7a6ec948138fefa5 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 20:56:31 +0100 Subject: [PATCH 35/44] translation ( un peu aider par l'ia ) --- .../translations/default/events.properties | 79 +++++++++++++++++++ .../translations/en_GB/events.properties | 78 ++++++++++++++++++ .../translations/en_US/events.properties | 6 +- 3 files changed, 160 insertions(+), 3 deletions(-) diff --git a/src/main/resources/translations/default/events.properties b/src/main/resources/translations/default/events.properties index 1e2b1f2a0..54d0c5843 100644 --- a/src/main/resources/translations/default/events.properties +++ b/src/main/resources/translations/default/events.properties @@ -52,3 +52,82 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>L'événement Halloween 20 <br><#ff6b25>Vous pouvez retrouver vos récompenses dans votre</#ff6b25><#ff6b25><bold> boîte aux lettres</bold></#ff6b25><#ff6b25>.</#ff6b25>\ <br><#ffd580>Merci à tous pour votre participation !</#ffd580> +feature.events.halloween.festival.start_message=<#ff6b25>L'événement Halloween</#ff6b25> %1$s<#ff6b25> vient de COMMENCER !</#ff6b25>\ +<br><#ff6b25>La Sorcière vous attend. Elle a peut-être des choses intéressantes nyahahaha !</#ff6b25>\ +<br>\ +<br><#ffd580>Chassez les Bonbons et décorez votre Ville avant la fin de l'événement !</#ffd580> + +feature.events.halloween.festival.end_message=<#ff6b25>L'événement Halloween</#ff6b25> %1$s<#ff6b25> est maintenant FINI !</#ff6b25>\ +<br><#ff6b25>La Sorcière vous remercie pour tout les bonbons que vous lui avez apporté nyahahaha !</#ff6b25>\ +<br>\ +<br><#ffd580>Merci à tous pour votre participation !</#ffd580> + +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=Etage 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=<gold>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=<gold>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=<gray>Achetez des items pour décorer votre Ville</gray> +feature.events.halloween.festival.button.house.name=Maison et Avancement +feature.events.halloween.festival.button.house.lore=<gray>Accédez à la Maison de la Terreur et vérifiez l'Avancement</gray> +feature.events.halloween.festival.button.terror_house.name=<red>Maison de la Terreur</red> +feature.events.halloween.festival.button.terror_house.lore=<gray>Visitez la Maison de la terreur et atteignez le sommet !</gray> +feature.events.halloween.festival.button.deposit.name=<gold>Avancement</gold> +feature.events.halloween.festival.button.deposit.lore=<gray>Augmentez l'avancement en achetant des bonbons !</gray> + +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=<red>Atteignez le %1$s</red><red> pour dévérouiller cet item !</red> +feature.events.halloween.festival.deposit.add_point=<green>Vous avez ajouté</green><gold> %1$s %2$s </gold><green>pour %3$s %4$s</green> +feature.events.halloween.festival.deposit.broadcast_add_point=<gold><bold>%1$s a ajouté %2$s %3$s pour %4$s %5$s !</bold></gold> +feature.events.halloween.festival.player_not_enough_item=<red>Vous n'avez pas assez de %1$s dans votre inventaire !</red> +feature.events.halloween.festival.shop.confirm_lore=<dark_gray>■</dark_gray> <yellow>Quantité :</yellow> %1$s <gray>(</gray>%2$s <gray>stack</gray>%3$s<gray>)</gray>\ +<br><dark_gray>■</dark_gray> <yellow>Prix à l'unité:</yellow> %4$s%5$s <yellow>pour</yellow> %6$s%7$s \ +<br><dark_gray>■</dark_gray> <yellow>Prix totale:</yellow> %8$s%9$s <yellow>pour</yellow> %10$s%11$s \ +<br><dark_gray>■</dark_gray> <green>Cliquez sur la molette pour <dark_green>définir</dark_green> manuellement la quantité</green> + +feature.events.halloween.festival.new_floor_unlock=<gray>Déblocage d'un nouvel étage !</gray>\ +<br><gray>Collectez %1$s %3$s pour débloquer l'étage suivant</gray>\ +<br><gray>Collecté : %2$s / %1$s %3$s</gray>\ +<br>\ +<br><gray>De nouveaux objets sont disponibles dans la boutique, venez les découvrir !</gray> + +feature.events.halloween.festival.last_floor_unlock=<gray>Déblocage du dernier étage !</gray>\ +<br><gray>Collectez %1$s %3$s pour débloquer une récompense exclusive</gray>\ +<br><gray>Collecté : %2$s / %1$s %3$s</gray>\ +<br>\ +<br><gray>De nouveaux objets sont disponibles dans la boutique, venez les découvrir !</gray> + +feature.events.halloween.festival.player_not_allow=<red>Vous ne pouvez pas faire cela !</red> +feature.events.halloween.festival.floor_lock=<red>Cet étage est verrouillé !</red> + +feature.events.halloween.festival.chest_lootbox=<red>Butin du coffre</red> +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=<red>Cela supprimera le butin actuel. Attendez pour en obtenir un nouveau.</red> +feature.events.halloween.festival.chest_lootbox.prevention=<red>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 !</red> + +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/en_GB/events.properties b/src/main/resources/translations/en_GB/events.properties index ef66704a6..31bea0ad6 100644 --- a/src/main/resources/translations/en_GB/events.properties +++ b/src/main/resources/translations/en_GB/events.properties @@ -52,3 +52,81 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>The Halloween 2026 event i <br><#ff6b25>You can find your rewards in your</#ff6b25><#ff6b25><bold> mailbox</bold></#ff6b25><#ff6b25>.</#ff6b25>\ <br><#ffd580>Thank you everyone for your participation!</#ffd580> +feature.events.halloween.festival.start_message=<#ff6b25>The Halloween</#ff6b25> %1$s<#ff6b25> event has START !</#ff6b25>\ +<br><#ff6b25>The Witch is waiting for you. She has some things that might interest you nyahahaha !</#ff6b25>\ +<br>\ +<br><#ffd580>Hunt for Candy and decorate your City before the end of the Event !</#ffd580> + +feature.events.halloween.festival.end_message=<#ff6b25>The Halloween</#ff6b25> %1$s<#ff6b25> event is now over!</#ff6b25>\ +<br><#ff6b25>The Witch thanks you for all the candy you bought her nyahahaha !</#ff6b25>\ +<br>\ +<br><#ffd580>Thank you everyone for your participation !</#ffd580> + +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=<gold>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=<gold>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=<gray>Buy items to decorate your city</gray> +feature.events.halloween.festival.button.house.name=House and Advancement +feature.events.halloween.festival.button.house.lore=<gray>Access to the Terror House and check the Advancement</gray> +feature.events.halloween.festival.button.terror_house.name=<red>Terror House</red> +feature.events.halloween.festival.button.terror_house.lore=<gray>Visit the Terror House and reach the top !</gray> +feature.events.halloween.festival.button.deposit.name=<gold>Advancement</gold> +feature.events.halloween.festival.button.deposit.lore=<gray>Increase the advancement by deposing candy !</gray> + +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=<red>Reach the %1$s</red><red> to unlock this item !</red> +feature.events.halloween.festival.deposit.add_point=<green>You added</green><gold> %1$s %2$s </gold><green>for %3$s %4$s</green> +feature.events.halloween.festival.deposit.broadcast_add_point=<gold><bold>%1$s added %2$s %3$s for %4$s %5$s !</bold></gold> +feature.events.halloween.festival.player_not_enough_item=<red>You don't have enough of %1$s in your inventory !</red> +feature.events.halloween.festival.shop.confirm_lore=<dark_gray>■</dark_gray> <yellow>Quantity :</yellow> %1$s <gray>(</gray>%2$s <gray>stack</gray>%3$s<gray>)</gray>\ +<br><dark_gray>■</dark_gray> <yellow>Unit price:</yellow> %4$s%5$s <yellow>for</yellow> %6$s%7$s \ +<br><dark_gray>■</dark_gray> <yellow>Total price:</yellow> %8$s%9$s <yellow>for</yellow> %10$s%11$s \ +<br><dark_gray>■</dark_gray> <green>Click the wheel to <dark_green>define</dark_green> the quantity manually</green> + +feature.events.halloween.festival.new_floor_unlock=<gray>New Floor Unlock !</gray>\ +<br><gray>Collect %1$s %3$s to unlock the next floor</gray>\ +<br><gray>Collected : %2$s / %1$s %3$s</gray>\ +<br>\ +<br><gray>New items in the shop, come and check them out!</gray> +feature.events.halloween.festival.last_floor_unlock=<gray>Last Floor Unlock !</gray>\ +<br><gray>Collect %1$s %3$s to unlock an exclusive reward</gray>\ +<br><gray>Collected : %2$s / %1$s %3$s</gray>\ +<br>\ +<br><gray>New items in the shop, come and check them out!</gray> + +feature.events.halloween.festival.player_not_allow=<red>You are not allowed to do this !</red> +feature.events.halloween.festival.floor_lock=<red>This floor is lock !</red> + +feature.events.halloween.festival.chest_lootbox=<red>Loot Chest Loots</red> +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=<red>This will delete the current loot, wait to get new one</red> +feature.events.halloween.festival.chest_lootbox.prevention=<red>You have close the chest, the loot is reloading, take everything you need the next time !</red> + +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/events.properties b/src/main/resources/translations/en_US/events.properties index ac6a56e15..31bea0ad6 100644 --- a/src/main/resources/translations/en_US/events.properties +++ b/src/main/resources/translations/en_US/events.properties @@ -53,12 +53,12 @@ feature.events.halloween.event.end.broadcast=<#ff6b25>The Halloween 2026 event i <br><#ffd580>Thank you everyone for your participation!</#ffd580> feature.events.halloween.festival.start_message=<#ff6b25>The Halloween</#ff6b25> %1$s<#ff6b25> event has START !</#ff6b25>\ -<br><#ff6b25>The Witch is waiting for you. She has some things that might interest you nyahahaha! !.</#ff6b25>\ +<br><#ff6b25>The Witch is waiting for you. She has some things that might interest you nyahahaha !</#ff6b25>\ <br>\ <br><#ffd580>Hunt for Candy and decorate your City before the end of the Event !</#ffd580> feature.events.halloween.festival.end_message=<#ff6b25>The Halloween</#ff6b25> %1$s<#ff6b25> event is now over!</#ff6b25>\ -<br><#ff6b25>The Witch thanks you for all the candy you bought her nyahahaha !.</#ff6b25>\ +<br><#ff6b25>The Witch thanks you for all the candy you bought her nyahahaha !</#ff6b25>\ <br>\ <br><#ffd580>Thank you everyone for your participation !</#ffd580> @@ -83,7 +83,7 @@ feature.events.halloween.festival.button.house.lore=<gray>Access to the Terror H feature.events.halloween.festival.button.terror_house.name=<red>Terror House</red> feature.events.halloween.festival.button.terror_house.lore=<gray>Visit the Terror House and reach the top !</gray> feature.events.halloween.festival.button.deposit.name=<gold>Advancement</gold> -feature.events.halloween.festival.button.deposit.lore=<gray>Increase the advancement buy deposing candy !</gray> +feature.events.halloween.festival.button.deposit.lore=<gray>Increase the advancement by deposing candy !</gray> 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 From 6efe8589ce8eee09abb24aad726d1219bccad4f1 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 20:57:31 +0100 Subject: [PATCH 36/44] fix Listener --- .../halloween/festival/listeners/TerrorHouseListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 5621047a7..cc9b5514f 100644 --- 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 @@ -39,7 +39,7 @@ public void onEventEnd(CooldownEndEvent event) { public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) return; + if (player.getWorld().equals(DimensionGenerator.HALLOWEEN_WORLD)) player.teleport(SpawnManager.getSpawnLocation()); } @@ -103,7 +103,7 @@ public void onPlayerInteract(PlayerInteractEvent event) { Material item = event.getMaterial(); - if (item == Material.ENDER_PEARL || item == Material.CHORUS_FRUIT) { + if (item == Material.ENDER_PEARL || item == Material.CHORUS_FRUIT || item == Material.WIND_CHARGE) { event.setCancelled(true); MessagesManager.sendMessage( event.getPlayer(), From 4b8d34ed040539653360f2e752654225ba77f990 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 21:04:14 +0100 Subject: [PATCH 37/44] last translation --- .../contents/halloween/festival/npc/WitchNPCS.java | 2 +- .../shop/menu/buttons/TerrorHouseButton.java | 14 +++++++++++--- .../translations/default/events.properties | 4 +++- .../resources/translations/en_GB/events.properties | 2 ++ .../resources/translations/en_US/events.properties | 2 ++ 5 files changed, 19 insertions(+), 5 deletions(-) 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 index 29cc53a6f..2f2a53f15 100644 --- 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 @@ -47,7 +47,7 @@ public static boolean createNPC(Location location) { dataCorpse.setType(EntityType.WITCH); - dataCorpse.setDisplayName("<red>☠ </red><gray><lang:feature.corpse.npc.display.owner:></gray>");//TODO + dataCorpse.setDisplayName("<purple><lang:feature.events.halloween.festival.npc.name.0:></purple>"); dataCorpse.setVisibility(NpcVisibility.ALL); 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 index d2a35f087..1cd05918c 100644 --- 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 @@ -3,7 +3,9 @@ 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; @@ -20,9 +22,15 @@ public static void init(Menu menu, Map<Integer, ItemMenuBuilder> contents, int[] "feature.events.halloween.festival.button.terror_house.lore" )); itemMeta.setItemModel(NamespacedKey.minecraft("air")); - }).setCloseButton()//.setOnClick(inventoryClickEvent -> { //TODO tp dans la dimension -// inventoryClickEvent.getClickedInventory().close(); -// }) + }).setOnClick(inventoryClickEvent -> { + menu.getOwner().teleport( + new Location( + DimensionGenerator.HALLOWEEN_WORLD, + -58, -60, -67 + ) + ); + menu.getOwner().closeInventory(); + }) ); } } diff --git a/src/main/resources/translations/default/events.properties b/src/main/resources/translations/default/events.properties index 54d0c5843..dc6351b63 100644 --- a/src/main/resources/translations/default/events.properties +++ b/src/main/resources/translations/default/events.properties @@ -64,7 +64,7 @@ feature.events.halloween.festival.end_message=<#ff6b25>L'événement Halloween</ 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=Etage Finale Atteint +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 @@ -118,6 +118,8 @@ feature.events.halloween.festival.chest_lootbox.menu.button.name=Recharger feature.events.halloween.festival.chest_lootbox.menu.button.lore=<red>Cela supprimera le butin actuel. Attendez pour en obtenir un nouveau.</red> feature.events.halloween.festival.chest_lootbox.prevention=<red>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 !</red> +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 diff --git a/src/main/resources/translations/en_GB/events.properties b/src/main/resources/translations/en_GB/events.properties index 31bea0ad6..bfb4a6e89 100644 --- a/src/main/resources/translations/en_GB/events.properties +++ b/src/main/resources/translations/en_GB/events.properties @@ -117,6 +117,8 @@ feature.events.halloween.festival.chest_lootbox.menu.button.name=Reload feature.events.halloween.festival.chest_lootbox.menu.button.lore=<red>This will delete the current loot, wait to get new one</red> feature.events.halloween.festival.chest_lootbox.prevention=<red>You have close the chest, the loot is reloading, take everything you need the next time !</red> +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 diff --git a/src/main/resources/translations/en_US/events.properties b/src/main/resources/translations/en_US/events.properties index 31bea0ad6..bfb4a6e89 100644 --- a/src/main/resources/translations/en_US/events.properties +++ b/src/main/resources/translations/en_US/events.properties @@ -117,6 +117,8 @@ feature.events.halloween.festival.chest_lootbox.menu.button.name=Reload feature.events.halloween.festival.chest_lootbox.menu.button.lore=<red>This will delete the current loot, wait to get new one</red> feature.events.halloween.festival.chest_lootbox.prevention=<red>You have close the chest, the loot is reloading, take everything you need the next time !</red> +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 From 389292db4081b81d74ae0b70fb5911b9a51d5006 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 21:06:51 +0100 Subject: [PATCH 38/44] new TerrorHouse.schem --- .../data/omc_structure/TerrorHouse.schem | Bin 71312 -> 88692 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/data/omc_structure/TerrorHouse.schem b/src/main/resources/data/omc_structure/TerrorHouse.schem index f4f62e7b77ea90e557527301555a0adf216c9284..ed549e5bc22e99a3941707573dfecad82dd7f5be 100644 GIT binary patch literal 88692 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 literal 71312 zcmZsCb980hmu<xrr;>_o+o@DoamC4vZQHhOn>V)28{4*Ry|4S%-LK#4K4YA<_Wt9H zamJi$tvU8ydlN={|Mu?>#JLts>RwYV^x)l#XSBw;$CbsKbM>0G3*}|!SkqsLb@a}} z(%AWv$M}x>O%FTwtInrQkAKX55hwq*pXAZs!6D*-Zyi%lUN3bRy)Q5Uz2mw}-&D}* z($5{83XGa7r_E9ghtDkeZ99;N2iQg@kJR$m-;JgWR1%a^R`V7LyQ_$3kA*W(_JWW< z=fhPLX_h>?)_A*50)e7RfXPhW&Yk@eWkb%#o|AE%9rc~eqvla>8OjE&CF{W7V~Cm4 zNHUdA7#NwhCUv*=TWKy_@MJeJLIXB1!1^s65rC#~qgCA+_dCCAo2T`p8CP<~w)s*h z5RG%~?7}I-O0+}Bxn<KVn7&Sqn3l07>jfZwnd_si?{aujZ8fy8uBjUm3H)`{afkHU zjXeGJ+nim^E&7ZdgG%a`wqC0<)+)tH(S_rAu+2nJiF&lGtL!7z2cS8F&nxKDGS#qo z=IX8r9WoL-;hg8S@#I;L4bLOS+tM|eaJjL!9-V^Q^}gbaz1hv0{n+(maD|%&{|#f+ z80Na`$}Mjra!bc7URZ2uH3D(X$^F6(?pOMLC}cgKQ4_$#i_oS8MD|Ac-25JtZbCob zR<)p}`>{4kHXM}=lXvCV9+}pnw{@4UYym_YXJD}hg1M+wI&+M6!RBjqFV%>}K7FHe zIuTe{)gI^f>WYwf{M&Kyu&%D_lzu;2CC33U*?ekR-aBqj+b{p=jxsxgT<!n}F#oh1 zzUyC98nZt#KGVi>zbMN!a=K7k^@%uHQ_7j7+<G`Xx;PY1ZqL{^htgYv69UsJnXCOs zx0o`L+w3P(p`m)RA~xb4eo~s7*jANskxkG{h|#GQ8(ny}ob@OZiz)vTJ+rn(mXc@m z!(Hp=jMra#?raUZ1utoqtm0Gk2lEzj9b?15s|%Q554L)o<gLbjbFzw+>8lmR3ZNs7 z<2f}SW<EbRa3;s{`B^9O@{?lax7pRHSG$Z4Uk_P^82?jNjYtTGYE9X}1J8X-_8FjE zd+X7Fpv050uxsLMyvoE7nQat(aK)*UZ~u`<nmRD~Oux{!Mgj@DV9b&bKQQoydw>j+ z{BQdPLMdHon7wB^Xa>9l+r|HD6pF3g*carpTYAnYdM%ewA$<%k**15!oDq^{DEc&k zcs|&FCm>VL8N)Pc1}kDV6D^Q1_Q09@b+M|C&WDQi)pkS=Nxzm=AREmx$}?Jsr3y|w zQ{X3x&<WUab4Oqbz;?WQNjLB#E9)tHbxyC+iuz<s&C0gVvSor3f*USlv-9K;l>U46 zbwi=XN^-0|QG6l11N*{79D*}hgDI;NrYlPBPo0n%p4%hs7uzF&!;(08s2WUZA{#3n z2!geTyXI10UzBTRr;(^s7B^odtCn^ihdt)vwCIOL==1M+=vz%sUoyRKo3y=ush;c8 zF$wIhLjP=&c|Los)xn-(Etip{<>>?z<((<vv`vzkkW+~Dr)S))Q=luI7w5ZVAmQ)J z^cSa-lhteYpNSv2pF43-HPGeAubIYsp@IoVFrdR|r}3>rMmlcX;8rRKaAxek28McE zYED%zc$F}3Qp(?#AgIW)k2X@Ba<7k>QM4k7c>J`8ameo6=fa27A+bABw;S(E^2=^G zD4g;If*{SB%6ZY?=}?pLo+}jk%n6LaO>CPatOaT_<vbA=cwvC)LbvvDnGsn^E9KNX z?;Y_=%zy7AFJCBH$<c*oy`3|%k4!YMt1Vne*s!X;yLG3`MjqTvKXHs|?={t5xiNS- zf{9bQbuFY3^0iNsaniPDg1}54o=FnsA?2^R#M{=?sW6Xp=<3k*0dgL&(J%gzcGRJ4 zJOuddR2oN)$E8oJ&Xk#z8iGuN1oF)Y;w<1PU_KR>zt8I2i#%H;7?R!GycFGnBxDE* zN@X-O%XEdelr@zljr9y`%l5HWfb64iV#F6PRlTW2{&Pp_3G0d4ze`9Q#KS}a8b!zK zdFnf5`p>49gxjg1Tad`a@N*b$PBHL>8A3xf$-==-#4-A&dEzHyZyzKVTmAP<KA?Me zrrwv@0469r4g_-*CL`|Kw#UCBZ=;CPsPo3Z=7~JfK*FMo#z6g5Jb-kaM2+f|VitbI zGONg>cDGuV!9p{2b7~<C;nxVyk&3TI5nQa&<^WfoV{@`Fm|URE80&^yxe@gsep>$f zZdJxUsv#T%kQ5PW6pz>%t*~9asnMu*@u)q{F>CALg6R0gQ-!tx7;wPmF%f)|WAjAK zw^uw@(NvK;R7{aoX#s67_0E>{X=XeynJIyUGt>BMBK?Ye@A9FoVwCs$k0Z??rOLC~ zK_{stZ6b#Y8E!|hVAE|g8_rQZ(zbD<#b*kWBxK?%Y>Ot{_z%>!)tgu4CH006A`nqq zT8vv$8zM$xK#N;y%<+h^DnSVoo}{e#Py5si*HdRfreEuX^xUbP$je#gJYZhjHN&ML zj&7XDSphL>;f3)?>J?B#0%PJMXCVoBO1K^y)`d~OD{6;>1#VibdvQE0v6#=*w#dX{ zCblq?agFPid8>kDTt)@~JtD!j4&+f7%>BiLT$T{H&IS|-qtWbb)fGSb4Wlk$lr|fA zepV{ti%Z56b#+THpjcrmnCQbS=mA_Vlv0xVA&E6$B<J6JZ1;_0_X&JSn~@|g{kZJs z#O;y6>m`J#mC~kQfKTTRf$+%8qs(E5C}UfFeSzBT?c0t5y8Sr(KmY!++f#iafKKMm z-w#|i7R?vInh43*_Z?`FN3Hla(v;rl&S*LV9rNw&z3M=b)2#8LrV%T!L7D{a2Lvzb z%$h3?A6&h1hJh;qVz8Lyac~r2K&@jdoCyKEKPd5PpAD+&&W@rLeP=o1;D!L%o^yTd z+SgldgUI^?)|a(2kw#rOC$ygKEH3##f{3|_v!h(HiqgQId)H1VVvo9<rKPfBL6Lb7 z_Qifiw%@TXSJ|B>6t=G4W&-5}n}VCTw){@@9MJd+uu*iu?FaTIUA?8p$ct96jXlck zXp$3D)weJFW?3^G@t6ezO#aoAJsaDTDNQL3+uCwOHHxW@{hO2XsdRqmu3^LiW^QVU zMhnlaYNS~Fv0pnjp~k-8B8Z~Z4tD={;TK5)9_^fk>aQpLgiMBQ3Q0bmJN#prKz#SG zT<2wnWzl6RX?tCL_@TqWaIZ1s5T{{A#RU!<gYS$mj;iN1sur$J=KQV`P*yi^u}-GX zGQV<%fb}D%Ehl>_{u^z%2OipM2O^h&9dMRF^S_Mq`(94kr=_D0IOGq!$&|&P>hz~= zEAvZ!c~@)BDNw;0$Bcpt=_Rz~jTH-Ly(5UHT3(F00iV#y)YIz!ytslKGyq&@F5e{1 z4%mNwy)h!(GZ-Dk2D&W=VS5X_i4f+Il)aLS-O~mNsoTcN=wq*|p5v<3IRm?(M(kI{ zd!-aPD=ruDFAJ8U>^2+L(G}Q7uMqw5=87Be)<ylfm~co|^Sn)@Xi-~ic6UeVy%@%d zO}%(URC)3#ghh2FOEu-NjAe~0$Z{4sM_k+p7cknLJ7~5<V=Wv!I=5zqSJB{4f|{RW zI1&Wzut9g)33$}#leS^6d_PfR41>h4V3Mr-cOw0D7fijsMIP4F(ciy|0&!H1YJ&-t zc0_JU;jV;<%oz-HjKp92U&anzmVN%P3qp_4DP!`R#~(f$HZ|9+q&p~>0M~|<PKVTt z>G`eWhqx5I*7RBW>e1D^(o19`@i!&gE@cl(l@F_S6e-de$N5&3yw#0%cP&9C0^6#6 z1fslaeDJeuEs<<P6FxFSw%Oaf6z^^|hWQFMNPAt3zGCu*#~SZ5n9}ya`sJmHWI8OP z@?rRbV<oIh)o>Z!*mwkxcHjB=hxG@lN1An@jrLFQW>xGmgrUy<c0upvo@4Q?*?DR$ zF<TqkctKPd;!Pbv+5c?f0etnG*`TgPcUCE}!r;blLC#9KzCi{X+9-md+LU<1@4L@+ zjxd-DgL~pyUP^(n9sFEU^@cIz`q9rh(LB)&zn@V9Dgr%uwD6kON{?KPIdo*U=z4#C zvy3UmNH#jJ|6p1=zT=N8_#&<OJ7&zUL;V#a$m8b*uvR(6kjgC-3eWMKgN`G-Wb@3( zN~Gk6dQFC#mZJH3!NyY@2<DaAG&NhB@@ri`Y&?sm&$4+xK49$mL)H3LJM~e-V6l$+ z4kBx^BuF$v_Kvy-tjz4&=(?*OVBV@-Z0*jQ(!rD#iFOB+$!8wv`RuG8UG<*Qk@5jT z6nszy3<6SaGH!h!AF=b2=R860uvX0Bkc(dt*{M*c5}ycUvB{r++U?JLbVL)B7odd9 zUrP#B10AOe`X;GCI`2Ij-7$)nA?O=;A5IBiV54D4nrf6pyup{RhGc-2QFaTO*vr>I z`%b3wh0dxV7Gvler!GS6M1_^{X916WtBl?LZ8t?3=3i~HI>>nT$E=rn_KL@8qTCYo ztGm6o;JgtD*?Px9dBMvx!?S9={1lnij+9#PqfSWmpbdU@XQnXaY=EJ=he46VB;N2% z6OXh>MldF;Guvn|0%Nha8~QY@tv_!$fjk}&r?Udq7sC1ijguj_q=CtTC|o`3(C;3A zSk8qOX9%w05Cf6mQq$oYAQQ;!97GvfzzO3)He{{4XH_$Z>F8Bndwz3CGT*9g(lwlY z33mFezY8s}Y(2tGc4u)jb|^ddDHi&QFJ(r%CY^1=Jl%*bvQv4$73ifjVBEsIf~lq3 z!@(W(;adtFAIZrX`H_^m4o;AJPAQdz1LIF_fC>!sr`;o}u}NNjjKVUKMoQ+`f%6D$ zfV~>Zo29TcGQfkb`}O);+3E;41mcSxY=q`bo&*mp8I~Jmzrcx%mlAdadFls8r}po$ z7W|+j0RXrVwO>JPK<XVh-5%Dt=STuLOEmka754nt2>1}+7gt60z9b~}FfBbwjxD93 zg)lcc`cPQ<?l|TYt|E<251@2Nf(CQKYGss0UDL6|H&;#v9^EN^2xlX2rgDg-IO#GZ z!a#H-@>f_R$k_AyBKi#1U;iFe<Zu-`R(LfsD@!@&co-&J`7F9vPIeAI@&F2Onco}% zu8hCcmZeRH%CLOMTHVIE5Xqt%&LK!zF)~8t1ZTyg@{@Wa1dZ9-S-^WOi3X@lN-NNE z8cb-QV}?6S%EWJ=?pNRxI%c@TMR|YntIUMrhTaK~ql?xz!b?ZqHJZdUZM9=kB?z{{ zRQzabmf)Z{(p=O+9fDFFYLErP!7RTIv)B-k#09aR>L*nnYCoeY7xC*<YQe#M9i9x} z&evn5=w$_c##!vy2emmgy9MR{xH?FZjJq*bp*FSKa%_~WTCdV6z>(}KY{y`a3IExF zyCiX`G%h29vjlV>MVv(}2Xv%x(hPubHxl_L7ivG1V~6L|vj&(HT8Ftf4cbUsF)>!M zG;aHk#V-KLvr)2x>5{lDFKvjK3+)^E74H3=?5bMEs@tM~Ch~r#rEH@th|&3*2%$(G zuIOR&{PUd!l1{_N6n5*>{pX6IxE=qC45AgNHHUiSj5Xb|0^Yi!_9MM<zq_Q9v)L#& zx%<V3WvAB(^*NWe^=OrTj0G&7zrB{njwPju!X<jG=Y6j2y_^UvNZL5`HA@_hgew|~ z!K6D$_`g}KQzAtSYjSNdQC``oMmRKcf9^KfIfcw5Bd{!SkBGt8@w$kwK?wdyqtuVA z`qQ(XwgsbmBnRzmD_w!qC9z0*1l+dAe6;>{88|fl;M$AhuR&*opMK{dxNLD|>MHBV zsg(9hN`vVe)5rqEaYWTxuaa}_k0wcDI28;oMGR(yFq-6P1gkNJEevxtd!2g`nRIfr zp${e*p<EbMN;{v(Y;>w?=1;LBMU-dKz#)j+8RaZDHiGZvbqR#unF$Qz@5EwMAp=HW zqJ)HVnUOh0xu*%Fu7D$Sf0+p4%Q-Bc^83B+cZ6BFlB@7pxV%#(CTW-7RLcmXQ3}JW zQx{1S{nta$_DOpQEH+9oXsAJAV4cUaM1B!%5`@2T&Vh4VOl57UU&G(JGhDg9oJIb= z*7iUQdF3TuI45Cm4@AY)1vaZ*#t7e3HsWI@c=L`Bh`%J0dxQW}$<}1QwQH)T6;?P8 z;kl7$@0Ob-7=K6<As&T3#@<mvASbhD@@VWZugQXG*qf&59(^hL1<*yk%Q4B06)~xD zUf+Adk<Jb`^zlMW@nk>8KA8CT1q3f$x`X|K!$=ap9bc(WY;uE`<lxts(;GQF#+NK! z+)H(jj-Tei%R8chtsMN}o*h4p5IueOqf49kN)=Yem-BG<g)|SbIu2`dN^v#+MWm+| z`DCwYTN?pT<)6a(gsQEu*@6E3qNsKKd;Ig*P`>|qK~|G7BaGWXuajOG(*=4ypv=Ej zrBBveq;iP%PFq>YfxPQ|fu;nj6Np<ey#G(e7_h&b`?*#^+g&`LJK^}tqhL-PFC8WP zTFmMO!y<dna$6p}$4zp%MQ`67b5-OU>`go441j<~JWUhmJXYE;7E28H!D%yE#T_lf zT5cY_RbE&4yo2#az=pO8SSRuRn19n{Nzy@@V;F0_oh2ZfAQ9I4L>cb>>EcJPa115s z@7nxVqhzVD@!>bo0)K^5SLg7(gXh&j=QYdpu`q|=k{VT_na|cTjP36npKH?ZEjFG$ zJ1azUrO3W9PNKi_`F&6<*CQjC=?9TVSEnKe2$1JOSXadw?-qW3#Ecx<NZ#Gam*H5- zbYIu<ro2k+&9ndsVX*BVD*E1rv3AhXzrU*AN=T38;tP0|H(UdBZ}_tqS;TPOr+km| zO7G|LUn+*)mt<wVs(52aV&9LXX8xw#cgr#O=OXKjU!mK@y`;cleaGud@!OgZ8ma$= zC3!+yG=v21TkSt)4IR;48<kK^?8Uvs^TktIIRHueT7QO{3)h5z5a;wsL4^kr9mQNm z((8gc4IV>ZM%iB@4+#Yiz50pcx*qvvo#%&1fdKjYg}{EBUG5LW*M|^9j3YY#Gy%Go z%e}DNS}eBHP{1=OnUn|%B|pQg)qduy#0!Y(dVpU9M@Jj$krl<-gszYboo^+gEGNZi zksR!aQ4+0`?)bClv0*IrN1gmz5{*{4wpOvz+meVS_vGYfvEv+B?2OHrTCc=z;8q@Z zgHZIt(?~BB)25I3hG>BveQo`2jIQ@lOtMkktKyDlxnaee%j14xyrue=nqr<(vM^C$ zcj9jpf9rSluTvy!)OYE0DpbR^&uD#WSs8}Qdwx0pK^XjewR>5!W|P^CPnF3|BfpU^ zt)>tR-S?70^lC$bujUcnp{mwPNHNU@VL8iC9pcp=QKA*hf0*S+Xq(i_lqBn<;!hNr zoff2inO0X!>v$fkr-P7+#8UmEE9UWHc*7eFZt%+f`~^y`X`_dll-O%(HszI9FnAcz zqs&Ye!LWnNZxr;5i{h+<7@$b(GQWW5>OHPR#LmL$cbZ7Hp>-a_XhG`R%8w)BD}PK} zho8`CpZ=&f2o<|c&0=K5tNkNniX(0)G_2AJD;jOR?F{70UiVNyd<Er4`mrMkrbpUj zy5ZIGj|UT7q%HSvRO_?`OYY*YJ#}>-bzG-J^HuUlPdG7;y{2GA<8hJ#A&K=UiKVA` zMnNWZ#9S2uoVFD2wq<2$GHL0gg-|9Z<ZcJzC;HA_uR#Tccvg~jjtxJFw7eC#MWJgr zHa=B11O=)?_ZaY0tXG9}Bcf9t)R?|gj;xl9!O>Dm!Uz)0m(6M>7cNnvODqx<v?fG| zIEW`I!Uf5Q$Fh?TcA)~fwbc2^h**s(%gC@SBKB)+i`}#&%0$&7>$KHzQnQ<IZwXk@ zb#2&2TS?SknZGDjcnm2Hm^o57jmUBA%jXs03_a8(fEuu}B>{}gCg<mi^sjA;?nZ!O zkrVex5cX-DSTV=sxSPLv?jIAQSkRA`9Qub~+&OS=F^V2XEyn{*wKv3*$0G@B)aSdq z1r@N!XszvP@X~cD9%{(noi2Q$yn|XWN$}ef`{y$L&;4sj@V%|~!D1%8+g<)3k!|@6 zBh0n?-%~{~3>>2bqgAblAzs;~_OLCGQ_XnII5(zHh#5Yq`9tiI<3~l`V)1454w%j_ zFF{5WtyF1&wpqD@lQzu7&^py8LHA#^nEgr&oTG!T{ti_~FL2>1srxJ=UN;^+v??^A z#gh<vq1sTB<VcK)Vp&oZnuuNOuwCGCSFH~_!_vcy^JSV44B}YcsO*bP7SeV6=Vcl1 zAm;-f+rwxY#fhi%(KlVyf-`A*JwEoGf&`p7+#cfbKt2at>bV2l#-A9+n1pjbX*vC_ zC@EC+GMAoz35k}!VE-7~KU`OggQu6i#>kbYCU#&5)M`hcw@$iVxFkMEzcq-?96z3; zJTGqpS+zFG^6q1_WRSD;2={Aoj*`391Yfl5<#b8!u=_T_p9?L<?MbqBvrovut&xRL zPDGv|@ns`0>Hx>7SDCeRFAjT~P3A7Ra4YnrW@0UVSRAMB&#ptn&YZ19Ae6hdG5pkH z?O$lUuF4Q+4k4tjXb|j}xp>(qy^I$@!as(p@TPx}Ukm4Sb~x|YfUUfViB)O4es_Xo z+C1j_Hfp}6XA!3k!WxAkG&)~RzFMUdhqZ9%;w1E{ve@?mx3mDv=)l%is==BU!Ek{4 ziqYRlwtz5r{}yJoGMty+_xdZsK?JDLCsw-t^c%0Cig1k+VI?OV=cpr9v&%+T-|wmB z4H)^t4$gD6B>NN=q>C8xjU@(SMMW$`JP_X|%$Ja%LV*1dkCB|}>kHYG#i0-m-K2$7 z$c(e>?B+{^=-7|P<O|(pWK9<3lOP<gyHS)k-()#jn+#43VHuYD$5aX?sL8~|sI=%$ zx?y#bPIK~4xQipukh(rqhb%q1#b{pSDDg=koQtrPOU0;*1&Q2H-T6XYpn7svdhRE^ zBG@K<uYFB2_U!(!IjZU!F={5+Jj=ymoqzg1s-C}GLQD~55Gz>esI)E%GgTd4-uE=D z#ee^L)f%?9NJPC@ZjBj?Z*(J^94dosku1p7rTLOa&J16ZrD9YNHkRT$J9Q?xAL<?* z7=S}=MOC3tq4uY^Q9g05B)BkfQb1534Fo*AG9G-C65d~!a-wt!C2uCH+)PzBTecce z`aAHQ-1w+FQsN%CA7c4&yBh+2Nzt)Eje!CNs!|bb6_}GzN;5s65Z_M|P)_>okt-zY zE2S_FUkXPeaj#D*$4f2~8Ki)_oDew4KX|T+Q~zVRV~0$2*ABq^*=jCsd%lqz2fxIz zeM%#l#mh;)vA|Z4`-1w^;iwumG-(>h10(~ak<4M^#z%>z>r~dNHKgEz9vzGf=$U`6 zmLx|s?#mtS$5Oxs#YkR;%Z*iP975)e8?6A1$}q+hyj_HoAR7O+J8{lyeKY?x@E0u- zk`lI&*Wjc*FI->xo4LQY;mgVEqkuZ!3ZxK4a3fvb$QQ&vME(P6!Z?gIC6!gn7sR)3 zUti~0Zz&rbKZczqLH3qcLu-LOhw+ZomfGZqa;D#H6gI1i=%?am1@Z*)sAImqVAu*m zj5L}KJcebSvj5p9KRY{H7$%J>jN@(R=1L`>nd`VRS=_A42CC8KV;DS0Nac}`iC*}t z`Lp$?`LYX<7)Qm6tD%tzse^~XB?pt}k>`I`Eh7U5@R*yd(#=~pw3b?_)pKjqHSHGG z`%5)b6xFC>UJ0ZJUjSTDC%gszp4N|m1yqnrSS{9(8Lm`IC15NWQVBuh*rWpbXCgf% zFs%&q6n^}Q!JPruH!9TT%$TPoeQ2W>&tg%iUh|)${%2CjB}g5Xav>_Y<X*@w-%sa0 zPh<f$Z!Wd1w@6aT-mI(N@E`{tkF-cy30jp^y5$v{P{&H*Et##u5W}w!TUDIz_0G?R zus~NbZ;=#P<(${X8KlCQ&qnf(Z2MOF@Y{Amz<5yHR#yHEyXgw^lzZR;==TT$%YiYQ z*a+-giBUr)$8r*smx|BEHJ6_)*NDjnva5N-eIKich+c)MU#zDQYI`olIw9fLCxo=) zdAuYOT4oE2Ob*W1C69mP#`oY{=baZ3AI^?iNp8faN<!CeXE!@=JcnJ44x;Q?ryL-Y z87|gq4JeX`kc#$BFT0sCp-O4Rqozx^9_}1%BGv>6rWjVqt3xm)8Ko(tB}$efbWIxT zoruojKQStxa_c5>E8uV=qxphAFbu3sV+9ox%TBPsi%ZajfwyZR?rN-bmw=&o+a%8G z9b8I&(6`+xS=-2qp2yfBAq6v)7Tf>D^|!$>Qcbf3AhpSnmL3NLFry|1;yF-BTkJ$U z5n$UaCrhN^3}Xdh5|hL<R^nMOU(|s%4-q6(Og8QeoT-hj?20pSANBeHe(gxVwrZ4x zwG5WI6ImWO*D6e*c3<))5rmg93TM`EYouc6?KSFy`9pi}QH;%FmE7@8R7g_`)wSXv z$=~{`)2x*UE@IkiZYx+dXwG{iS7J`Yxkep<$muk!=;FgH0TRvNcJ8d7NWK28_8B_` z0kd=U=ecC+M#7L4BJ50E6N0@`l)3&j-wYsB0x(E7$ZFv$t&;s$=c;xj8-+7+RGJUA zCz>EcU@Mx?H~E`zg>Zm{2nHOXbq$P$c@QAu;Eg;aawJ4Gw0dF{b+q)i+KGkighMyD zb&8?zO`7{IZE5U4{7PO&fKwl*KHI588ZuhjV{^q=dopG3bSwUtbCD_b?3dGzLpl^k zeW<%CPANpp+`gjS^QQRa+C)Ouc~xBs;Y9e)!(3e=e`tqIKKpihrRg07abpCgv7bhr zzp;amW>=K4YGK=LgM;0G!7xD#G$|}UjI>6_+d)mryadtt+igmTc{`|oUrx-)nl3PC z?)YeKE1iv}F(j@ZE3hF#Nb75+rIyE2cuM_{%y2N;lW;fkSl_}7z>N}>{ECyO%js&& z>FTmX5&z6mu~FY4g~naz4zJ@R;Xd`7^~(-|CN2}HDoPN9VGm&7nf2#nsJ?R-VW(;$ z9+HY$U0@W;_7X&W?v=#N$kX?h6W4bDIoY|uB?XOy0SCrsknbBJECvqRE<F*Zx~+k= zl`L;;-qv`)Zc7~Y>2V76K2<u^*vMSe3eYYDmCU0l0A=JnH2wy?1luwRpLu|d779v4 zv<oe`@NZfevy_07NhBE1eFk>2OFaLNAf~bxaxiFY+@H@B$PAE#Du0~c&c8z7bevcf zM$PjaKcrN3VPHio_<IXar#sJ`DKCv>X`*X}5sFgQzHONaxm7$Qm%Bdr(1lbK!BD71 z{R-ydpX3|vXiy`+BFI^Wyl2R>qV480%Q|Mg{!9GUseL4~fd+MKjb~gPxC2{2vEB#J zz0YV=+bLxWlB}g6Siugl;qN^5-c-uISv_gOfz41S+o^KY>eEg$a(*&ig@8FNi~)J! z?ExN~9eaK4!dd-K;{tUM*dyG{O3uqxan;swfIL)~S!sf^m%}Yl8Fo2XTEd`D=qg+q zyBH*omPRDN_+B<&t>%S>QKi$K?d7U;+AzzV#;C@ETXbxiyvR$~_!M_b>@w^^EhxJ4 zaD`09a27FnC9y<yUI&K!B0w&)uh5)8GVNmzzXH_$0ebeULl)W?DsY@phA-MP)ftzA z#0Thf8|>7>MM9l__sh`6S~4*Y{-G6NXoJu&sb^whld?jzievO<cAkgK<JU>jyjGsf z+qB1y&}XMbjb01SQ=ya5PEW$!<i|4DcZu3adxsl2J9Btx*`#*c!<Tbeua1jF>cKWD zdVuYm9;&uU{2tnl25L~QKfSE!!&wV6gzSWRuZ&sMr*#!Cp6k&q$VcXGer)1Ggjp(W zZig$(UH<U&bVu>Bms0kCu~wSxG$%R>t9Ttp;7V2z0(d#s;X}%+9jMro7KRlGvCzZ> zPJ3ykGf+d3D=I`$L`eMjYnf1Jw|c$k^i;RcTd;$QLx?XbnhfQj>b-zcu_q=DQzj~M zamyhcIm+=WE7oZ1EwSH)zz6P|is*55UeR{Q;n2N7vf(ABma0**Tfg&@c1$ZbZ~W49 zaey;!wZEZl1uM}9DH@iF&q8L16nPze6A6;8J&4SX5aB|hilKA8QH_IVK!%$2!VrMm z0$q<h(y3L6yXFVUB3M3t4oIz2Lu0v$r!rK?8lR&w%64d3Bcj+zF#jtwh{!3DVvUQ& zL%^ehfv7@ll&xVftd<H{b&ixwQL9Ra5izL$Z_WY+-AGwE$eX_0Tu;gESeY)8W>Huf zvE0#7E9X^5IZ3tAkjiR79tM3{!ipZ@<e1984R7-s6x=uucw+k(4;lXKi%}T*cb^!| zyr6<@OdcSpV2`xn<ak6)*=*ndil&AQ1B~7jIF{0><%q6|g|xh&lnVhCF<B1cP}*KR zIOvBKF-Jc=zJ3lO;aYfx;y%5;=Bnr^Hu(X_71Z)eY2!v$BHl2ScbnBy^^<B)X4+l| z%5Jz9*Z7qY9U~$CuoK8YR<4SyER%P7!eX2^4Yr%_@F)QU0DFLmXkF1Nr{>e#RjBGl zeqJN!w@oZKWkdNDQj%k*)6reWc$<-d!#P+@ktpoUyz=?!H=T+R!^4bt3XhdPes(Hb znRGi>2IM!G>yH!N_2e@^Z{%0qzm`x4N2UGY1t=|IyGuK|J|sBir3oXR(9|j$IPl%H zbm?oT0r?uiY1Z3H8;(*?To-F5m&6)M&6!Ev;a(XJ27V?WG3ZJ`a*ASz{x=r>gN%Q7 zgt!Yy68OQEnL+Zsd*_1=g$AVw2?<bgZSQ*q#8uErciXkTk&v!Mf5Of%c4Vvqmo3+! z0#B^^>OG_HMLpYEeVO>Dy*p=AmDwrc@=s}X=O!?9EKBvyGEo7!^vyv+z-eMWQjWkE zzvu9%14U1$T*<qFZ-G=As5PgHWuW};^<f$Pbx!3pQg&@CDC)`)DFclbLY^Gg0<J5G zP^zuO_X1QWTmq&^Idh?`wh<Z`i$txgr_1=So{wwIHWAXwr%xFg%_AEmymXiAtp&fU zO9$wGbD`#!qf(ZyBGo31U6o35dC|bt3G%g^u)c9(5y}j*l+Lw3X$Mzt{@{zjr1Nd_ z(CM)M%C6DEhAu%=7ZEXUn+RyXcK-s)UiGc{{4U?s#C8fV)N$K`VXe1o2?iYSa&3JR z@cdC1DJeeXpUz8~^Cz$crj+rd$-U7CCQq51?C*kHREbX4Tau#2vzY^!8_%P~>%mTc zNMEit96yO@kin@+t*s4a;X+)oLGxB-u+7xuBo!+UaLJ#u2_%^U;URjAa|2DSNwABZ z*H3yX|D>s=(mQN83wCk%`j96pL0dB)Acr*@UcKTIk&6dw_4djs@K3-0B&gu?EPSri zCd|eM=3eXX0s|~2AN^O`jVj~MfwL_LuN+TRI8tnJf=X}QO-;=GepHMnVTbQuIia=t zV&Izb9CvSp&o{CS-f+VQQw`%MIsIeOtI9s1<=%M*{H@*}6jmBgr4AZ?F*fhFQJh<^ z3wy)e#nwQFk6T=#tPDEKd)w=qbe_%@UVcuPqoatc_{<!Q<z1?EJ^#~PN6Y^#0slSt z=oW_s$H<VMl%5+nW*ZVyLB~5J<s>29=-p`DArPzSh<|TJYX;YRTyfE$ZsPc`Y2ppF zt@_4|Uhz)0Yp~jMIkTSQwGk@RQ6I?0<E)#J)U5sM;pD31=6FQZrt^c*QX;}}&|kvf zB53}~9Fb6WDW6#=qhAG@NXX*@Q5uOWdbW$b4mtP5b54FdXH9mVm*$e?@E~)~#?Dx7 ze%OH}%Cc}0&Nq>46$vFZzIX+uq6hF_>H9>E6b1h-B9SgMu=qHc`cs(T4D4RdgBJqI zkRTbap2tZC(rs#>1eFl9?s&y9tn(R_42#UxW_^Np)1aAn>^h!%A5TjhlUE2ldo>xk zo@LP#Oy<-0Tkfi?In$*@e=J2SubP8enz1}dM;r?K9W5>Nwdmuc@$Zi7?jdJ&)bP1g z*t{iLZK*g6a^j08mp<_BP()5Kw1At<UkKq9l|*Qb73xX%oW!4>$Xulprb0pHnD>4! zw|uwXg;|y4@C;W0gZu$#g@rEtrFS~&dSfUW5BL2hy9F`VHEUF|$N2)&-CuV*tWu{7 zOK7`@!6j3Hwp5CKtL&Suca_Kurfa92#VvPz?<)FCTPaD}dx|z0kflW~5^yOmA3C>$ zO{aP1jKd6{D)d(9=0zK<|2ywcNwNgms@Egf@geXj+|5KZ?p!)wF#o<>)Y6K<6GOl7 zt|(8EB<Zu5=;xcb6z3%-`{V6L`2HuBV~A=9<(;5VYx$8P+s;;>Z&BbIO#Hk0>7t5? z^3ph0wjw^ph5@j>#H2}POQYHP$uXyG&dGzACIfRL;Id1t+h&n}Yil4wNQN`X^*JI$ z2-a*V|JB3>f_-BgH$?uUZdahuRA}Kh5-w$dGIo+Ev)8?btRo8#lMS9Vx_pr6hPtU( zC5_KL;CZ^ygGC{5sHka?-WEVke`1+}nvE)&^ju<_`;+h|As31S!oYXlU%yzTM3f?+ zqRUyT_RSklF^2pIe-7Id#aB(QFzmcZcHDjclZ5A}8|8Jd_$2T*YgWj7t&WXU0v5t1 z$?<IX*XOea@r0k$7e8{K&Iit565&0vDY3KX_P0R1)cg^@BdRKp;IDEQ2=wrien}|~ zJPddj8ns>fZMMOW=}0PiX)+qMubwsibeCkeJuVvQkZMIn`n#H*0|D9RJ-atCx4jlT zE~_ib)-ftCBKk3PMg!~CKMG|7eks{1VY;+T+h==9Wu^#q-Q`LKnnGop8xIT()y^@B zbPIn0X?DVtTUJ-pIS4<N7f`t9i?$A_NQ)nd#gvvdq|z0;S;gtWG?FqyDMiJXm5GQu zJ5uG?8)$g0ORhdDKwc=5b7RhEYqOBS#YOq@--^mN+e`xs`KL?PQ4jOALPNTJsQQ++ znq0fvg*Nx}n6MC_1A2A;U-#Zk92%k#V8{hvtMF~x;W_ktRaxn1`P%m9g?qHT{l*Ux z%@Qlp*t4wUVp<aK&vx7da@Ew@ra=zMPi1?3GghV<j@Dm3M{DUSAF0*a6Wj$u17=d% zp9>+Jg*Ya_g0(_8p$s+^+T)m2ziV&5(x49oY8A#6?~8{|asWmx=`|jeWr_ks+k~m@ zn#%8u<h=X$mmTx-IU4O><%<#v616`cu!<;T9JX&q(O$psLACNo6{EHALFQ82&ZO)& zZbr*3HQ$fK)?3mKv$jlmmS_(c^VAjC(HLmWjyT9X;J7(n<E6>WcZCe2F)T-)hAt=v zAvwy(m3A}aq|dRE#s4|W>h+?evxdn1sB6L9WGbvI1sk^i0~@CuxxF>}cV1f*z)Vl3 zw;X30f;tUKrbNBPWCRI9ge5PZ(RSrM(b?Ye=7y5cCte*EfJRBVJNg`70~GM@?r;^2 z2>YQ6Qw$J+;YcyaFf7zEjqOvFgyPdEQd&-Sk#FpJGQcCx!qXTh9_~7>GH&%4`u~{u z7f&rk-*<NwW3}0M`yJ}Ab3VzDS;T+@zgvW9YfK;(n5@lJ@HJ>`ozACc-RqG6qa5VG zD_Dc6>kb_oj-1Dg#;vtd&0<CP3dFgRkFdPEcKA4=@CjIGgq2YVeH?cFKQ{z__w>ji z&IAC*bx!bFk3+AqbP+Sh$+n$rjem-*IL?l|zC$}XJ3of-B~L;Qf37~N?5kG-mhy;9 zGf=mU^c=Ljw*{1L6EQKRY!M&I57+4ncyP(bB@RRPk>+tKxiO7@mYrS3mtU?>i`c>W ztAzjdo(U*raeFlJYCh*XOBp;4f^C?3f^UcsRATpYCU9<<18MtlTo%?<YCHcKb6?4M zQsPyNU&gGQCIJ0rd;_4@qlZn_nJ51<OsFfq=sdsE6^NJ{AWRs)F5%-8p(%<B+?_JR z0cAa>bhV%4RpH^gyfmOyy8{=ZUr)eJL92}lBnDPha4B|-4c+A)d&?HG55+b<wCCKG zs<-SajE6cGBOw`^*+q8h7x{S^hM9=R@ApfeHU@X$`z_R9T!Kj{d1hC-BFBuc`yISy zI4)Y^*DAO^&EA==2p;geEo`(_T@p5G*lmgGQojTvgtTbyqmn@T!+_HFdllN$Ggr!G zz_I(DvgUes`oSm8|H#LGV|}lwZ!AKC6yP@WS>b`06y8!P=QaH-;`18hu^Ihf#T48C zUaL@<ganey#2YGV(>wm0;lElsbIJ?8$Fh|L1TmY{7~%p!5ACe}V8$5<h$z^w(eTU< z-!0iMoXXaV52eKzFl0Iq>o2(ytdEM#2#J=%rwa&&vwxjU4#911^Hg()>lc_WRDQ1L zNQE8Nec0@Mx#dLps(i3-)~P#rHs8DRt(&gNKw;X9mF2I(pAS+s43|0%kk}7OP&k)C zY0fbo4<7{0OQts}$YWr<O1{IBZ_32DpL}83Z!4lG78jp(IJd`6^qtpn->7v}$GN__ zR=c*3{)~KO&~?XYQ&6}t)Br7U43WE8O-?3wd0%XPlX;ph>}mKw>no7s>MzA(;cQeW zR9USD4F1rq8$BZ!O?eO}fYXV$#&zLNYVvtWtZ?kJVq_Tv4p{hAiq+~n95mfJU_+Ol z*KfWQ&|y)ht<M2)C4A6pVlgj0<PNejvK!Wv8VSXcJ8^_4f7e?cm%o=~r|-8K9Q8Ww zwim9cmiv_40VsCF@q^~9b9l;O8ca3K*D@YveB9IJO!nv>^b$r|>M}U`*e5=jm%b?o zP=Yz7Wf*5#Z@n)~m9n+cH~o%qZuf9xAFJf}pEdX&&WEf9OWCXuDmNgU>HTo_cn;rd zH|!i<JAPiQ^$3{zUF*(0D=O4VB4ef0l*4?H#1<i2hhz|xuE1HIIZ;zTq>tlfHc?Z- zh(qCxI!Xq^XDI4)u9Rgcs+B2QGuD8tY}9h4@VOl&x%_C=fvIL?59Jz&S@Ze*3NPOa zuSd+ex=)4E0J;0F^HHUaRxN+(S(aVG#m_SrkCAGMFZyPerMt&0qM<r=AN5({!Iksf zLyjHpsaB(@nG3)tnThS_lDd?dI%?H|)vvmEc<gzk{!CkzFuNegV*dctZ-|RoCG4mS zV%NrTG&cZed6<643`_*U`zbP7zwQ)wl-8{Nd0jxn4e2@mV{(wk#4xY$7;mk)NVL-G zIC$0#qO=VnHC1zLSDs!{Z;pzA=q*fKYP21UO~U`<6`nX4^eE9Pove1zBpao}L3jOI ze?AOZu2&~Z>TQQJK(EXlmpXlYkE{^+sQgCy4&bQ7fh;kb@0zj<T1yLn&LF!e#-H6z z`=P~<)d+t1JZtM`)OIj_6ui5)KVnhT90z`><pS9QXg$=lS223q?h*I-6B0P0u-3O` zoQDf)Hp%?4rAckgYjl;-BbBst<K*-DK<BddzX>f9R%BM}eePc=_t*9JC)*g3^s#2K z^1~P$#NmjpvrUPX<JJP&Zu-Rd9{Y^oe(OkrL@{b#kv|a1oazgql6X-S-j!<#Rva7h z^Ie=JI8YVX=yG6q_*j*wTlZV{Y<>c?lyP}0kPLLlWOHJ}*|h50>7EOONnG=P<~X-l zfxn8&G$A#Kf7xcjOP}iCRFM!g+01fmW%ZQ~h0euECMe<$l1_!@;ta=$Lwvqj6L$Is zeWr%8waTx#2N;~WTu~74#?laqp_6$z>3+W~Zp-N8VFQ0!WyueNkVP!^z*Q4bT1DUi zwmqGk2+*jN)Dbv_fc-+df`bpT)etHg1aLe-UuPCAaL_;%ukHvx4OtXsOWN$&GYj+o z4q&m0Q4?phhJPl#@O~N0d_B33$z9E`w+psH6y#mVP=jifTU%9e1vWvyxg7Lhml2t{ zh?aB0M_`j)H*w3gGO~N<6C~K-k7mCI=GhY<Xc;?=Cyt>nlyh#$A0HXXaaz8oZ78yL z!tQtZLzgeIceFF3H+40ND9IF5o6Kae{)?>lslD!h?pgg?uSME=p93XmK`K51WX#ef zP{jg&Wr7DI4!#c#t4qY^%gAJLRQJPYUOJ9O!mLw4ciW2<v9XXNLPWvmczCH_;5%_3 ziqL<Uqr2<tnzrb^_ArzI?kloN*WM6&(4#MM5qg=j9wme8m6olH^+W-CB0tvY>t%8T zV86G*8q6B1sN%Er-iXkuR|7I9B>SIMGmb&j7h-;tyfv<5>4^@%98&ZkmZYX~sLigL zAyqv>bzHJ!$irrX9tPriYBMP<Vl=8b0ZVpsM@sCFJTFsB&^>wPr_JkrZ?dJ`U5oH9 znW+5e2@W>mRY}1(PX*W$I5eF-38E}He7@v4z|9ga`+RRij}L5+O;7QyGS!jS$P>aY z5j96r$^m|?M|?4gk*dJZNLQDT<9dIWTxi9;Tz#_0{la7g5otH|A2aF*IS`oP4@v5| z-4>qvGQ>xA#A2{vMa>R@ER^z^8KDt5MKy!?lUl~Ch2bUFF}fQw6fAR`{eu?wj7!c< z3>#jg-Si@2#qaMyUC8Lz)y>c`WB(V@{~SGDTe;$RYpaFqba;FotUwWVPsjL+r!02% zK5dIC?27{(m%@3=jp##F3`NkHh=C-@eL-yx5squ)13ePSu{v7ptDtrK@;GHiB?Inz z{JbINT2=21s6TYt=rng;>@_QpAJDd?ms4jIb*Uh!Y#VzeP#uSF?@>o%y1(#CZcfcj zy}f;D>>nK&GH0pmBt3L<y#>uSPmRG4bJ1YaU*C>FYpzN`T<9d0=IBo|N}CF9YX}WR zE8<>3m%E(G`w>&8PcP*x<lo{Ja(vA4#_L(mf&7oKb;NCBHEld#W&%z!gR3Q%20C8E zB`;nNgPE!E05y*CsKmYO(vPmqvXV6Ryzz-7If`R-L*?WgkiimVK-iEpmBvLgo0RbT zJmX^?bUW<!f1>qYL3!)vhMgTeoaBUs8vpIrD8UvZv3FSxCl*y*l;Lc@zxIYW1wOi^ zM0J;NoEH;q_q7c0LvUd*p2&99xMYN2O)ftw$6=$ZiN)myYwC-P%0Xk^x8181yx`Ux zm!}no0W#zAee@g7b;-9!jEd|l=zoqeq*#7p2`%E{!#6%2>55FM+v$qPpmb_o@8+y) ztwgaB_PKcn^@<qefR;!S^YMag^Pe>yDjyj>Is|zez(t9QACq)8J$>&iQ@YPt6N0}J zDvNNeH>;}{PDzF!z_Zh~ki4Dov6`)&z_8L8&L*p6Q73FZQ2&LvOn3I5XRt{O;+>Ga zI40ZQ0=j*^ai<%UkUz$IA}S|u1uxw%v(x)I?q0p1jwULfuxi{iPko@u$Q$C`!~eG& z{uhLvuG$1S+5{?#dXUt~%M#aE`Fyl$#<<HtD{6)=?oJnP*1jUn=2<lt=5P*(94>p= zYKA@pvt#1qT47@e;ddXXV%Z8DJqT_T3EFlE&?AK=O)j+7v)}T%QVwo=vlc$w7JPNH zUdr*C|LoY{QO+oA!1BybdTq;@iZtDw!ov8_OeJATAU*ZM@S{S~eSu2N|8x|VnU!3G zF+Dlx1In#x$V8koG0-6Q;ws%=`ih#{COw-V@@nVNS8Q*dmPFetzCZlPler)HwAThy zl4zXxz^C1Z5v=?poU{XdhMHjeaaj~dR!X>Tm%nF7-`s%&yVc6BDv8VSDbp~m)bsPP zjQtkwm+8sSc``MX)<0L0cdsNEb?WNSeKP(xv^>4NUhSOlMdS^|s>e-hC=x_CW|^vT z(cO5JN>n&+E2Fa~TN{mO4n@AX??zr3&c2#lk<4FtW6esndBw^l-8?NPUSXE`^x#_F zWUd#U*=Zi=6Hy^G;yJCP;r^iEhzI_zOW7h3aw2UpXSdaHf|1|wb*l<>>3uVFa-*AH z%?W@Sqzty#Udl*wGmMBFPAP0fXP7u-mNVoe?VoK?Z%}rKu^f{t7iTYf6iU2_GJqlR zR778)bT^z560BRrgtP0ucV01}^vWm0jaxjT0DgvWrBA>-f03<#R09kb5-acd4I8e2 z)gn67x^*~LxC1s?*|DcvQ5bcxhB3|acKVf56yqZAxVcOF&bRwxdlv53>B+%)2r~o% z2)2W5?~o5JbF_=6HvcIU|COgNT%O(U_aAk&P(f%a;>INhOVyk{hi?Q8Hl1K3X@Can z{n6jpMwB0VGm;u^_Dfgc0QE7rL+uTV`qfw%Vdc-=71ieW1b?e+1G}!r(Z@Tl3ln6N zdN`-jgVLob0wN>ya-oaD*$q<-W*mOk?=I|>^sV*hOJY!F4Ua+6F2{lyDqCt%ziep% z!+_1P-K>G7W%kigPtD#Cb4jJY&YaJf|Dlog>;Gt^m{hJZREi?N6HJSobEGd~IgBB; zA|7HNT)PO=%nlZd_a1=Lm0cSDq^w3#21|hZ4NT^Fx<fNs*Q5P#+UFC8Y>T~<-&7Kt zb_lChG?HE9ym{w#!y;{kTfn@YaA8}qS<k(Fg%Ab(d8(h8{tqJGmTWoP*{bZevTAnC zuluq!D$r#jY#dFwC~LVvkU&+13>J>UBC`FMIOoexA#)@9)e&x^UseW{Ek=Jib3Whq zVIHqN!f>e?MH*9H#&l#?Y&w3{$@5swY@2MsSu6o&Qrh+_Z}XljN4Ag;p#Mh+cxU|a zg{KpVWs)pSx%lU;kGXpQc>FsUTHMRa^|Oud^Mm>G4Eu)+&QH$;$aRJ3cB$tQ@`dG7 z<sFGKAZD-fFldqcL_-`hGNEU42}Jb`or-~)47Mn8w=mHLGlj=HenR2Y(B+AoF~wZ5 z{G5O?icq<z0m9Pf(Mic9U6NinL9K1{c8;rA)Ay)Q6d&t65j%_8)mQ7Z1Q%=b3k|}- zyG^z2gT;t$F8JY6y8~Fp_41<X`b#T;d^2&wX`oz1cQ^5IE;Z-5GNTPWMqVkGt?5*D zLsVWCAEGmOLS-g#qdDEgsTem2-xH4H07v6sveJ?EdSquw{^zXO&nWcoS<FIvsF${4 zQXGZ#A!TN5w}1LO*1@>nY)UTvYHFi(<&3<F4C;$M3YjzBt@YnEhv-Ym%fx^ztHf>* zZ;?zJ#)yx>DE}+Y|Ap>8e}Ed{9}O5U@QuFTmsHEitmDdX=kurrUO}y?q;tROsuX(j zts-Sx4!?Pa7Vd}N+xUJLQ{Y(PTd`iu2tyWiT2$8jsS=+JEdY9Sge$AB+Lcf`G0Qyl zn{<;6KRanDI_fWkzL{tDD6bUtx~eT-QIwBTKViN?1IdTgFRC47LV7eAE6KIblhNeP z7s8Mf#1~OR$K_4TLQvmZ@*f9LOhz!3Nh}Ef_V!oR3*Q})M@x8O;1;bDkh&#^t7^@l za8#8P%dj}|9q<zS#17unRiRyflSwKRKO-iwNK>m22#K#0Cz^^&)5=MK78PzFLZzN{ zp?1Y0tQfidTEbca|G8+b`Fxlx9>h2lI@(>)qiT!_T=YCxtV(_qNL5nvYvL_u-x+hK z%_BKb?2C99!|MOST8XAOWh%>BN2;7vwVK_mq9fNc8dhiqm*$iGFPZ;WT^Y$3`c-RS z%#^EFPTKe-=QCE@8lLOW{Cf0AoR!WxliGQfmk`((p;5#qRJ3}b$6mM!4Kovq!~UVQ zDk);_c+pc)kQbw)I8!-6O2XG_GXfWr0CE|-j$OJU<1EQnT7h9h{auwPPt=}+dnr^z zfgXxS)7Dyeqo8llW{<{5)K0NK9}9P&EN1y7dsG@yqy=Jx;c7)8D&TvNFlo&?aSCrw zNXu?8hQcrvEm{QJ$o!2@lTZVJ8nfpM{Rg@-i48B=S9YOuFPPtJ7L5;HF?*Jer6HwW zk`VN!ip5A<2(aL`6jy8%Bwo16<YqsmY0kaA$5TYV^(-9?z_H0Zb`lb7l?X$&)!R@K zg1l0qBDbw;$D_mM2R*pS{|{MT9TaEttQ!KsCBa=12(H03A?V@@i#sgt?gS6+uEAM+ zad!#swpeg?34ZyVbMC$MeP{mJee12-s(q%XyXWbrXa4ev+oD_LC(NaZ5d#}-s78en zZDM7(bmszEQq9%$iSc9^+|G2o-UT=IoB6eiw`garn$k`zs~DVxQF5}h7Y$T?p3)8f z-+*@wWl?B7?CWtdYFCI{SGABYqg%G24fK0$K*1B5dH3jv#EaD(UlaMG65Oul*K&Zz z#ksh=kjVhO%eRTd*Bob;yGr&|MF&2S!EMbUhL=)qxh$)Z$9Ca7#*Ll|;jC4^gz>?Q z#K|%xP^>q}?Xr1qF@NCDZz;0x<9EWHN#{;WdewJ^yQ1*h3c~{6v3`8|!sPabRJw^b ztuz0CT&M}bW|w)fnu}3U4q_9Q3z%$&&D`oGU_=cGjCcSWi$$GNM;njk`bZh%o81E1 z?`&Kd4O6a@J#|`7RjFV2b4<_il%;6uf^AC6wXFK(aF)hVuJGX8wceEsEOVpAbCjy! z%_6!rUY9;|gjVURSE0Slx-c*+ZQLrJqn=Xtd}C8eRua8oGg;{4vOFp~ZJf0l@%q#) zYWYGY(i+q`1KiW9?T*X@{IZ<{oR|&ZTY{S+s*NcB?Tc+mLr+CqpNaCJ2{7MfS^<}= zEi4dpeCk!SGu~j@;Cfo28l7DQ49Ih>HX1-hfK|h=d^RUr#PHZfz86Tep+6RT;^K`( zF@N^1yt0_MC?xDa?@F(!Jz4-abuK*!p09i)f$R;1eZE|KAtZ<-eG^^`5nFDAI|EOt z4*oKng13iXpMI$NF_5M|ehFO7%47-@_4KyjIiHP+Bzq%CZoXNSYH(_OE_ChJvpgB~ zRB1AhwUyhE$;D&O@uj5cYCdAPkn!Dk)bS1d0_#sevb=x1z<fWLKo8;5;5DFBa%s!9 zYVu1DOTdwZ_H#zY*E;vO_mL~P_YOh~+}xzR7|?9FZrzkza<1ucHKl!x-N?F9GS9la zv>2S#JDjiLbtAoXXEbQ<mKRGMKxLQ5f>R~9NBHIYkMg$F_B>y#cU^(PC-~O;7TnbK z_zkXiNBAV(;YlskH5Zc&X75-TjPyx5eC8_?ntNmx{=Y~0iMa;%-@)J3VT<#9pQ#8y z2(;wyzxB3hXqA$pq!VQw(-Q&0%WCl(N~2Lvdv0k<w~DoJ#2cX3T<$w2SZB-gUta0L zrk9UaH{*7dNT%s7I=wC-`{k=lXs=k)x{lpF*A5HWDDZVzY-S5mczd?V9^8uL0Dasz zY0r+s5aicdKKc>)F|2gs0p$nY@#vM75n=s&rj_@HJ-nVhQ1^hn=-Z(~>+ET%cT-MI zcfG6k0Nlj9Wp6IN-$5jOqt}9dtwf2`S@nR;^XB<}n)xrUbFVP2|MZ(o`OnZRnzJ{& zgjhR*{z#o&Rh$%)G!oiIgn-|ZB*H@mB5jJOJSL==C`n4ryZsmn(nAA<^)ylO0Brsb zOELvceQ=-95JGdmY11It;M?2S5{%h*4q58vtF)`y-?bvIrIr1W2&V?&A6(*sX$y=z zJwTsjCQ1A4MOKafV5g)9rDLZQ7JEASO(-Q&JeLbwe8fAgD10a}54%_@ab60P?n`Yv z{smU#*jGFLsTR00M>0m)qXsH#q|r>zrVsQ8jnvAG%!A<PHG0nQD(>Zu6v47N+UI4g z&aj#5dy^O#uCU8DXY<jbCqXtxy>YuA{+)L|Q}D)8Qt?5{MQDd@qPHu91H}=n2UHm$ zI8RQKrKMwPN`3|X(nFGK?Y@2%ks?v$t>nD@8flLU3W_Cd_};(!IAWKaQ+vdwgd^{q z`l8F_f!EO<=T*YXbwb|->`w<yU`S`8ZRC8(_P{m@*wn<TI5@Qv{#4KjL6A*3SK{mS z>fadGt39z?pziH86F%?^nRidf=9=LB;pON?vv&_1#-e}{n8ist;HkH0^^7efx%)!X zS+eu<nxcZ7$>>KCXepVDi_&&mkPlS<kTj#!8XvgmuC=_n-D)8#OY$B=wmtI}Mh)55 z404$^rg?YLy`kM=K2`Edc-1gysS_(U?e+rqd%aE#GPvgi#_zX>uYNykHHg`KakaF^ zuERUpI~wapMZ%+5Ysz7LbexJvLRR)UHkOK{L4qXs+G1nSg(YwSWE3)+o=N}OWrv}Y zSB}1T{SoH2=Fv7-zxpwo`)^?rn(Lv||6fo4^=;6URx3Op$*cZZie<!i!TX-aTQyCH z5FcofgLWVTqHV#w43k#zWHG<xnTu^xqk^@4E$F8hkOw9QIzP6JGuN4h`%4$(28R0; zFLa4QR0unE?Kb=Tk})(|k2`-MEhk(&4f}Z#naMOx#6LM@PCpLPVvsTMmxI((*x8zF zz4k?$r0P#X96-k^SA>nGq2l8`0`lgSS-txE^xTeX<oH{N4=N<D#SG0+tot`WK-B7) z(#1z*2*aWYN(RJO?J}pF-m@Y+GdwaWZd||Qh@RyH_A$1eD!7)s>cUsX`)aN@n>JH> z1KJkL7CWTH84mX0E`VeTC9gQ^!~Z?HtY?is-q~1Fn4Ls-Gj{j|BZw)Idp%Glrg%zQ zupW?J8(zOAb&JO^yR(Z#*lC%^YQs1E*=)*eZn05o_K}kExLlLg6Ie07xBy-nN?Kv6 zE%*K6Xi#7^smHyqOdg|vM)~iAGd}MoYHI{vK<{RW$y$|R-|~6GM5vWjAfIDVb5G^) z5&R(j@aX*BQ`h`#plEYCwQ=+|_bsg*tMod8Pn_r?o2@KM!pa?wa?3pNVjnOp)<RF$ z?CMwn!wLLyxlPHW|KQ1Y#tL6hfqpn>8lG@4W?l1z($jV(t;ku#IiSZH0;hS<*PV|) zw?b>>i^j}_6z}5rh7nvjKBMz(_+l1m<#@Af-09Z~Y-HBQS>@L%yYbG8jWq<G-mb)c z_cMKLZPzcCI=`p28WlcUDW8p;6TR9y7fq39(&}|)(&phZzDg(CA2HZ;j=y%dR=fad zR4XRZZ=z*wFb`?Q*lyR*BiqkIvQLnK>K43}y`9WGp7ZW|mwBPJZImqYoJ5sDusqev z!PYf{Lk!-MZzy)9^p-JSOZj{~W|^e?h-P*@@`KWDFHN8X@#s;4i>d~ZO+W@~3x(7= z9~P2-$7qo(;E8PJ+q(b`$I>hB{^rlh>iH8{>Xijq#*o|stXbXsP6|#{Q(d@r)o>LX zbnGPbT%5*U#VHdCP^_IQ5E_O`pU5!U?<-y#Tqng)MWUrg8yW-Q-~UNJ_M<q_n-b5- zj6s}M;o}2vJ5Go8ow<)EJc9bcG|l^u&J%Adll@01qos8g-cI*d)&xN*!U6Biy{a^f zyW)Z7ObWxHDY?ug874V*H|<0psUfIMw)L?;8ddTB&@t%CojmN&(dg4R;DC-)1}(Si z^M?2k_-z~Vnu~6HOx%EKwex)e6%$4;OGj$Ec^+2Kw1P41(g6vYpECk^{PCRwChw;a z3QZ}@f7|P=gk~IeYXQ^L_g6oRNn7hMM$+h|&@fcTPHj#LV`lGgu$m$jGSkb!wBuS( zZvtmj(PTStHC}j&(t^f2%+BvDGallPTS`bU;ym^Sx~R`SwAQ0K8zZqlaN+zL?*~C0 z+Uslnk}N$I<@>vKmapJGELpmkD?5V_I~X~K+f*H1z=5?YF3#HvWm5v6hDEkl<c2rH zT7Akp^h2pzN|Abz7@z<i#OcL|)=z4b3&qi35<>x%IyzBh!ngm_|MNtV40Jn|r(N~r zmupwSd!f6#X8gZ7Grmj^q)NP6y<?egxkC!H_S40>zC|a7Zb<Pk55H`xwnF7LQx<^< zo9P9!s$R3;0)BJ1lAVY;+|`A8_i{nOkaXs%msO&y?CghWgTt}IDA8<J-ZBzR*OT~U z%Xx<|x%HD5pR)v{{F$zJi5TEY9Y1XypT=G582T!!24@^GN(M~6nr!xKC&mGLN5E#W z=+ekx8^I^~0Pkh3BF;uN^kxw;+bZv7u9VL{)iC52kzKw2$Mci&ybtnBqQ+p8dZR^f z27*qks^We{i9w_O@#gSN`wumZ?OljLbrF}9McA}OdoFm}n>%NpD7CV5kg7!}nrm9@ zU*23-@U&mrn@9eD@nYT}Wo9je=Ose<VP5s%;9#isDQKOe3ntTdP()R6A6l65nJM4v zAdxWdwK6MvB}^u{U%U;@nF*Q>mYDV7>r4OW0!LMMTubGyEm4D25)ah7&X{<YRG)Vl zM_(W(r4s#}dEad}ft$*^Alp`v{B)b3jbLbp3gyvx+LkJ~@6;DPeu)t8qhH7Vt`;|z zhD^P5kU*eH+Pbj|)<wH!W~(x}k$RhV>&@FhK~_GLDFKZRF=`>eA)zinpp({aRt-$u z4+OvD=leSrf41w6jEJ5dy;7d_m~}D53@B?0-Lvs+Ph>2(=wmR-M6r5yv{I3ypBMCE z8LbEga3!tp|F&8sN~~8GZ_1U<qsCWL^adVadmZ$+?KJ5WD+vkn_hEOODgl$%KU(jL zUP&b<q`e%t_v%!C2HPPq;nZu33{wy!$rjAMXT1(odhz>5P36_2>%w12`?gHPwT0(J z_hr3@MuP)sJYzdsI!z+Hr)c^(tEDLOhHi4#y^!}M>(BU3r;X4`ZiWX9?0=Q_mGgc* zK%RLzHgwUYBUdU`;D=r7sBpZK)4y3RRw9D!%76lAqMLD-$N9!uTPNc%_DijmsJx~q z5N~EBWNxtDDAcQ0U%G^G{;K5RU*Hb|otFD4Xr@K$;<MNb2YXR}AZhFvhQC6L3QkZX zH$q<W%b!++5IYxVI^OOBZ<;MI59yLzl|76K*prwSb;*vDU0u22fpse+vtRQ0L&TL) zm((I@+&r))c9CcB85j9nGyD|Bo#{(t&glK^UePmC%0zffmGo3hUZ0A~-1!Sr*ngfh zQ|@eDjGq4fqH`{B%j55E822OvZQ<4d$Uvr);kjwP1I7PksqG9`((xGo7eU@+{9ayz zaYb32xuhe*G<D%ia>b~l$=B0uzW4^R26NxZitKpgv1CC+J{BOV{%)T*t+{hGPP8(M z-8I4!l##iSW^k((BnAjIzw{|%*DZD}2uHI>z|I21x6gHjTX|);sr@Ra<I2b3EiXAb z<1=@z*Bw(;^{k!fup&y0Nn}EkusFVnFB*T@Mv+;YpZo+ON586tB@wBO4s+}q70ej0 z|8a2h^>*}Kk<#x-7$!-W@?_8(y1&+?u~Heg$925{U1qB(IahqzTwb%5;huRaXX$cC zP3?H-$*f^N{ifp|?mtUO?~EdB%E|*ZCb+qv)bbFyUK7zx!agYqd2ZS813``2y^@5~ z|1^TdfOwN6mSb?zc>nUS?x@~VTi|apH!M-Y_@4mTS4T$s<qm}o{j@^s@cZJ1KWJd0 zfc9-oro}s0#nWR`yX$KAllL!XV?CX!t<Z-@vp+RSnz$c;!*>$ZWRM-OnTjDDwzBC% zL$mtWyiD|8HN)RFoc=7;4|i3gZ4t<p`l&~*o4FR8996O|cP4<I>a_$i@3e(HS^VmY zYK&Uk<nLWMvh~z*g~hzA`ukGk1%v0n?QcZ0U+FhF7E3><gMOSyMjq_{@j0<sT>@;M z&YuZ0%|k6R&r3XwIWP6<tTkGiiJjr|pqzDTtT!}@dI653&#h}8KuY%-&d`T$;QYFy zs#V??1Nx3b@<;j2)kSZu^Mi-Okmm=(@=^@hMPb{vunX5!6t?-_<c32M`C<RB?)hI? z*H*fpy!k~(P~lN|SyAZXprIJM9I4#m>MK}juWt_HmfuC=1;ttq4cyv4Z&=<HT2|Kv zP4kq0da%f$f9N(hg>OcSS$}PboM{(q@p|oYRy;KWhJCyC{eEb?8(W;T6-<35o?<%* z^d+x1r{X_+;-(ifwZ<53TzFE8i$iyTL7%h>xE|il<7>I8Fsd>y;d^8?L=4W8yHS8; zB$3&N{QTfr1*;+f&iBM>TzYbHRQ|J?Tm=Svj}C4x+loBM%wZWkaJ-9$Y&Go>ol9Zq zd5uG<V7Nm7<O^iyLb1-;94-VC&AaVla#xxjf1cahpk$b>-QW3BS>XW-OLEnir!7+{ zSZ%S{bFYJEj{o)K2h%ub-4p9pFUer0$T$dc_V00jsef6S6or!vj^TLY?IMh4rGROk zQ~t?uIPr<%e`3~(&3}0JZJ9VYb>8Abg2B?iA8+Lk-pVbtenlfR)BV)YWVu#LEk3lx z5;Bx#nn1{_msxjH#82!XCO!A(2&z4%Fj~W^X4|eUWW=0o)T(i(qsQ>#G9XPxhzA_v zC28p;BJt_Y#dzT}YV}W`=s13EyQev)_((ST*P3J#<HM)!nzbwX=op7P*VWiSN-Cfh z)SUv@i}p>_rAm$=KO4iayC?>@=}M{ed;bIi-Y#ATIzW3!6qESbAesO^=7UJ7ma{|Y zHnz^YszYJ|tkw$mqNE^-M&c5FhDUY|gdOXj;{yRn)do~71D$_>a#5rUKb*T$+#&)= zDYDHrAbs6%*j~?DeY9uG@AEVZZ#Pp+=?6p~dSxvo)^JLGFB4|<rTm$eA<F8@Xyv2l z68zwFJZ&q`gw0n4SMVZ)E{CFr(IrsS?b*08@4Z`RN+k{!$X2xI1n86PY=Xk-RW=T1 z(<?6n%4ZhiOI8xY<Tf|@BC$-T?)+gv;;l18Dg7V+v7h+K(a*mt3k8_3eXFYE{(O3T zWEd6ipa9&qQE2wWvn7Mg)Uwe#vVcmy8?7V)Lm^fjw)uAM=HqG>#Pr%Kna1-LUp?EW zR8i-D?06MuVyFix5>Idg8I)2llXWfNRS)HMN_eTcfQ^&6C#C*Ccvave{d%`lDVJvL z;V~O+;>j}1NnnjmW>z5T0~aOmdeBHbawJ1?=VM8eaV3ehnneX1Yh1TD-nd#T2{jT6 zgvm`zrDc@Rr4wa$q-ka>>hUp9B)ZFa4$HhZJkO(j#vNTiiRuAR3D?6;FJBiLZzX%s znE8#sX#~I^VAP+_d@jup__<I#L*7tOY6#=IzwT<Pf&AA|FC%(8mAtC}-D{GzcIfZ0 z<JMb)!6=cQ;==r3$rxj#Xq>%`60Hmcp4lHg22aKUCK%PG!1fm882)I64DAK0L!rf} z-;ePZqZJO->559yJuAuxh%__>^~YYK(h#UI?5nIR58qn=M)4Ufzq#EzvUrOP-t`ra zXHuvjOR(>l<;$Pge|jFr<<-?4B=F--_7~I!24YA$-vPO~2I@-j?0q;y$95nB%|ds~ zx~_2aZpG{ETtMB-POObETub=c>s!7FbkFwUnI8|pMxC6cO73u552o3!A1qHr;%luc zC&F)6dKJR0p~;37jl~dM+b>lSp<j8<?=~1hZ9B&Z8!MJIVXgepDMw>D50E5Hv{-N` z+s=V>9j-LIK-^Ctj75<3`Z6kE7$;<>K)0h=cb?9>a|5wZ+f8@bddP`xeHnfqLyzOb zXRg7oSA#Zr215g)zQPKtXC~M2{I5H7js>Ty#XtJ8a^eSmKmqS)C#MrDZs-Tsxu8}% zDWGNBc8YiPTrF2ych2SCbJSSijXr&oq(1PE+aXVz@`vo5yzcyqQ{Dc6kb>u?=11bM z5TwS4!{XRZwWqw|PH!#?YCAm;uoO)I>^5Q_Epz#W{)<kzZ|CUsUM01eEDQ9Axw-9M znFMlEg6r_Z_WV^&x$#JkE!JUxhx5@%E-Kl)5#mZQ1;2|`{7`-KOfkMX*~8}ahN^wj z-J3F`m-`28z_45^37+hM@&NbJ4dz(7VtK>qXC?OIy8i8p#3lx%I&&piPX-h9`9~Jv zY<TVazTr^IPK!K+j5WLXCbLXd^IuD9i^iC@HS<J-#~y{oy61f<SakIEd67CaA^?g; z!bR7^`5!NTaq^uQ0eE^0ln^xmV7ko9bn9GH!feL-iH&uaBfsBX$BgTQgolg$z)4~E zk=#WNZ>1-bQn8j|pZ5YTOkm`MrNt|Fp((pfC^{5wx_M)MNQ}V6$+#%{*m^4{VDYM% zvf%NC(iR2zOOpRJh?IuA4d;<REhm2{%tOg<rS~`$IPB+g^!f`6#ar;_{`E#!1y{Ko zhiakXdiI3bOfKBx4jx=ZI|J=aCt3BD1`hUCUvv!bV7$3;aQ{v~N(5O>lN<KGX_Y{Y zO4XzeSjd@zY-U<??M;o!T>GNR4Yh5CDOp!cajuRQ0Ob2m#rms(4`WZeF53)v$qzm* ziDARmdVeyVpnW`RU^V6wZNVus0hd`d+U>q$xUp01w)x!5wM-N^jiJ2hTxH$XgtD=E zs}z+?eESHlK8}t%n^Q#~d^qbu)YG>F1{UuWGOg7;s9x96!u7W;6$XXX#_V~`*u0DN zCZz1G_92X74#X@ezS;zZwfd|hpnVZ^f3ipeyvNRlCVa?TtHLo4SKz{rV56Pn{(H7s zhIw|&iwT@E3FOI5cYBwG?_kqeu!XmAv@jQnkrHvmy9R!daol<pSFSBaMMeUI+tk;; z<Vl)hy}~*j{%%$6I^mCTcT`VY<ZF9j4<J*XNcF-<lE-C*VrebH#8Bxx#FxCYCYySd zIs2NC=%4-~FeZ6u6LuSII~`CTCo&f0y|vPDVu-L(>`F$zIR{iM*=p=+3N20VehM3g z%vL8x47-9<yw~0_K_2Aw%s~SuQgw`KuZC-b-AdN789Qd89$pc}467DuMz$U($Y%a2 zUkzt{sa030Sz?$e(pjJf`MVL<R-(MuYR{rJuzHVbGLU46lgvLw$8(;!fOo<xP(KQ! z*d?)hEfE|UxLDbC{`L{sV|1EzxBsb32eX}T!uV~NG-Nn%k-hIJJON}3P!%Pqmzb?C zZ?NO3Mh6}YR2zLNQ01}b?GJg>+C|_jnrNJ9Y+9{0>LEEJ+`Uy&y0a=fI@WeM=1x%Y zO)^<UPZ(^+{d?~=v#(BncV);o^NR3+z+&|#Ladwd)o%mRV7jA8h;W;fPTt0Vyv@<~ z-2oU|7Og=2eR7pJdGh#uBKrSz3o$s)|J{U=sS~!$iyO2O9Y@SE^0kO(LhJYU)i0@- z)R`lQ*vPW@F&GGlh!^~fWQPMRzn#Hq4dYz68PST{Dt!FyaZF7cd4~r7!`^A5QLL^c z5*W35dcEvT$*?6k92BBF*EU6<>Xd-!;vu}}V<9Rf8~WAHjqdzUVANrrmd@ICFCpu3 z11`@_kKs}Vh7Py!bq^U3koUz*y}vO8LhbrISrzetdbS>PHbvU$lYlyM+J1EjpP%t1 zVu<Th{;fKIDAj>;`l}yFP)nxH+vajefUZi8IhK>n<0hcbeb{D_!}+F&f`_tXK3y|g zI3Ryj_`2P`Ku@r3iP<4t_fR9B2DuTfT{m>ds9@Da1{*2qU|bS=s1Yq5brXd%%JnWH zY@T^@&W$WyzPc9vKG(WHP+J8Cq(TPT<R!%<HnM{#^OhP}L?sf306OCXQG_kvVxRQR z+~$XJDd*cCuHilbRE!hjtPE9X=%<&15WEzL$T#6b%&T>$m@#j$WGp449;mSQ^>nRB z`!8QV&<Dd|QZE;VUmHN)?tj|0y6E%iIexrs=C`*Fwyob{Df$ia{uPG+L=~E3sH3)` zeMOpokl?HSz1ewa;6d8^_j)<p+8yl~Prn-_bnRYBDCfN`Q*T=QS*hBWbi7G6XvJVp zZaVyYTWCq4L*8XWK6ZkU?p}~y<y2E!0^+)IS&#<lco_Z3AOInkSCiR-K+8LQO%dFh z6>i>tgu86Cnha}uQ}I>v9XcDwDx|i%w~?{DRYM+Z)8Tl;;s=ahQ0*Gr8}ixiY+wB3 zKI@b(sy@B}S|r^v)&8)z=Bw!oNIwMeFrAyVICYr*bqMRqzaO)D6vaH>Obm~HKHB5C z<jB$#j-UwQh|X!#Vyp{H(xkUNx`v}~n4}yWUV}fLk`$;Jh}zA4U}tUrz=x8<?{)S0 zUPIyCepI3}eWO9gT7f~P_x(yS9`BfzK^pA`VE8TZneDu^Xe26Qoy(Slk0ZvBev5-& zwLR&$>1<l$F~Rk9kW8D_MqE~{KSDFqbfTi@&+5^}NJT-FCEOSht)}#x)p}SYm#|mE zxaGgejzRp7He+FCOwRfhR(<r=;-F_I1;?@xLo2`?tpRZ8c>1RP%gJY_`S$__2S96E zObUInJ{fCGsNCpqpD2=oiZ++5Wp?(3S~_o7atU-2bJzyU$^YhK@M~eE>?*hf3L__6 zPqN}$8wm>kZhBRock%nXW*lOR{(@>a>lRyd<+>_p3t?dtJ0(ap6>>AbzGCh0UdX9{ zbWB8VDzUPcOJ^~~sT*J45w98P_?^&3VWRQ33kzrpBdn+Z{Lz1mTUVVPi@6Rc!(j^J zNd`C!Nb5MNOm+~&v+sH>I{SbWRer}4&Y_8=@q>N#eK8C_z2jvGaCT4lnWjpd&ZLEZ zI%<$3wzR=Xe-{0_?ip;%>3iZjZVLWPK4EZO$%Z&xCF(@riQ?WT_5QoUO)UyHSRv`C zZXoOz(ILR$?VC&7H=%kwSRF?=B>ytu_fYZLKVk&-BLGt-nuaes6-V(2cjf(#C2p|E zWQ46Q_;`~nwVaM}IDYTM;)whNR9w%J#W|l06)nH7w|h-0Fy@<^&Wy^bz5>MGmN;S? zdeCS>7(8qWf7=koP$q2vgV5rc(5qnw1h<9rdH@%3lj=3^k~jH*AeC}KT?UU^!|v{L zj9K+I^5UV>_=CDcKb6Y2l>!hp48SBjZx+8HEhuznLp5LjyJwVXxu`wnD@$@@qk`Gg z%rqIvaFkV<bd}faJQ;|Ya1cfAZ(U))1)*-Nxw21k{iQwNGR_$N^8i{+e+uRV*KJj} z4+?HXm3G3z0C9TPG4=i#O388>^PinHumWXOlf|8LaP!~tc;qAqJ|js{z2JO$9{PEx zGxdq><GCN95$T`=Q0#K)h4<G8+2s$XMTd+T+(hU0b1ETUI#$H0<bUpoUgJOv!Nr=N zMs0<<Ozxja+RL=?oB7(A&Sa$NfI5rQu6^$2E$gZz<pvsx9_hp9XP*vLYp3G6t$Z53 zP;E|$lWEAyowQmoq|LwiQofu&*&J_vf3uCe+(HYY;0@3qoW~1oK1C~zR!Pzdhx&23 z-Ryq=u8IO|E#ixTfL&hhpcIV;V<AirEk7Y9x%$(f1nC3Wc=BSIMA5_GtA&WEo{tdX z)<rs%${}{j-*T0KZxR@4fIMr0{WC;DPVT@o=qMu|^8UWFb&yRHp<0>l39om8c!H1n zS5^tWRXZPqpT#GMqK3%f0I^!oCs3qRIB|evViJ;6+Ey|=<vMD)YwK`5M*{RGWIB@B zBqmCw(X4XU-ryZEK#mrujrAGs3#*OPH^+Sicuy~W2_MpLP9_SHKeBKV*A(yLA+l9r z0D}|!8z7ZP_~_%E%Rjc8{|T`d4iyWGnR|S}lh0rZz=mt~Mdsb(vW;(s+7bpnx!p<! zDL(m`NU&>9wqkkInxHVw)A`fpiNNt~8^221)WZllS$RLa4{*V>YtQWN7Zc%6mUr6^ z1e2wr<wuA1Y=_sCgm&fmPCeVJs8{agKmTsThV=;uG2qnHO24ZBFb^S$U{GgQh3SaM zBj5v7>kSKf;R_NV-LtEljN653i1xB?=ie9I@zVEwDOF=xjwfv17R^0SANJP7!J{Be zpkRbkykFS2K{VO_Bc04q1@XD_(9JP~bESaObXK8Cmr6ucG4$p3)!7+-z9P!0Gw5Wd z%!Ld+zOo<x5$2EEY;wO3+5Yq!-cdU9mHXI=@#L2CvtIJ{!$+PF{Hm+(_x9b*5^Z^K zLfHqd+IYL*pvbk5mB>e0($`tKxZiXmB(zum(~fa0_Nr^S+Sx7U1RnX#BZJJTN2v0` zSsE!t4vkcx4g(a=xWc@*SM%{`laan{6t)BB6?}n1v08sQS}{ckZZ(WSzl@62A2|b? zEve~lK|$&1=`8lI1kFE3a$iSFP1H5mZP{zd`ol2a?#eW)LOzAqt`VVal<)W2pENct zt>vVQKVjgq<a4^UhT!|e-8!$B_ONX);i1iHYqXn@`s6~xG4=sXmtV)qPa@C8JV}Kc zc7!CJE@mX)cYLfOjfB!)er?hUJ`=T{>+OCw3Tw<|XLMJ{{Hwp&`B$n~Vp2+&P6>TB zZFb>uGu50Fj#^4Qdn?zS4%eJcfGKu>PLy8eYm@W%CVtB=QVWX&it2OZ(!Zu<eR2^7 zB&uH$CK!k4uTi+h0Tpu<LvZL<{($%?H=9vrR3o{STJ%|$@+--qu(*QXu4%qp&}JNB zdssb4w__aE^2nXg52r16f3&5B&gWY6KHOB?D27EaM2=YWgktAUAfCWE>=d<{fpzR- zf`n?FfwsIVmdmfO7G|({K$p+Za3PPl({;&*gFx#FKH9j+^wy(uG9BdU?aM|Xp)x_* zcJ#{hTSbXq)chWcjug&=7Ofj{LJNJvNh2QroP*aV-ruR7iy$L)K2_}M_+&EZ%U;_n zH@$NQq4Hc5_FY~14X3wz?eOw<>Il4svZO)8IE8e)1#SS4GbV>xlaZc19Zb|$0c%w& zu1F8VG)yBA{f@vPU0|K?eEtGOMoG)fs@s?XZz6$7Gta>emJo|0Mn1;HVVjX5aSo_Z z<XeKhk%W-}7U&hAv#uDe`Mp~nxK4RRF?K+`4ZBrdXCf%-^_A7yNq`SsSN$x`-mZo@ z7ZWdkuKv%iaormW_2Q5XGM35`%CdZURB_r^sT14ws_F}9PrY@d!8xURtGVCMO@(T{ zbar=wDa||9hbYrT)ZU$IxPq>-9K89~BSTz>+hU@kxSo*Z&*RfCDWKM)+aRDjN{0fR zTB;aBB&qR!3acQeXeJ?k8V)Gq04(VtJsHU!a!!^R+x6)1((H}}js*oZRk92ZN3mb$ zjK%%fY(4&5_gudDlJdX6W(jcQsj(cZa$pjfcaW#pY$@R^=V7mDYdjtqwbGqyDjs{f zJ}=r)#QWk2(ny=xFgAJMR<_(Wdsp9QW$t696%%HPIpbKC=J7u3jOfJp3yj8yF~7P5 zgzN=2XKte+2`D!_ul98AGrXHGB5VewM5iqdweuyGU1eGPEeiTXl`qiuq*%f1Ju*`7 zlw$q8+)8h?K3Z1;9+I~B+Bq8Zy+H6Y<}caNBX?D3c?wy{0G6_EyX6DZwMF#>D&dV3 zi74vt8=7zI5**BolOpossXXc$=k*W1GA0AoFk<s#wRqu32?~UUCk=6;BlRyWQy5@P z&mhIb_^3Y7T!3oxrFWr`YN8@iom;DZk<9x@McQSn(a@}RBFgkOD(~%|3Lf<h*o7VK zHml-fVNr}B*n5N)<jiEtRw5vw)0o+7<9R(;2!F=VFTdAg-~KV|s4|+;b?Soa$adIJ zG*!M&$BUAhf5FGBLDk+|pDjo|EDb)A3F(6$HyOEIId%=|gq|EGH!rH~GxpP_iIxkM zZ^s~3G&;641%+iDH*Qpb@;zBCccaQC-<KSiuWxwbNM2j%G|8_{Q`TE=$fhTxB)#7C z5l)gh90R!z*5=Q&FrD6r)zGMB&LDF`55TTV-`Q&Cn5=oKx8}*bi4?WJip+bx1;bNn zHzc$~vp|c6HGAG@n?QB;othfXHqN_WhK-j`;CCB37rvi#))U6>ITOp!b-P}U0xgO2 zI93`&HG#)gL5kv<?o5E{XKv2gVaJDZonjzcz3i}|i=dKO^LM&%8jZv+x8EM*Y#ghY zP;Gua$tTOQv@Dv3erg*|zy0bNITO8d96f556>vR~`Ve%m7oZSVKd(3Wnab?uvo?VU zh94H@KQMjs<}1ON&Q!%=&(P$>ylWAEpGpZgeaw|oyEuw9i^@-$TCOlua!sB0PaCBM z*@{tp1$rkO%2dMl)9OX4PIbY#m`zFf%)d3w!!e?0*0}j{vliU8uw%V{w-ywXYZWW4 zDr<1q;Ia$n%BRm9*3)C02!h%%SU?kFm7hegf;RRT(wUn0;+GC+&ZX$Uc!QUOrHNly z=uGP%^P`gu>4FbxZeQc0uA57v>g6%^zOFiq=qV{4GhPqP^+$29>ERC*RU#89(74n4 zM{TvQV7|KEdq`YjpGJvcmKFh<yo^2co9(LyB@-~vU~Do{MJ$+I(-4IL)9TM^6x<%N z(0A9%AP<*9iq|#YJ(QDQCwK{F&NbGGM7Cw9_SjmcNG5i6)rUVC?y(kbwva8L*!8OZ z`~M?@;^lwTfGajzV()`8hfl(0ka1IJm%`ihx<6J+wZ4&Z4{Sw@QR@ReyEd#CctdJp z$3jvvi6n(99OPi+*%kZzqR8$cKM_KyeqKe70sr`Xu8)5!hNp}y?O#BDgMxO?DFp=$ zhyyBQem73uTHf<a%cH&r5xe&3T2SD9Wf)=9i|q$h-hvLoKYXl<WQf3PSo+~61kFPj zVqy59!bDT$i&ytPFGMA&^9gZJivX=%9pAq0IT0fH_B#t+g$x-;pWbiZP~}^QEsA&v z!iw6bS%kMYASH%tBO3}!DJ}XDKVwD^<vvwTBCgmj7ceKL*_}=h(beI@lGOEf5(Fh8 z1}ia=4@57eVJ1eabiK>z;SwOd?yj==@n=FWu0np{Ct^_ua1VtLR6yOof?V1up#&0E z#>f)|fO1j4mH^&~hPR3AiSyygeoHnAhBb~U^RWd+#5o0qpNpY7LO31q@zf8>FuRg( z<!(SasHBMqE%^WsDABdUm34dVn`H6+gD>9a*!e?eVCk2IY)xL7f6MwV_-z`rNT^!) ztPzduJJ=fp`_>khKU>iRwbYcD1B}{@T}I32qFYuPSMa7ijGpJ5>+eznb#4-I^_s*$ z^7_2@0gQngrFK_HZY3a1`v;4bLTQF=TOHcygI|`wqo-1ela4j1KSLi)D%)W;Z|w9L zP#+@v`qWtZ+E>iDf`iIIxU`_>g@teS@12qvUfCmeIhKLai!{}050L&Jon=CGa&*;G z?uem7$2tvPS&Ou8nzQ`3v2#q-<K`WIIAj&3ei<&v*n7Esl_uNme|rGRK2_8lppUzQ z>p50u$g)KNqUsQE(QjSLi=(=?IWpm`1G@xEB!MVCqi(9x`Xy8l++3YWX#=7NUO?!b z=WvlCWia)-bVD*1Ww(jB({F%~<>wdoQ+0;P*9W!*wvL&+JI~2E+f1XJkeHZm{Sn=y z*Q+wt#D-w^Wc|_Vs`vlS##=v#xJIwA$|X>HJzv+{cq2NC3wB+O?XVcI)JwKVlLXLM zH8t#Q1TzaHueJ0zv=oY}=&CmRi_Z?<GvBr7Dm5)#m4g3h9Qm#}%lA(*1-vY;ym-!+ zt?F@BA##J%ULIZYNXBF)SKGL$KC5+%#nNiE$$hu=Hl<JY2G#j)<}y^4bgiqn&6mDK zJG_<88NTZa^<Cxfg7;-8NTd}QmE#?iFeN_*!!HpU(q3{5JwFv}v|&g++@6NWOq^_s zyzpxykeiR^zE!B*e=a^^%Fq7G`~3`Sj*T>d+eeD>!1WViZN@lukjvVVQJnqE0u%g0 zhh&ixE8g^TQL*;X@T3oyzDOJ5ioA!qxo=p4XhIXyv1F9?&FtQhjwW+>z>Ag>AX;<j z+U_H4=qoI_25xyfq9kIN&oh<IG2N;eit<l>dyuC~`F6qEDwi`QBH1S=3)ojg=z?;| zu7OF`6&yI~J*(ZiGwU*_>oVpKTAIXei9LG6=0#~)4r1Y1&?;XmrD`bE=rBk=67<^{ zvRU`i)?O^VZF5OBxdIaqGKDs1%bcf>*fC<slb843Dy4psjFSPA@_P6EQg(6A)7i1- zykbqBpQ$Rkf-Nkq?7m}CNGI$J81trUX6uN;(Gr*`;=dZev?!dW%6+lrMClgzsK!+N z^~**`*reKzr;h03;rMw{lQ$yv;2ycYW9`Lk;`&NqmT!$JxDT>q)?#$551Qm-l6=Om zigDvs-g*fZ1s-_z`{a1}qr@$XL~_*%#D!wavu+N;?<!A<jGEM!be5M3+DmDc><3qS ze3$}!@LC1OWeUE|RExH(Rshnc**>2)t_eekcFFNI9C1eipBa5k>Hn?k)$N-e7${1r zu(Cvd*B+ks#~sTqnT<lZdNr5K6FktQp_X^kRSzfWYZnCdU8M2bF4p!40C|Ep!@OJO zb#T<Ldpr`wsr-0Lmdj3ehsHQkTA&6khca2;J9HPdZZ(#l!V{L<5415JV8t_!Mukd9 zB?0n9aWiib>YG93Q>#E090N$9VdXw%(6y)Ms8Av049vk(2IEG{k=v7`b23TY`kZW3 zt0bOIthV5JZ>U~9)}(iH<ww*3UWFBI_Q4G}0q(IkK?tLk4gPNk0O^do!m4q;6-b~+ zUya!iM1!9w|KknBc{h*rqWRo_9Xybd4vhtd!!4WK6oTbhbxXCh7Y&UJ+!<(pHu=?I zb_|E6&W6h%*<k?k($F}}#ny{Q?#PaQ7)E*9H%TyW(p@JZ+Er6zPO>WQ4SoLCVqZh< z5PDvakSd%Tr}BrHf!%I~R%u3xUL2%uwC2;Q`obr2)NX255zDjCl-zGHUE(42+cyV= zns#7MnyNqTaVs5*6#4}ti7Q_%?ZKWAaugRU*HAQc9z&}Y)2w&C>q9Q=lc%|9vdK;N zU`#>hC2t<Ys?rJzhMP1Fpn8WZ(ivjMDche7Q^*OUt(Ip1%X7MG`8el9qPO9kWY)WW zYULIy>klMOZ$p?!&UBfpcV&K<^zOC*YOHc@>rI9c`8$0fuak#)7T=aQM)2ZG%stGl zRsXuq%`jN^&<1J*o17A(un}L%(`S0F?y7aWG<@yzXExr<8!Suojylx(Es|gNmL-Q@ zQW`W}nZw!O4E9V}FZaN$QV2}#SwugbQ}+eeTm8orS=MyWjWO+F^UDVw;>5<E2QXf{ zkl${Lyyg!7*~IHWXI>QyLeX)>Kn76f${Q^Mr2Ovhlm_s>m7#CAJ8=~5N>G_N59)<J zEm||O6(z=GL~Gr89MO}xmaahUwX#0{!^B@)R&}!4S|VZr-=ww`(8qwF2b9&nbKpts z*7%KlPJyyUrm|zz<4x^_6Q_m8%or9cR}Z`~NxjApm!cjYW_gG;z4f#FVAbF#ZC>S% z4+~x#A14@@rhKd|x#a=EPadfmx!$h&PcH6P4}C=~S*I8eMn;6Phkb`Td6Rl<B^16E z!WG9Jr2XSsrGUA_Y6kcGWdfJiO8}+?xi{kCz4y?0>m%xP>F3oC6EjpHRh@hjHuS0C zu7(X;hKZTzPS#AOeC(c?LuJL~yq;mQe1PxrP1HZjifZ_nip>7Fu?j~UtrdS8tbs-0 zPWYX&4rqQTyFO9}WFocV@_n(yh!~)&j#4>a*IIC1vHyCAZ~VUBLAKABsOWGj4!M{+ z^HfmX!bW~t9Cfk%$RE&0Hy_1b3miQ0XhjU!>y5*HD)aCZa%7>E?ki@%cKS`j0x)Fd z4oXLI?3PLVz&3;&2j-34bL9g=?VBj;?VCm#P=<?{bdYR_lR6*Pv3dXLy^-(qK3qNL zEo+Srau6vGX*+clsPk{VpH=ec@U(8YAg=gJo0_eClKX5#v+mw8*W&N~73FVdvsI6u zuDHJhMw{Akv6NtDhQ%H%DGWt{+?yxAaw~py`nGt_%X4vt_0$y(|0Eq^^$D%}?dE>r zoS=E1nG=x&W>{FbN!G9wB0e5gN$3jmYG~Uu%UyRp#9|G`knCk}di7&wrfd|rO4>%2 z63ydXIO3pL*q3N7Y*h-eGG5%YC+#WVcWyT-Bi6BuO5nF){8hkj5F3)<TRDJN;h|WG z9-rv3^M0iB<1kh-R<fecm}YO}$J|1X8hbvAJNJd`dIRKd+euR!xCLTd^>c4(PI3z= z^0k|{dY8GQN#yW(d>TjIdW14zu~ovp)Qbv~8F2W<S=dQG9PZEsQwh<-5jo1=E9R&M zCQ~Gb$FqgxBad~c<t5e4^4O;t)Uz>pyTR}zNz|(6SZ2{Zo<BHr@8WTN;ZzM)v`v5M zG)|`d3#(|oJ_psVeu}XmlN!EXyuWsJMlcYwUC}f>^Qa3sa_&`+P6hWYEzY{sHr2(i zP?(#Q!%2jXZcGk&j`{!7#o1E^Unrn<)wowuNV_@pwX6%S<o}3==+f>c!N%sh)v-#3 zKtYXqXk}g2`RJuT8fHjJW)ZNEgv|>oz*j8Z1&)2@DuG%pEI?4+9X`Ih?cUQ&n?rmU z`3H3_;#x0-9oCVJ3FsD)AG1Lf?#Qb(n`$0>Q@8NFv1Mn(JYnAJ5xbKDgxlFi8x`~^ z40PsiY!n&kXC@}+2=B8es2l*g%23m$L)7v5`Pf{`{l#*|9^8qKz+zpv4XjE&*hjp( z((i2KX@QM<hg&FH?6Zmf8h8U5v#yj(v%&JY@A%oAF?F}z3o1f}d^i|g<F5X&;&J;< z0<X7!(Qi9=r^(XmublBB&3WTpnHP^L9Z#v5cc310Hrm#bJ^7sqFAZoiZW|^xz#k%O ztMY-vL#oz%X_0OU^cTD1(q3A`^d4eF?T#5)BlK@YvmnxG(b&(U!T*GpD$t8Tp`DzL zTfu@ta237{ydGYwQ;2c`7<FFIOdxYE1YK!ODAfBEjHSV^frKnEANPh+LF-5!WBHxl z&O5KljP3l;+(4HhzR!2Du;XUAO>*LkOqM&*0)BQfayww=%JYA|3RP9c@a36XerdB2 z9ph>@U$OkWMi=b?t~<Ct)4Y6_yf{5C{@~1fYn0Jb>(V%~X4{$qc7P6@FedXzp(k+Y zUbFMHF;JeUxl8Ydwg@65IuJ#H17uH5J+%Mxx9vmhnCqG?eyBWN0$*Ugf>usPh`Hej z=V3I(DzhT<_uF~iP4V{ZwrxdBq_4F+T_S@&T!d=2pEy=M0uvx>)y7ByHf$AT&7Uz+ zkAy?;5~k8OQI06cf0#~ocfNeqAf>TII?EdG?o#>}c3U0&6S+t9+NQs6vdy0BQ?fAQ z!}OTZC|D`Hb<?%fEJka-finwO#I4v@IBVx_nTXr9OaFr-v#_O&zTRulCAYe-`likB zp_Wc7yvCG%F(%eLf0Ndj^d_u8?@vCzYMb!dqqLLY)e{zPNfdmn>NTKqEh4^~K64H{ z9IpQZ`27I7YZY@S(H2$^dGWCl@+FT2R*GAuXSh$lts*neYUNs@-`;N7FAd@7s_;Y@ ztM=4NXpJeDV5Uut)fEFPO3=4)kS;9!0gk#WZiNG(5I!EzR8?1dg_89lv}f}6WHWLS zTyEdUzBbq_ulf|Jf=qJBSbDT8p^e=tB-)*yMFP}S=pl4ogpV>lwO=b9#=MX7KfBmX zc92GpIb)6Z?zWS@pS-V?5Md~IzumV%S3c^Jq)FPhVfBxA8Tj5|Z~=Nm-^=8<HbgzX z+BbEb5ur!si_vw$QmZU|qbd_#t!xjzW5(lHzlYU4q>d@Gy}bLc$gLw2^{PFzww|Hn zqYOYe%h3PN!8o)(34-HssDJqVeIxAe_huC_Oa5~adZ`pZg-0u_oM8#4b-w>f5<?hN zt)5>taL{8AEbz12=T9~34-LM#Nr)S9LuPR<XblBObQn<={9e@V^TOB4VRq9D<7n$z znnfcLl^xwE3ufd`tAp&;N>7h6JPgvM-1jSjgG$a3opx=1c)P7=A$`BRsn5%F)~o2M ztFH<(#6dDahD1>g(j^upij9_f3!y`SQ)Z1fL7By}X19r?pdJRtV>AJ!)b+6}t<#$v z{{1OQO#`J{(9bU{G$FiL0~)Eqp{IRi&1<h@E|Tiycl#V5!t*^0oM)<H81D^Ed~htL z*jc*0`SZ(SK0}ChaP%%RMGXo`%pNn5s^;qeR9hoKs3WI}f&Lw~ip(Sg>9-UR-Hs_W zpvtwBjTX&r=MW^0$q-U^j=eW~TKP9lDh$FEh_gz*N~Q~#%xGZcIoADUC|Mvfr1D!y zq+dkD{L4SMm;YvA#&KBND_57vjjz)&2&Wu*WezZDOV+HExb!TPQP4cqN-|K&V%e!x z>*i1xz30<#ZuT@CyHzYzQCwGp;b}sa5EHi)wesSWH41m2??+<art2y1NKrG*xx{r< zPpT?Fq98{;xf@v!t8YjyDqvf68ouVE*SHjgsTyZtkeH^Drrax<SWb-qQ=M|o2Trmw z4#O-;m)_dpX?SWeltYH*rqXzN?`4o6W_<3j07sVISrcu?DcbWk^{RQzvHBBLCMI%X z$N(nfh*1UTIQ!(Q3YL-65CScxYw>OEJdRrPI5_(B_-U3@u_rJ5XA=9btELbWZ@+&} zDyQbI3~})M67gE<!zkSVz1O*@nphx89OI7%cX-{ZswU~&N&W?#zx`Fjluk;+YWS*1 z`S;)#1u?cMf@|EAH5kd%<H<;+nVeG(JjclDro39trze7jm)@6EJ0&N9N*#jGSc_TC zybb}bxH6R*c!7t2O47pxweEl=O-UH9?3BJ^87zhdrC<6GDlo_J>_WY6yNdR?G-?~l z<3whQFmRs4rWLhc+SiwgKhi{*%BdQ-=nwWb4*=RZ=V@Z^*xdn3)$PCg!M>%eB=td( zhELQ#sg~Bd<KZt6pUDZ8MZsezGzSx;GmS*mRD<XjDoBse_=+6%VXBEbG~0WkV@;5e zr1WbNcq<|=hIchE6^EMVow*N*i(*=7E0tl+GHK<tmw%#vbrsagZCCv1sxTpH-=M8y zKaPssuy`lYf9T5Et3FmT^MYnJXM*-ZD+<3w=T0N=Z^YibnfTS{<X5QgK|gxpmtQXH z@v4PWxg4H|9=gs06a>QW@1d_i@e-%W=1wzQRQz0LWMDphuk9(L=UE0Hz6+w%e3!bn zf}m&1Q_jBL3V0V8pPauG)9Hkpk&gA0zqlhGWicEOXX1QR9>sB1m%G@{UuQQzWioIV z?P7a2d=ZO1YeHk$1zb-qBRg=k42SX5Es}voARmXLh6XT~j(BgI^T!KmXvyqyhsP?Z zy;N8}_|CH;B%73n*1V$~w7%@!dFn?NIOOE3Ar7h$Na~yikdpa+*H=cah|3Ert-ZH! zJOE0EC?o82FPfJ^00>!`F9Uy0^3GH*gVE|@yk{jdGj(VxO#Zhm{gtqn+50~GYsd-d zD%rFsTf7LhajcQTsbJ*B#9v?!n3_67r#!0~JGX+!l0o)@VD4St(u8R~d4-x7PiEl~ z1o&%no(5l#IKrsXZSdiqFUG<NiXHKBIrcG51!W(h%x(XOivkr^zte;Kd+k9Nt(#<# zcR2@pmfiOYCT^9*P`;^3bdUM_21}N-W_`4xzjvFm1Q8#enE&>zbMTzw1U1^VLXkra zb2S^46sJ^RHD2;DB${|2_a=0_Zv-|<D3E1FwI|;)h#@6siAtG+X~LAsHR}9@1oAGg zc#MDs6P*MomF-w+;*`<xE>=^It3(Cbmn!B-MCSkQnRRp`?9NWQU|Z7F{aLeTSeF}u z_Y>4IO^(c5%ChUmjMVHdH0hF4X2H+H|6~^oM7WS<Es?EC@}Z{IL6HvM57McV=rdlr zIC?*F<%l(;LWJtz^1lr4$9SjS_ouy{!P}ItHyUh7r-qZ|B1uBc?;~!{GX)dLC_)Ch zF7-Tm2{!j6PlbHR*XU!Kr(Cv(yuIHFXLfDobOE@<g$qAw>Mi`%Z;pI0AACV4fd6d2 zICg1g#1X>Gcodp8;!FCLU^UkV)62ta`Lwmjsu+(WvV03?aMeVUM?NY_Az1#1_w(A3 z3Taw*SO2}N-pjABV-;gTVH#b26p@ow6zdu;qXRAf+jtxYZQ9%9u`^OH?3MJ#bfL^m zHzxaIzQMiqbKXpCuZH*qY7(gO^iQzD6k1eMHK|O<lysD*JDGAMpF)0nx~_fl<@wJ| z_6INzSUQjzE*hT0xMSy+jE>I6==dKN%_ZLE$TlANOk(N5PVAk1BWaqTP`PG$C7P@_ zJ_js2+i*ykH?)R&Bje-nOw2=Se^m~4kdeDnD!YB*9i{tqFD7|rnM>xfB`~M3ST6Ms zF2$#Ts@O!2fnKxSUUif9$?O#9Rs`k8yR7<g#W=Pmk=>A6q??m9<HL+(nj>(c8B4Xo zCTG#28L<XY$NJNG!Y6tkVp?^$u?&we`st(pL)SS6XYy_RekOJ%wr$(CZQHi(i6^#g zJb99t*tTukxpUv&#d+^Jw`$j}-G6meFI4yHwZ0#H21?`?DtQjG>S(a~ktTDg+6-rW z&O}$|??7Z|Bc7Uh<cXW(p>s8u%9M29T!`Bz)A5>K4i6(^{HlG$QX_nEeR7J-U2}ts z$&LVNwZA+_SvX>Vuq=D&{hd`gI+_`kQVvRh9wi+h`{=0j=(%>Wj>}0pQNAO9cF!_f zUBln#>O3H0$Mg=SMwTn8nN&i6PtE2>;<dAiAi+`C#4n7!ffofb8?<DzauadhTkFE= z^r5b#F_di;-xM_)Zz!``-ire?RsFSkFOI#r>y#*wPE@oJop1mLgVAl6y!)LTZ=CRH zPQK=^+MVi>E%yRCxcDOq=3$A>0OkU;v_I;%+ZEo;QwVrorD&<W>ey$-B9z_5^eKln znMYos&rG!ZTZk@F;y6m4Uro)^0HG361Bb}lg_PTLRc#&kUbCXVJ2pab{&36qo}osR z;6>6FJfwBdr$x*oIws9)mc~D!@!Msv=kMu%mQ!RB@FdWN&erwRB<Nv9&D}*piRDOf zM_}^)z+UALNrELZ81~b4fkXVNcT7RcGn~iKPi_G1PY=BK_J;^zWZRICly`#W5DV%@ zuG^{J!Ujv<{fW&A_gB`<#hS<Z7r$Cr<yuD%w+7U|YLH(V`a$sH5afl3ar)!mmVy8B z`;LBMp4UoVKUbNkEM@0kY(L(b_#;mBUS00S8b|vY=TJb(Asz1)dT+jP3&B=os)Lq+ zVeT1tw2V@Js$ZDrhRQCA7ocFXHayGvPT6BdrM?xHyZF-1c0Us}??XQAVt(ZHLo5b& z@~VA<vs8oN2a{kGCZ0BL6y7Ot=q2O28_L*CZH@e|3UI}*B57*hMHtYH(0xAPQm&g5 z%+8KS<XwKaxsM3Mt822i!*nB_3+}E8&hBU+#;P@r@YwDiRpcOs;ChI|8cS9(=bCFv zPK1^<i&{12Q=K3llQkqa0HNp?DwD-!-=X-{o6hgw?=Qau^TJ&kxWrd8g_bC@_py^% z<8t=vVQ-F~vhvX0UaO468#8L2IM<0tnL5$#b&=R>_Q9XApG9MeqC7WK{bN_97Ts%| z>qK+SuZVN~&G<Q>))p}ARI;R|+(B9lOtLNtU1A5*&$V<R{GQgJWYZcie)ZG*DqXY6 zbO4r+Ht=TJtwFWrOvqcWPKT+cb;vUC?PdQ(#~|D1jxk5{Pb(aAa?9y2KkK?0JTdWO z8IxgQX`@E{ojIYoIpFXW$aHxopOBN<!={O$J=TgGJo+HJ(-CAoF)h-Mq%lu(0@SRL z^TKO%-61Sr59xE|WEPsmJ$QK{d<oJJ9JLYYYDRg_wVcQItZ@<~J$U)F6`7g%H(Slj zX?!OjH5$b<cjNpJj@``pAr?8t{Hw)j|HKpKHjKEy(!MCC#7ZWBk!5-UK7A#kgScl8 zFAqFVpEWIuoyAex4@o~5;}4>WixK+f-iu>QBm5QV=(6X}^lt?2bL{6VIWYng^|B^2 z5>`O<^J~X+RFoZUH|IUv9Qx3~HE0o1(lRWPNA=9vnxxuXsp|0_HMUQle5KD>qX<BM z_Byz%f(!E%A?tba1+$MuN&nhaVfU+g(#gwlZV#tE69@Stll64~pX4o$@V`3y|0S=) zxLKS6ehQ%P{Su)2eU42#D<^9j?r0cdc{LVDa0)5hsie}ovsFc$5$MC9AYfA5$dT3` zVl3C?QN7Torb5<qAFis+f8QN37;yX<R9{dlVwEO|2uZKOgIF|2Fp5AW{fhf$TLrNq z?rsV<S(HmhXj*8xry(tw;}vH!EU{}K0Gn`d^6Xci@4@gTD`tcd`-yva4GI}x^7g?f zkdYYPz!S~t367`zjMSw)$N|YLu;PAH>E-MLk1Hq8DU_<iTa-#s+4wX%+2kb?=VdY# zh9MB1hZ&Q%7|X~usWN!aBDuE1<osPyqO*6j&pc)cwoCU%v$ed}Sr^V4@$WH0DbG6G z1MFi0?k3$2b9z>>OLOF%T;riBP`edjksWggyiMNiWGugs9<l9to`U;G(x<Fwbpm86 zw)jrP4t*;9<Z*qUfk)V08U;>C|F)kOORo^yWFH~DF1x7ih+}65h0UBi8WI#%BL=+> z*^(YlaJL%%C3|&a;-$l5b3HflmGFDZ<2?lSZ|EpLV?has@L!WaXLKS}Zo%YUCC>#y z`{q8k+-nO(M_xKPZe|9;IG8e9ZVxEKLTuIh7=l+<d*?~{mbUnHoKloFQ?|hc-ws;Z z$EUg${VTSRm_`IHPE-4|R6XRj*$vrRO20ir?k@&QMe}rkMw)JL{5Ryr|8<W}H)H(l z<q3Yei@TVJpH+!=u%X0mXGXjWve!)a(-Fs55X9xgxV_YkE}Ybh1DTv$izlKH5Dq+; zvvNPBx$u2W`EIc@CfAjRr6aczRlmvcdV)27*rekRhgjUij%S2+Lb6C?8+$3~$Z4C+ z#M%t1+|*&fn--j>`v`3&HjGS$&(U1JQ3+m~TKJp?ozsE+Ion}E7LK+ndb8|<8{a%P z8~HTopn{ch)bVZA?3fkCAIt7uY?}nNZIbS-t>)(YzNyOkNU$4IZyOYfMGfPC0oATk zvCZ+p46U2ZwAr-XXtwoN06;pSt+E*sTt0Tr!rTh=6RFgrDwIx21a&QV%APyk!0@)r zdwz?w3e+#(MLQouO1FYSe{C#fpWHSfWFL$ZUYdY?R6VKG&f!-?7mQ>e4_G!aj>0^Y zXJ%WeU?dF$?_|WI7#boK2t5m!Zp8@FwYk3T{`z%pzL3H}+h<2*HW^4GLz?-NTE?x# zS7tF8q&ycc4{b?7{Vn85@bxhl{HTm2CFm!_JNV`|7n0KVbQ#MR4NsJKT&~+vufm?j zD98b<9`7Zlfr5uj9vCo0JvJfGMdqjJ0u+qi;4%c${}0utt;`-C_OmT)cV%h&iV;44 z!^R?y{5jluL-L?~bPy>ma$P#7&tH`Y!7nM-?}r@P_D?mHX^Jz7rNt4e>wUDgW-E>8 z+3hl7hMZ_O44zRsYUFj?8v?~Nh;(Q!sqIP59uz)CPIU00&XCq;ml^N9E(k+MCe^u& z*ons}hnK~-vZ_|8F}D)z{feRSyrB>Mbun0-l0jP{k%*APmW|<OMiSc=&v$mvlH1^$ zU4#CIb)HQua*ewd7s7@!!<7sp`$dpMBmN`pY=Ob$v_Gxxa<ELrp>SGL&6YHpbKFro z;{e${`m4QEOvl#}b&*83?(J<yX5c&}$MJaVxyPmZWs782X4Cam$ojwxVc~-9L*91_ zX<HRn88D2(3U2;;aV5}fPWmk}BM_wt_^#z;?CtWo=5L<51?U!1t7y9FW!4~Fe~n2^ z7`=Fo`n~OpVcnf=l<Hib^jjAu41n(&r`QwtH{LIE_&TZ|*FofkK#~f?+pSF^^Fsxn zG2xvB*ubN@(){#`U?VgtM_n%5)(hg@gmL$sq9&=x6E~;9nzaXBr{OqoR4~K}XA7ro z?TFeUt;G5~W5~vTN!kA}v;Hf3tJhT9!a={5Z3{<NfcCYN&tRtRby?*<JSr(u!2$J` zjYD=NX&?f-3O&MTyFZqgg!mc@j6)V8UakxPS-))z14QNQS9cfFKsEM;i{Z<ygP*cP zPgguJ(J<S?f|)m|!)ESn@x*1Q8U^Wj&Q$@KA!+Dp)DJXh09rpqE++t!4^01%MYE?n zuQrO+Nvml=Y48+DyE>{*E2=jdirR_G#-JOh%X7c&vJvfVd<h$xe^ro9|7^2QGlkQM zZN}<tG7IdwdNP9B%6Xxp2O@=>EFv15cX$McHVtlOXI=CY<_a6ZOwImQ6t#A`e?`xs zBK*LlGBixj`}L)lG;`M)PZo=V{A?OFi{Kt|8Qgw=tNItVmXo7EfZCPqVmNDq8WyLo zF{-^^*}8?oc;OY<YVYtSOVXfur8uvyiJhZqzk&goc8wy^?usb$_h-O&B%~(^4y#Q1 z)@0`0hF~C8pffY6-v}gSm2GoTm$g#n0PIp<jV5%|mAeLSqG>tb2`C&}(zz_1Dt&&` zFuVU(Tt{BP^=bl&0taG>2mGv`lniOCTC$yq|05lJ{`Bhzi@i|YP@Kud!wJ*PxV3c{ znD#gFTyCfHHcdR)22id414R38sd>?^5-M_!0CvB1#$IXrv89vq#nkE1XxG%O1!pXr zChS2l)p-lH7KiUoM4!kv3_c={pS}Cy34Oo>lxm~p9^H0X?1TFgQI(fCsCL)m>$n-W zx62736B$p=Z>K6y&~_`tO9hskYEie;zuR!J%Kh+s?2=UXki)Bgyio#zZRAZ|gy0MM z#Ep?0;=xyUvBnJ5bh@>56u~PBRp5<hl$DquT`d)2JafZ_!s#StbK-QAwxdT)&~AX9 zPP@o!SPB;qBmHP&dua?idfjsHF&Op*KNxGt8wW(9Oq%Ki@L7xHq-Qq`p-~fl9ayik zfG45BA9d(`8>G-=RdXv)BOSEzG<@<yaOYCc<-I<x1~o)j{XqPudOMMXD}hv7siP)m zi{wstm2+M7oDZNA4TXP%{RJhK54jx(syTHD!VYqQ=&5C62Iu)=!6<;Z-3KFfjm%Bi zoBb$iwiw_sRlPsCdQH@m#>%o$^vT>r-PBpubBey}m9Jn1Y{tn$;LnqO(&aG#1;jg$ z4Q-VWvYJpknva5E3-f93d0kKaOd!qoekQ-M+-r8n|2zM_pC#O7M|oo1iYv$WvBBl3 zaB6O$owe=?8bNuizc^9byuh6Vj~!EZQRq;!k+5&MFg?Qnu}tyYm}FN8EE3;T6h%&^ zs)tv3Q$>%Ecf^q*|JCkdTQ9+OR8fsHZz+=jQ+7*Ae|<t40K$@FKpI9i<Nem6a4~i8 zwSP1VFwygNfLp%z+sbFvGY?$4+Wfu5!*R9Qq2(RrVLua8BYqps9B=cJQqtLwC6*q3 zDNim1!t}r6bN<iO{&NB<gC49L(Dy(aGt85=&qka>gJOld{Y4q1t7Hr4D3tjP<327( z=3QOK;$sa#)n?J79geRv-k)m8HvdRkbpZm(Ch}JHvk(y7SSxEjxRr5cdkKPFLYJ;Q z|H`(`jXFDi&Q{|iwPV&C(ZnAP^_BV6Ckw4`*u+NQ%{ddTLXd~CVn}B#y&YnfWMb~W z|CK9h7UZnvBSkY%nZ@KdxI|DcY_;^B#~@h|cULn0DuA9UZAXG2EUD|{=rQ~t*(%He z=0xQdbivGKhWOny>|FM=N~yZsY5RJow4|xvJJ6#loWZT2u(C+R`9|41shLWh&{-M} zT1GQO|Hev65!uTaltx*)8hiGNYF!ppTT%d&BzH=}j$w}Tp&XB&m_*7{kA?~nHQg-G zm-~<mrj9C>?y5xB$aCoR%>MOuf$$qR>4Y^qa=fIK>V;Vw_rh&&sT-$fOFo+dY*bx^ zL(1lgie0XI((D{}Iw&_3$&PN2X@`)L53sbwnturf=b-UEfl(UaQDHYztP_n~ANYyK zMoyX>P`9tS<4=|7thfnvq%Ybl?c~1_i|r_WM8hQKhnB%yYXyE(aUuzRgpT-z1hGke z&;eniXjjXVy}6aluoWW@vEiKI?QC+x&88D$oi^q%beHt%s29?TSIJr^kZOtj^Zx}Z z{o@hK-=@j1rqfqCs3&O(FtF}ti!LrMZg--p+mF|KIkBqNXaY(VXY@R(&+8s-Iz3a} zy@;kv9hkGq>5DyS1Il?#I$O8OMxtGWQ}A>;Ya`pjL-~zlerIwbyT2K`AN+Pro+xoP zQ-EI(1v_e0hgLjG#j-OP2d-^%Q}eBM|MD^W@&e&ZuKdw#CIZ<I<;GVI@f{b3QA31h zMx6)d(@m(bil&XWL#N)I37kV?j<0xCiSfWZ$!5pgx(e<zzQ(2Y87-JIoE!(Jdzfji zJ&k95Oj9w8z;=!%d#`^{?q(<E1!lISB$)m?F)mixAzynM{%w)7DQHwt>4kfLaqgQT zOI)X$=9)yHIq3=NqcpVy`tKb^<`cBI>9<!9&lU~S9KDFa<!{I5s(e2ViLn4_(?R4( zk(K>cH72V1shl;S6Snylx6$FFrA*c;0>w&77U6MrVyV3vDl@S}l$UIr50j<??DAhH zuOtw}R(^UutQ!%u`E(@rD$Ue_c=1PMgA;tVTX1;flyi7X%>Nn3(exb#7sp;^<)Jq_ z0z!+PmXH@_4E#fn*Z`%ie+g$+I9(DtY~InK#<Pz6tdK>a7_aG)va>4jQtzSG1N1ZP z04|*t=gKAs95xuu2#NT5Nd8__9?V|?X>?ThTkv-fdzw#8Z<I#W4j0h*pak^!nLO8A z`kwpx3x;CLECWQAxW#}RW@vO1<)g88e$ZyNLC)UrFKbVxC~Ur23lVF}EPT1I-Cc0s zg^PIDfK(p~KW>9Am2N!;q4Q6LVrU(2H^HXO(D!f8%|tC|w4q@hnsY<w$G;KOQ*@7w zh4ccmXl3aXbp$m-;|P3|nV~>ks$H`MP<5ZuI6*s!nMZ~C`YQKbj~&RMM$TqmbH;yL zNEf%_yAREC>YW){2C-m*hg*HG)4^Xd6tN66>{SO+cR}E+7S-9mP=-Eru-TSjHCWRe z$HS~MBFCW>h?Uk5*1#Dp{W)32pZSsFeKb&v7uvEzjM0;XIRfKZ8&1!T38~H1sXpz- zMY+BrwdV>AQZlEBd}9l7S(Ka62dgTsbEll^{cGn3BfekOxq?BV-M#O+2l*OyyS<be zH+G{R+n=W1ICw1wamItf7$Sb+?j?a3_#K@bTTgPDU5(=^p-apbcolcSuw`l-N)^() zPX{?ODK>xG95a>?J1FKer#jb%o3U%C-o!6<;|QW_i5jbEOr4+9Yz;`Aq?VUXMhn-9 zwd}#KQdB4*+p6$36NK!&aZ{;xSpLL#Sw>b4cKkP4iS&P@VnFS)*(Gp8qVj0TkL_?k zb`7qscTiUi<AWo&jIO5b);uyXlwt*wV6{A6ZFX?q%jbRcg?<GU-W+XBs{RN5+W%z# zq{Au{vkhWHa&%qzchKtF=~mw6B6#%EIW_shX<&JvCC%tL_uI6KpRH}R!!Kcc(ZJ$3 z(k;}ks-$clKto#%cy$NDOdM>isnsiTSLlc<XyuA`ANk$mUskz5$0LvO!4ge+JttE8 z8?$_Beux4k*4(srq!u-XmY$?OVsr)KPAS%E5$Kb=!}$!>e5mQX5JD6@wjydYji-nl zZ~SFLruo3uH@0}d0xE}=VI7renPd)mya_QPg4muL`f-0a!S9C0RrRui2qYBd*<*DW z_5k?NLgO>BfK|$P*UbVd0vah)yL~iCRiAZ76CcBdc)!KB%IF}jr<l*NsHE8(jUIBT z4M>AH{29>Mu94Qqn;3orfb)x?D<={{cvL&|FZrUqFAg&0ZoNBm)W@?;t0<<2_PFe# z<JiAHvfDz7G`#oDY_{p}xTfhBK8%2bf=y-9LFxQ9z0UcDTwt#V{0=rqXSlw%Lj1~q zLVsMD5PpWemLTK3Bdp6j2oZwTns_$BRnYWDA@?Yk;dNZS8NG{uU&Z^yCXD^0$KQU# z&w<n9><jdfNN_phKHsSOMy)UG#{Z6zd?bkX0<P(&jT3ij0NKdcTgFyG1W$#yfW(Yr zK&3DCv+_%68Xfog;JDxjY>Qu+k&6Rg=;vtE*cznb?$!|Z_leZjPi%;Jj$y2+y>D*~ zt3yhxN`pmMH*(zKxWomY=iw>qpb}3zP%d@SD7@XDi&?JKgBD=4N4Fe~>-DN9xMYo& zZ)pSCkyTV5Yy{N%{Hi;gv;<|vN=F6UP*R|NuS8&?Jz^4de*x!@tPuV3Evh{O^nQ`( zxaEw;Fw%PMA2|$t1cG3<)Wza7?ggwMPW352+2?W7Pm`WSxsI(*uE}dky}<;9A~(43 zry^aUViP0q1L&{ZIH4hl6>b_{ftB&kOe5G;!#_OQ{x(F!DT=teln{$j`v&~pTmxgc z1xixqAeu1WV+^ZmP}ei&BIX{5a(2KYfubv<!{`ArU=}S+?B=ceNDbiSuw4ohWV?8; zrct9edwf>TihBEUo>9a9{~-g1ZRWSC+gDR~zpsP6-r;pNIf0TP;IT9NEa?$4>QQ5- z+^vC;A624Tq_BWyq+H|k(EyYOC{z<u-a@9dD|ju^L`JRFzV+hv=ZHJ$RlV3RACX+n zTm7JTZ%Cv+B}}S<%M5w5gIuaD#kf?Urj1i$Q9N6*3FX`JEHEZ?ye!XbQ+5)2k#0$= z-C>_<SuV?wVIDactU5HQY%%-_m^2Hc4_$08|NGo80}$PogD3kW5FI>@xg`f^uoOdj z6en$m-6f1(pK$`nvhnT)Q^V)H*cBZ=Yua0tX`Zh=Mpv*M0(`tbqNH8(lE_!F{Z2!U z56V(hb~dpyHbO55q<!OR-x40d8mWCkjUP?iidi=+TQ%HJcj6~)*e3$xb{Re6Bsg|S zzzZK(Yn78y+bTqg*CCb^g+F2NHu8PmRpO{IN-{g)=ReDhm8=IrmrP#jzRMVuEDksX z`nTXL<ad0^aVI`fvkS?XSBD=h7ANGvSv*?GaH4@Lt=qhrGn71C>wz$-x!QOulRU_+ ziBZZV`>+SAZs=uKq%Lx2TjHGR>?$OsN~JcNUe_a6{iW%a4rl!Y&q3Y)UKa&8nTZ5e zP`8iVJ<-?GS9Vez)!7Lrj{GkY(|^4{F@=5o9fA7i2M4JH(%-3pv<wn5Y#F|i?!p&p zmutV@F|63j4Buv@&o^9z9qR=fHTy+`UA|oen-XzugC;e2EtlFk_TAP`^y#BF^?4AI zFgGzb;j^Ss7orzGPuMGHc+h;MDrG1wsC-3RV+;KN`>z$cFunR3u!voQ*Q7erP3G`^ zK9^-IrNFNjc~`*9FW<)RB7>8)O1H{ks_gC@MHV>lDp1!b{`XVK`Z_Uee_^xjjhz7_ zkz`$eK{=(}`eB_S?T3zsfreRMDyH6$vCQha%F}!T8gJ>~$Mro5)>61(q;FFVxJa^< z$;nmKH41wAnO_y(v%6w72i&Lw!Wa~?>m`rdk#~*7Bm~Gl4!!a1l?G$DftoA|09|HU zY9WdN8gL^s<}|1U>g}I*(0rHhDP#ke>m<%IkywNM%S45sK<4Gc`mJlY);($7pT9z+ zav^&u=I2wE2J8l8G$TsDC+u8Z4=%WYN=ng<@9V)BrTA*o+>Et`+*h!&&3aN0=zu|` z!Om1&YIumaNV<?XofnW3<fIkd9I+_w4sp@2^I=`%v!31zzEjCy;M&JYus90dnvwG! zI%l0zK7`fTf0XR;l`_Wn(ZyBU$Tk#oFp0x^!DW$g(E$a*iSc+yE6@2Dan%^T$q{!| zp)`FyzpDO>JjG^oL|w*+A*#pzG|FP`R8@ISBD`O_z5~Bpnf<yn+IVO9S9rBy^dCzi zF&hEy<4|iRoyd%LY%>2IsI6XmzZ>*(b=-3+Z|Gfr@Jm*YEQ>xB`wEa8vi1_fjAcwk zbE<t6{`{#LB2uVe!vA-11ea~z#AXz@Hp%|kwU_If#_v(&<gZ=b<)tgQkms?`i_Dn2 zG~z)vtbbO!7_|RTjN@+zCDz=|l6s6RWO0Rv^{+8d`cuMU#D36NN@j=NW3T(QMX5q% z5tKumP&l))u;I|c$Uo+$Dd_6v;ElueDgAvsXuaYfaXjs^lTL93SJ|PJOUA>ow%)XA zm3Q~H>QBuh$w0cGW`zHOGCp)O`a9IJ*|fpw^=oGRU2qKi@42{iikj0CbEw^}vMk1s z`_fC(6kj)5$;GxgDh-d5X<tDvroP_`AMf=h#kH5oSQ;Mt-w#sw@y46XrxCR^o+w2J z$&Xk#nb`^od{BvE#M?(&G>P}NX9s=?!iaDzcbyDGw?c$p;^7l@$$Hxf5%k?+#}$;k z8E;4F3+p~OJAV{sTBej<PPa8w0FK@xwX3&lxP#ueUaK8kf2#O{&i{$XK$j@BH>v1x zoW!arNJo_@L-X1gf=<_@hIuz+HemG3E7RRD+WkXL+U&M=t7X+Zh&s{n$D4^<r4d}i z+u5xTP1OAKjgZJA7wALL*$IsI*I}|o`<1i$fRgobC4v5V55i=|z#oVz@AbdK_@7|@ zuibN0v)mpAT;XMmuwnVVbjL~C2Gl9IX>#xsnuobV!gJdGJ&t09OZxRwJ(b@kO&aiF z9U=uezj&7=|0@w1QX+Pd!`R7wQTTEsEWGscdM-hHFP5O>_?4t;0mzl@?lz~rc%-|* z{i`zr#x21Dn^Qx*yvHE+=VtAo$tnE=2DdJ9Zza1LXd)w9I9%+Y{jys@GLCM3kBZ|) zT!|~##`#$(YwUxH<>WHZ<mTdX?HC*nKo0HWF(VFo&r@M=_6zV-sYv4$$NWoz0|3ad zzV6${m;F0*>aoJAJz@kAo+b2bF^JvUSy>coYMVKcqE63RZqr5E&(@>xY0p{i!gAIS z*wFKaSjpje_cAhe!!JqxYIFa2DSYW)@;GgAV8Y!I)wmHNDzysODF+D1j#XuLNgWBc z%p;C~j9ytnz`kM7U;Tk2*|3Q~f3t9#*VNrqqdH!BiY!?k3&kh_RHgN;i+FLTdt6TZ z_JEi0@C^~U%j)_-nEetFY3$Sbt-t?zZr^E_aaF#dpx+~%P}O5`U3i12Zh5O;;_YFS zjqxw0`rkRYEOwCPr(@EFQ@W^e&8A-8Zr5ONs%GojFI&6b@{2PbUWOrg`Y^it($zKt zBD#;|x+elPGhny1R_u#d#wsC)(z0y{^)Y<S0ZB%yZpnHZV%eV&9&?yF4+2RPSkH8d zO^iVEzp5h9nYB6RX0$Kko9v#zD8AP@bBFT*7K?fa1Nlvg+!3IP8K%z_b~0HrX42cE zg7qzl45jftPnv}~6E)OD+2oOtNr5~uXAmv7d|!!lK_SQ30<p`ZO_CRT3SjVZ;%954 zm-FbA+#(QTPTy>6aJ45u{g0LY=x5k$r7!PwVf^b8eF^;AK<g?iVCK;$y+&GK|83)X zIZ&e(+Kp|Gj)qnrWQZ7j!P!VdIf4#%SxDT8zUIU4V0)R9RuP*r#t6@E>&k4atz;?d z!OsM{V5#r(r9uy?o1jS(mvQ@p{Ax#G!R^pNx?_3Kz$fe}LMqd${ae@JmA5>Q!|0Pd z$4zq=FeS$Tk4R8c^yqkacp4iCB>jZQMib8=e9F-1K3I8@{8e%N!GT6@aLktR;nUgQ zh5*3s#c3%vCo%8+kh3d%0$}4^fthdTO(^rG)?c*@Jt+szJEBCjz-_l;UayOF?<6Sz z3%>x@^RWM(XM0s3?9CDF%`a%5qPYB~MSKeRawXgbDt2kbG(*w4!W-1)@^nlSgB430 zJ3v*sr15_%kK!K7aFW0wiuFKU=u#pVl^9iV!3w^(w&wuYGObaARc9ioBwI05u^wH9 zYY0o~mhxA%Eg#uAV391v>Yj#Bba<Jk&w$E5vcANql9W9AB+F7>J@<?UI>eH)?T4k$ zo}xW;xM<7aK7I4fynIR!`Gr=?Y#;z!obn1$?g@85ZrddE8T$Ztu+_d&uHV?pq$Pj? zgfBLrHG637Jy%Y95PK*_hb{>?cuiCS=#k^lwzdRHagg@`Y{X7WMIn!8c{tL+EVj5S zUj>>^i{thY5mc+vS@jniMGs>j7pQqq$9sb!HOCow?gH(G`ZoUH>>kHcG-Xe^m5IF$ z)4B9vaip@t0!=%<0#8I+Z?qP45AKW%(*ybUEeX0>@AmyQ)YbL$5e$-Cpep;za8~+l zGJFCU+X~0~85QvI-whB<NK2m5T1X4Y#SoUTb^&vQUWDp1QEgtS$%gY<ebx!j9sRqd z1U~zT-4kM6C`wP5>gh>U>6+ja^xbQj9sab;gWehb*6jJRy-{{uEelPCn;M9?5OJFL zT6Q&L@=#aduUu8Av&MJZ*#4~Pm!ism`VPmxNmu8LDYy0t>UNsWubhw?5NH6rh5i9? z74;P$s;I@}+1BTxSb3j$6v!w;Pbstd5XY<jHJK>N=38~f*-yM?m(siKRidCQ<<=)o zuU+Q`^P6Y7iscw9Y{9H}p@gCy7=N7#FBhGa9^Bv=ZPGxrrs-k7)eZmT$Kgq*n7(zL z&3n`Ik$CH1Ff%_vzhB?a)qg>pzUEt)+mAZ;Lyd_INT{mOcD#Dh8wc*V^lg$}!sKAY zuZiAkAiftz?r!4|PZ=YD{#C7}+XxBvT|y6Gtp(2cQl_AzJ{guLtF}%~3SSP2aKBu- z{_OT`KX}b<8upF-*-y1ghR$M}(qY)lC&NKri2A6P>4z=jPxvN4LiN<N&QI3CKc=EO zyS-7lcZA_BRrj5C(j!J<*G^j0XVQPjOUCQTfVi^1o3ZtpSmh9(z$KJWS0DcpHHv!) z7y1JSXS8JK9_aRvZlUcFBbF|NCvl5+iWnt__}&=)SC7zGJZ>9WxK;}ZR-iD59EY_) z-EP=pW8pUwP_G~`OhWI#c=T21AB;3Z5O6(-82UKkggWSjlJe)zjZlbJrfO~UytbA% z0l~$!r&yl@BIsISuU^uTZK4djuLgHdO+S2y=JfYIHw;22j*?Rh<cuu@M%|DcLUgNF zIW80E<jX!rPcHV%e>C%Ed!w}|OIuULNxj9Q_^_7XMZ7T1eK8zHB%jW$^)B97JHUQ< z$3v2JVV}4yI=~w27o7}bpOy#b!k6>E`dr1r*EbTiTG|z>&Mx=3=Xrh9f&9}B^)I`p zgOWD2H!knCkc*7x@2>0}p(fi;f#i9NIgFLE`YCj1_W4x0hu-KF2$o4YqxT|TDtNv= zixlaCH;?;3s2e0CcLMU#YwL=OKN#@|q!`p^%aB`A3<W>aXEv17>rAH<0Se_T!vT{X z{Z$#Hc@taY83fuw%IAD6pG+T@DpeKb>{EwVy?G8gQ~|XChF_PMg|929(eL)?q;0R? z35NPq?cI_js#=|EpFIzq?tdk$g6dmWEFigEJ2m-97D1yav~;e*=KlCRsGEpq)l{Nb z@8H7-sZ^8Nh{M5cd3B)|wJCzFm_8y<7*MC^_<<eiH|-nq;?V7}7p-D?a^La8*)CCG z5)pfL+9I<r)t%>UM6F4Ahjw*<fj_T1yVd_hZ^VL1YbKgu|64=R4i;6~VLEG0N9`1K zS##2u@(3CR;kk1w39U?rNxDE|#I0(cIflw-FA2LEW(a|TD=|Uo0QBmdES5uos-KAz z7f_M+DQwk0>L^?Q>dE0Kdogz4?KYYE@d8k?ibd}6L*wyppdt)kz$J5A(2XiqvGy$w zLTPN87Ssd`S8O70V7T5WKB+3U=Uu<u3OciFEZaNjxGFH4-;fNMFeh+4-WrqMc#B$O z4IHnm&|FouAb;FFoZ8EV$5aSsc=98*Tin|{8tY$R?olE>+B>_w(S+5HFo>}x;yJCs z{)<oia}4wq(#9cqz=GS9H`Yq~uC<~)X?YzVR8_){`qWRbQc?(9vlLUfXtCq9+W!#P z@c6W!94%#kRk#)iSl}#Qe&48JxOqtdml5Gg@6+L-aDE<AQcqk{`HXrp<;wzYbvg^G zl=k+0Gx4hT8lym2>B^fV?S3UPXfnLLv>!IT<v+ZAw2)$@bz$3&Vkn#lElTje*7xl4 zD;+bG*`4OTyeWN@!gok};B+{=IXuSjfOW`BDj5P;i`f%27htjKbcsv{_hfBs%V}|u zmF&AhIFNm~8hTjgrfPQ(4G*0PT<kJAuI1k$;b@g$;ZdpA3}91WfSgdU2}GDXkOT7N z<J6$g!+G3&_*>L5;r4XZF@Y-w@;Tz~@h@^k9`BM7g&URJKBE<zF?H_YRK80x=Z&A= zj<Y6_UQ&j1(BEE{kb#4H6I3lbH=C$tP==XC!+SORA3YmweQ8z*0T?aZLwla(K04D8 zyFq{oOJ#4KVfjrgq1*MhzrWUvLCR}ONAoUGnpn`l<IQWk9CRuI9%F;5qSqTe?sWSW znk59TH|IAoI?Jtn4op~UzCQ}#yWp&gy5X7rn;E~+O6EPzWfK*&2H19AWAZ4V<eKHN z$a(5j**Gbz8>L4t+B5F~=551e#Y`{$vJSXPX3NIL#twM~t2b1klSwqJK0a@65l!Qb zMw?_dt<yySN;c<vywHHuI}QQ2?$fW@Bny_eA(KJ-s+Upf!{&W~Nda@S6I#z|Xn<a| z@&R>=p@6a6vL3o}%)%#0{EgYcp?v#n5lv)~zQ@+|#6)JpTiHw5j~>O;uL*fVtWGW3 zn+9_lHUoZ})yvu08X6f7wm`@3Z-Jxg+Gv-52nRBVcr|3Cu9k1jZ1&(bnpJReV>iM^ zCRM4TBuvjIo6xvSAY<_0r=Xbd#wQg@DZ1Aa&F$Bqu{#p600&XA8y0NN36hAP+9YlF zM>sV_XS3W!`|)?KPT%~rFV3A=wK!%t40G6>$FwV1g3IF8y#^NgJ~=2-<n8gg8Y|t# zT3LPrl+Dk&(Gl1AL?hS5-kN~QR6sAg+D&JTr?M0GcoV(#qW-o-)ZWkf*J4o^9dUvi zC&aN?;377m7)Q`%yIhsbJF$Vq*<m_zRe5a)+`ri?5ZpV97g+iNcX(<D!CBPd%_XvX z^Bmfp*4gcH<^3yRjSZ75eEyPcZE{G?+*iCJ?sp;<%PP}L^}2L2k5f@KA;!i!ZO-86 z&!*P{Zj+Ysvmv6tQwFPmj=ZF(t`?UVLl)^IAdn5S^CGc_w#n3BQ<^}HdFKMt`gvuP zRPFWJ&u%y7D1)!Y^iJRwJVEWLIf18Fsj6>Z&T6co`OoeQYOEwKTZ}#6Xm09mis|li zsXNub!N+-`<9r>Ez=4W#dOQe7^7XhgA`h4w)IdlhA|qfb8K&2*eTV+zLZn@WyD<qa zH>vzo3U7w$QX^{zhm$zSo!Y~Cm4QjU$jm6@v2Wg4u<HPySkziayNC$Pblf8ajA&yp zP&;}u)eSmmY;F4aME>HkI$7Lgm%=a@1?m<n*sje2W9waqqDs+Fs`l4Ev>mdu0S49@ zi`Ky5eD4_XD?wcCQ1nwuG~H%1#OcCv>$0>-?bS^MUdJaCGxtk(-Alo6ud^G~F2M?B zHw+Q2vNYhjfq#zPezcXiEua&?P;b1=Eaz^oc79Zf^_70X)<Zj;q`ySKwt*v!(&UoR zQRh(DiNO4C#{7n!BJ<33dg3t9`sD?swCk(?u!!pD=8!5^hx0&5&Z8c!Ur8s|>INu# ziPb(6zbze~O&cjJ%Z4{10opFQOxpjM&lFb#IkTurS&1`WpWD#N>CoYK8|iGj*oR$F zK-{6RHYWFIb4Gu(^J$~KP}sOQKHoT8&?OhBgWIgOwj&z)*f>{4OBG5fa@dsBuaXa> z8Me#mUq*H_7!)q=NjI2&WN@iOOmE{+x2L0o2yGl?)swSNMIBR3ktuH87TZ%p+tC6` z7Eo%j)IyxtT#YYajY?ihu?bTrDyg#VCqdROBhfD>4&!hMUE*G{MM_0<4P91m+KQI= zV{^7SIm16X55z7`T8<oF(OG|lbZ%wc=+&#{<fw!jxslN7{OWG7uDz<B>~o-N)pOr6 zbX$3UtzETVRJ*ScuBd9cOuFq~)JbN@JP$l$CZcf}zZg#`S>p<-!`I!vU5dZFly5h! zQ1<Vep7>ev*5*}!R^H;|)00Tp9ncHsG**6Ba#9O;Ku%|70KJs7+J1tCL*2kQt=|kh zio>(XEUyjz@4*-Nl>1K!^{*BGXB~Ad8BYvv=xy9V!OrbToekV9Df8)_#%nkW5w@RN z$ZHqAs#V&63!v4AbE*H+5&D;CKkQBLQfNLU^>$9=cd;L095_GLEn~sHzb)~xY`Aa% zMozY}XK$alR+^5+xlXR$JAFERtb6Woh%m#Aetm%#vub0%9UDleCw<6_3|^hcY%nc* z4drt%k(8v3@)s*Vrb<|iI=cDH>0t3!wuK8rco?inX0F|JDFS?tCTSc&rEJalbf)@G zs?VCbko0ZR=~FK#+tYG{M(FuuJeQO<()(LG5RHl0Dss}*w3!#BYe&h>SCB<w`rXAr zoGeM<F*K$Q5|bE}bXk?fh`jD~eSa(wNgX{Yd-<C>7W1nw+f%L?$o4N8eZGDJyi^cA z%Rh=AzWLLY?|&ws^5EMXrXE*m0oRf#)5z$}WHM&CSyurW`3Vdu<>!*L!ib3*ThfH* zb$Dkjy-EZDDLx0}PG+PNsDWYU!p?TE_OZ$lmSt?!SyhSaa-a`Rd(+#bC9CXeQ3dj@ zyfnrQPmLFA4q#fNFLClyaU+?U_E{Ilnuol|b{-^TZnkUIeLf=NiZNC*C1jfs3j2u_ zy89096N~ML$cPL&GoH&>CQJHO+Bsi9O;lFMSpMSZ&t+VQx$ptInSd!Bx+O{;JI&al z)8n7c$sXynY8O`ew10KFA|G=dYd1^BB%Ns-4eRd$&o*v&u{3m68<DD}M-IG}&$LP6 zU~gytB%^VdiIrvUty20SS5enid6F`aj8Q3M!dR<WzL_`Nj!G?lcWb_Vhz?0s7RR_U zMO2oo(&wShH2Q1ze_KRCJQVd(&1KDrmDgD>TiQ4w4k_7LBn`7-<sJ6bsBWsAG8SO+ zF|Q8CIojv|yfqmdvYCd+slhce^34z@<<h;>ugiWr${`7~%o=j;2CEV(GEpMJ)ES5> zdeM^EVr;!@U3F`>ohO^!S}Zp7zddIfZU)wBWQ9oq_mvnP1G9{qS?XN;1yqapqUP0# zjjFNPF+5&4ViaLwaXjrJs;rwA6NSQkNOs`yah0!x57^KVtE`o$;9)7XncbivlXM)D zDw1}a>ZCC4z3KMuy<S$?sA@wv@hJK6)|bZ3mfV}y#KFWdqc(PxlI)V66%)Nh9oi6L zt#C5fW^lFO^>y;pB_Z?V+Be_R+4&IKVyV6PoK&sv#HnK_qOH$ftE9-97p7zEuyLip zJB0^hFax4d6--e)-Y3#fTyl~R`t8Dwa7I7pRxkN?Yh8XG;Jc0+&Qlnbh)PV)9~qi= zp^i`zD2X2^T%7+jUH5A8vnf~j)dC<~&P_x~A7g~;`}c)<zT8k0fK)V!I{gc3zGo1u zU_QXC_4tWoCj4*R1&MZL2<la`ZG+aCfmWv^OE5C=W8*dX!`)e^iZj?x-C^L9o&TzM z;2CwDn(gE<el@@V{0qmWu9D`E{^?3M1yvgd%e*l~48I##&j=tew}_)m7K4mq6$w>Y z8?MfNYW8vH?R6AbhkN_ZVTdnR5^O=l)|Wrm2e&o*a@?YD4`k%w=>iW2jMcpq?W*S^ z>5eTjqizf@hNP}WZ$gORoY<C}7IxuXIyPFF2sbR%S}#=_CQkbP88zCN)Sltl*{h`x z<D-ycL3QPZJ(<HW7x>OUs?b}uO`j60%_4`Cz>vP9kCV5HnSijC*2LbsQFU$A4k#Zd z{8hXJ5~K60WoKe)t*Cgp;#7sKvLH}&9Pfq5>*{;CgnAq}sqqaC#_D&<Lzn~V*T(p- z6k>ICgJvu6$XVkhN<78Ej!HyTyjy(D@2?|LD_qB$#LbQ_F=$n8i0ey3wv-#iZHU&< z%g#@KKGYKrK|rlW(Lyia$~CCiM=9j<>HCE|zaeOMpn2A-{G^2abfoOJAas?stxshh zY~bNwLQbcyayqH1N2YFh*>H`HZ)hue4;Hy3=>+@IEZXCQlQ<6{XYC2Z+I?^`L3K&d z28o`oUar(J--Va9&SUKa*E1D9LAvx=cWs%yY8!$)kfR3~h&Jlbe;>wAWaZFr5D?MG zGwbtPRM=`6#SJnrMcIz;jF(3iV{xXSBWZ*gP;c6c)~q4$gjw>lw+p3!<7`JhiCcSD z^urU+58E`0I&@c)g{4R9UJIK-!dun(q2SKPGT<YTIx{R1a(%2a&7SX+?2||QpZt;W zYe<)>7Fpw|HrQ*kdHpVkZ&LkaHq_>*@m%Qi^^72Vst?0jJyPte_JQLaUv@1Q!9k+2 z<tCF!yWx)_wL`k(r^s82Nh=PMhBTef@~>Waf<H%d8Hx~3-Hf``+yXL|4VmBB!-$zT zWL++i^Rj;Se8!ycU!3i~1YIN89sN}vkEqkxe_vz>auL!?CbhD0;L{QLBkVzP_F1^( z3-)B9t7Aag$~Wnq7<X=~M+d{wyc)ruO}$j=%8wVu(5G<<pN@%VUgpXthDJ`k-rmOS zRNG6!HkWMo`)n2rr`gA_uKSLg+n;Ue)zev<WKcuq4o@B}R9H{jET3<=IL7a(?`o+q zcP3;}+4KOO-0{9`3z2Vm!4>mrtXBywt{`gZ4Al@{DV=W%&r+xck-=Sem>G=D2>Z}7 zY1o%2VUVnjm2b8q-^DKm){Vhn?e=1Ql+@2u7u*l1%nKGlRA$xYB$E$8s@Fe-!`&?l z*U_e*%o^{|1NI8BY*l)Qt8cHJB-L4zAbYY?jy~qhf(p}c*11;b=o8^Dt&(s-a!l#l zw3h@*?BG@P6E-BGuxe}c_!?U+>G<!x*&`4rp6H(0+hauZ5bR)DnAD0HYp=eAOK?@} z3_F}(+T=B3*LAVXSdBNIFAe<`=KxQ>MFnmiFd3B|K0NCCox0)vhxEh<r&3Q?iwtP{ z)Fz%?0nD7m1&m1y6}!lvrm=<m_T3nVrtf!ZXB6B52Yz(gMF^4AiKmR#4c3Y$Cb(hl zPAi=wzmXk+5ZELwq@Jm8C9gXLzvpb8o60bWFLjD}YN<Yi{ehNb8!$3G4ia~0i`KiD zeLjD%9QDWT(xF)SEB6lkdX*)A&spM$xqI+H#p4+x^dO^>ZaAC`$P+nY<L+J>#O$u( zM%y(l`~YQJk{N5O(RK9;Xe0S6vw7kZ>&YYI;)gR+pT<)pzfI{|m+N~Qbt7fT03#4v z@Pq@eCO%>^4b#AlU`sOzD?J{jj`CpsW}h_>99Yoe*H%nDMTDOlDr}6x!2_flnRJ{q zeDkY^1a39!ZW0A^Qmfv16qKjd!bmtFTL0nJMZN6GQos04twVy{t*5QQk#k|QGCsyv zFzp<+|H-x~RJ?A_V@xpV&@*NCmq*FJyD`H$V-$xMayzp3I)GUD<mKO<`r&EpOEk25 zT^W0*0D}L+eyw1Tj)=UhgOVC8?AfR&Udr2i=Q{_vyEH>@LcSF!g;h6>|2ZsP(Bi{r z(nEL0eD}vV>2qKH1=rOd2!4Zk1v_<j7hL~qR9?J^L!f4pQ;t9GWhg*VGRgvGpz<u~ zrAZ;wtTE=A6E_U7Lve6`E-)arHT6CuI#J%G$UD5;_L<kLJhXju4J!z6cM5_Jv(%Dw z$uVYZm#DW7kYeFV@%G0nWh7`{9O%{C%L&a5GFTbTE2$WxbMO7k4mId=5!K+et3m&| zOgs&)t<dU^c?*{tA?8obDq#9gspp-eq5iEhtcG^?q}%R3)F-C>5nZMvC9(A4n=FUj z*jWH5Vu&A1mi(W)YmoQF&vyj<a}pKnH-^Wai1cl<XV5N?UBXyx`+C#N)^Y)m@E4eD z;R?wq%No7Y2T_#acg!A6ZP2RsZIX122Zh!&gRuSg_!6rwMwoC!Ykjr*qW6`>2Lt6S zHw~oxrkwfx_XRlQyOg@``gV@1t>>LJCm1LsqA@8fPB>;M=khzp9{X@z5OpDv?C}n! z7L5<*&39@(A|8Dv7rwGXGO(WpdLEtZ6UWt4+6BEl{`4*YL$R$uj+~gXVn;M1y!RT% za58iFbPH*<AOyc4@mzRLoGR^{9!SKFJ14&HQEs;NUz8{IK7l6d0^7P|k*RNr6V2Vi zb|mRvp?5Xb@RJJGBri=hi8ZAQHXt|5n6kW5<s_Zf6&yAmPQc;hA4wLEX;r#gsOM8= zC*A5-cIJ4cidFh*5MEEago+2d3*s~Z)l^)qG0Bofw3fINH&#ricQvjPthKXU_a5vM zX$gONP9<<NTJGq696>(g-kIKAlaFc8=LW-Gv-09Y=U2T6{cr%S>?9jE8U`k26OY=H zaGk0ub>f}`mm<Z0CpX6s(^WFsZ8cbbA#D0S$tqQ~>k4O3{Pr>hbq{Mz=$<;K?xRVU zo?2_^rP6&0gEgXj2+rxM97C~>`e5z~i4myo_1FPgx>Jnz`0;u!<as1<Ovak)i)ckv z#<0jdHh6?9WA?ehCYc$WL;KL*BrS+NU~HFSRo#Z`jh|;}WoYHB7)T~q(#~iOPp}+8 z-aLoAwnKWx8_~Rxt}{1rx>WgPg9d;S_rmRS<&K8hm910HZ@*r!(|DuX=M`k*TvSvH z9&psYZltz6cebC6N$JYU&BXBm*SGz2d)9mPgwE@fv(hHkm(ADjX82gsd2L5hcTH5< z)3N&)?LPnMlhM;jz#TxVU8zj3#IEoPRs+6qC49ot_zMmbYrQ~=3d7Wm%d^`?f{~L3 zGI{=CcQ;0Hc4>q*WH3>XjFm$+j!Y!R6;5J<i0YSAstyyaa5<e_U}>_kc)OQwnB+LS z7#n}oIGV4J@#*HK0}J_2J<odqgL<M%D;`rh9B;#THBzzc;%5Us7%dSq>Sv>0%&B&M z2Ue9`ZS)$Z%WpC3b@Y9og0m>6-W)ekLn&V^)I6mqc`s)PC_{?sFYs5kj*U-lWUGeD zZ_azqI+c_X0*UZl1y#;a;6ZWdc8*&be-*xb^M4TwTFcNX18E2%W}9IP0EK>=I;nIk zzkOOk5V4t((hqtLLQaLiW6cl4?6Ed^2quY0RA<Ly3QD#fT@5shJ4$$BJYO6yD=9wZ zt9vPS-9`8-KB)&(VE8(SzDN<v%RYP{7wVVdpNl%qTr92YpDP94U2AWU3<2bM-+3B- zU5(Hnubz}_b}X(Fm{r=iEL|V3aC`FIZS6x(-N>PVLTR64c}cdMsn^u0*~DJ0R&PBB zRIwddy<~f<`ip$0)AoTV^qg<?rzprnOo`|-7m1$Oj8I;l*q<pNy>!ch_%<azgXY!v zxo^-Mh$azjeJ_vJ0n3<L@OYqZq5b&1shqkBcok25{Lovmd~cvQ)~Lt8pL|6`m9{&b zSZm+w=~hqD*_^d}{iK-m+!#DsN4>S5Kb1?K<=4*gTTDGQ!R1J&4P_<Hn3~>F_U;Q` z{nDgk#YdBEQ!CAUJ=^H#GGvMW<{D((QC6&p*LWUhEdqKoEB}K(>Xw?r*i}VUi4@H( z*NN7j@gTSbZ_I$?d!wf4ZjdH+SDWk!yu{1$VkVbmmv%f!zFVgNwOq+dy<76v(`wMA zCKzm*t2bN-gOk4seAP@7H0%kuVR264;1H$QpxON$t0H)zHl4$g#v;B*datDN3&Nn) zLxvKw4Fz-T`%eqvtq}H%2<3CL3dLaRy8-($r#4X@e|0#8ck-eyZe2^e&n;vH6a`{Y z<_Ibh%#O)$!?Dn=5>lTvqw~s7Jmf3#DkVPNC$_9DZ6Y&E?mpe@o1Qe28RrS^rBYNd z+tn%!nGxD#IXyyrR0Xau1XKz*b4W6pa8wbv9UHfo@fQ?p$EFik`+%<tWMy^Sz~==q zAnc*nIs^U>k1H6I{}>q|f7<ng$iBM4o6`dz&#x|4woW*Dz7tl9U9eDk3%Mg`-;Ju{ z`4Z@!0R%z#;E*ke7E?6S9mDk{G-$x|?WC<BSh+jth8K&b-$NujX=Tu?kh9LxwmJl6 zWC9SQgN&%`F$6To&m`HN)vHHEJ~u?1TS|T!DZIN7P!Jl89LXHC=*NM7KXi|u6t_l& z!7$@UZOHeot41T?N-`D+?zOD2!!+ZEO}f*{g9`RWooijp(jZ`C-CXLOiPKl9u>5&L z;3+S#seG=7ubT(J#|%g;5mBi8D2Jc{aaW+}W&S3p?a!y>i_68K2<I-Q9|R85;YhNw zC=VNBDYzT0O-8^!;KM+&g_e<WuhD0XvCGfk?MOQ_{Y0wy!Vgv<e!xhHzScTOWqIz4 zOg|>D2NNXd%vjlD1%4POIbbHz0j`8dOhsytHbA9|aUESqP$#&dZnR%)6X6eETy{^> zaC%$zIp)FA4ihAKw;`zaS)Cj4KNx$<s7RJ&Z5VeQ+y-}dcXt`w-QC?`a0VD`aCd05 zad#cueQ<Y&kA3gC``)$BdDr^tM^|-rWK~5}Mr3qlL_AsF60JKzdfaRVp*|**(oE8N zn-z<L&~t{n#(=M8S+XQISU=NLVUetgaWs!L=1Z<~V&k6EzE~77{OX@J9uVinK4fGV zk(}$INEwOk2{TDwc~kx&l62gm$Z1;CiB%Td{fdw+NT=*8zca6$shg>LFI-nm#5V>R zjBZCF&tUk>6f8X>wO<atkQ}*@E_Q{8M&*!${ObG+k;W7mT-oqDCO6yuHn(gICR`mc ztfc_e_oQ$I8LI{_qyo`3*cNHycKgIlaTZ|Lan}zl^wD@%wwGh;+iK_B9Tw;(&n9~p zW3&rh9*yyUU>FKLPwCHEdC1N_^AmIljAQG2TJaGN@^O&T=I2I0Z+4w4M#VZ8^Fxm% zUu$eZI-e^Zb%ddvO<=swfIJ))g>Hp6bq{>QUL$^n0{G-RSLLMSOwdp2*UHAdT=;MK zrzHR1n9ToU^?}6i$c-C7yz*Shz?vK3M)>71df&3m9;}VV{(O|=uHux}Ne}}9)10az z?)Ph=vU?wkIUMqoKT*0jYkH=|wA>oXovbO0G*U#bzrK({9?zpcZC!2!<l8O@8~Uqe zshPm0Ckm%F7YEL*EpK88Mo%J@O+a6NuGuNzg+P9Z*1@aZ^IAl2uN*#Vs>s8Kd}0{x z)0WW01mbBzqhdocD3=PMoP*|9DI4l0p3R3Qpj6|{?{|BubIfp@&_(E2S8*~T6U}p; zx6@>JyL8Z?nb_P}?M~Hr52h{pl3+2SBiu=3@aN}328Jyr?!0DNJBsvV1|XWARPOwk ztnW1=_%Wa>xqhRWMFSaKst-ZG2N!X*f~r8WpC8u}0G?vTb<!=S%Ap(=qh{%l(UF8m zEBeBV-3mtUd?5rH!VLbTJ3vWw3;9@FCQ3>mB}Kw0HYWBeujwR05OO-dgZPx_E!L5= zNN1(Xekn`%?b(g}G@%aehf)ukAd#}iLI|?b;GUl$Ocri#$-NvlKc~-0t_c|>oqB36 zXBbQcNp3hhq|UI4PFRV`lDAr@w5wBhH@OUYXfm2G!;$WcJXCBIRkkabFWDqrQG<<D zCHC02&bJIA26Q4wNoKAF1d_?q!A5Ui?GOq_l`79;l)UU)Da~>*t0S1I;GQmqAOhKO zA*2KGNjHTr0zETsI1SrIAV@CAYrb(V?fqG!f28QDe`^X-9if^E5QahTf(-rAmS8Rs zI4Chz8sY|6rn&v>eYuj>p$idZzgbqw(uARk*?hzvn#Ut+V8FJuyKQ>J;G^jtm`1qH zl|=SYKX~mHF`*-R#L^zo43-WWJ{oQ=7ODR_qp2;Y*hiv#N<9-CYfDxgPHx4gz=jzL z+1%RY!9X=1`Ru7DGiW1_kr>iPPmEy8Mo=BSAzP@VHW`6TWUKJ3Kca=5da_tU33<ya z?D<7ma}DC8NZwauQR%A&3gE<1cFBz6tXRI8V#0;zx+t_h_o_$DB=Q8$Jp}oj652A$ zA*hYq;QJoT)T553L3~>hrrs&<V%w3+-ha+Didn@WYGmd4b99y_^YHQ(bV}MfX^GKH zf|q4<NNqw)TvEoWnBgCKP=ID};vea%_brEn%?7?)RmZMb4zldf6@^HnxDK(JY-~1t z%)vupp}iToelQ{XeQt6Wu#!R}sGAimqo}k@O=HJ*ydXZzekM#HyEOu~Iay&d^Ig6V zAu-mMuOCeacyn*oL@t^~HJtVw2CXgjc5mOmnLUQ-*5pz*!ZSN7Df~tKF=Mg;R*+&g zO60VCvMK%*PFz&|#hY}Cg^Cx5F&ak9=pO*5q(S6bBMUHTk{&mVP8>)WC!QhC0>W)@ zX=X@rcFHxmxE6uTUNf(U8nT!_6F-ad6A~3=C_DMd1?v*Jf8sc`+aur&r~5Lc0e!E- z!w=vreeuI`h;RE`?KlX8iOh$zHtX<``lv}^`O-}Ce;G#<Q1~MVPG`$6n$*VWp-a4~ z|AhFa`priP+0jxsDwsWGS8CWs!OZGUf27bCEzTXmnaL@579BT!k$4I@#0E_&F3t<9 zgEGx;XBe4prp_#FIL%@cWL|6u`vpf$BEMB}-Hnfr-!V&FPbiJhJ#w8?*ULqV0F(O? zi5K2LBO5$c_k8=N`bzr6P=fmKZrzv^RlucG2F;qo3(O&)lLA11aYw4<>S>P6pwSn$ zk)@UVqg*Lzd=?0aboodK!mb9bNG;3td(|ZuOM}qlbV)BU=l@|=IfwYHaay59y>@`E z1mCQj1WZvv5Z{0q@&Q)cfrG?&c^r71RaJ?7iKv+0PUv%uLU&q(M|;jTK!)^`Ce8M^ zHQkl<RN)PY2q*<EanmmW{>2^clk_0l;*fFVsu@9kk&~<zsI4$iy|O=AF(Qpy|M=?B z2TNw94PURp;m#6<=OogGlG`4h2Gh<zf!F`hgDAg@uU?6vl56`x%EXQJ2qQ0B2G^&o z2a$S8Y73e$mZ#Tp!gPRPE=jj4=99M7J*??UiA^@m_hqdJ{JRSl(TnB&OyrLrCrI=g zs?^7N>sCj%6$0~L?>XW0!Bisf#_3?o$U#xC6ijenG{(hRp>m7;D?~8#Lpzf)9j-Ap z_;N<KD>Vaa0|6s;Lm68!eV{>;T{pn)lPZB4njjNGt?|i|4xfje&jc$T1<+zR=#<2} z+?!>KdOr9kK$p-GnThGELL{)*_r+&RAf7vNw^@NF2ZmSYcep?1OoNVmX-XH4%_BNa z4iF99H`0xWS<%7F*6z!m?_y!35fOsVy$ay;%=kx1=JZJ-%i!siKAB%hTChqKtSG}p z@U(fawY7i{XqJlQ;!hr4cb*ABZZqBLBKkuS_%{+O`M9m4FC>d*BL*QXh9<c8B>v8g za6lAbLk#X+L#&H`w`OzNuK;oXuGN^AFyDjVH=4adRA#GRoae?0*9zR*!fX{3X-$A1 zab?Tpo_IIVkb(&SsaOR%ji%}ZcY^ga1*MGQb<?N^-xFER#t7BYPL3s{;9=cDJVfjA z7+$cgPOO6u0u}P^jy!lpjzg(I{cqdep^ov>%ozXKM|G-r%x{+TE%U*Jr~Zm{p*Kf= zBfbIguhO5N$Xn}!7=s7<&aAA_s7kpk<~pVE#xTpgad1meuVD0sq~UGfAi>3di>pJb zfM2nGR-mag<$?@mQ@|@}oGrFH6@OTFolO5AtFhMHgwe}XtYh%18IQN{<RTl`#HT6x zc||iu1rShLod52&P_3Y^B!PDpvmhzRJEMNm>KhgPzMWq;w7N@Ae{BmVs6e^rf<1kI zd3h9yAW!J9Ofg!4kKZAXwWGoO9sAjQ-`2X|MzKWH)~0m_ZIzX=1r{1hi~Yvd+~UH= z)U<uYAVHpO%qVTSW^24|lA^;GulchaR!y-zN9W4kimp_(Lbkk7y<3n~<+8t)%G#>4 zVR1E#ZOsO){!hHl{=GU`zmuKgg_Q#_z?7^ySV!hF51l%6%cY&}VT@jybrTi?Dxy#0 zHO+%w(^KRX-1CD^MUK^go<Jq4!%X5k+Z(rEnM3iD1NL!b!uEPTA#X1{!}o6Vrzgg1 z)k_`C;D;mZrPh4dN<@dn<ojb}v?B931_GA1Xjnhrk?0Q&a~ZXzJ6A5s-j-=CDc76! z__rdbzU9y};SO=;dS7)5J2#>1Y-^t6Zv%7(y-D(oqT%X&);I4p-{gf$b$CtcQi~CX zXYH>9H?%Ywyc0zWh7)yG<C?3Z*2=SO<@uJDh*v9b%7xWIbrKdbzFd1A&AdX%)rO>1 zbuk{iyS_rTmWh8O__|*<MS0Pqk@Z$S6kWJq2h}paFa6~Vm(`XPvtCf)mVb5(_F_RF zscH7G3*B`w>t+g|p28bT#3Q_yew_e)uPUukt!uTfQZbzk6=zL6Mvptm(@uD9R>@H& zEvXYJMv@>!_T`^DhYH@~R_}mz#C5%#p3%O_QFN3W*<XzdD3%&FCK0N+3p1@jEFCHk zq~Oz_1U>e5G#eU>X9Gg!=2iTOXXd;C99ar-i4~Ylaqi!Lzw{#rph)Wko^VJcYdUj% zLJ(&q*PvJoGA<=aOHeicz^&C@pu$7L2RF{ggFKRrdCLuS?@)>xryjbDl0};fy#I6N z$>X5FB-vt+(w}e#iz^sn*V^GO-AU+cnC)?orO{S+JYdt!+8tN9iM>7yuBYduzD;Fb z*|fk6_C?<d0F#z(a4VCoq`K(~q40#MaQ~DM4>ue{qTyB5rIV{mC-28{-R<}F@QiEM z31qIN@L`O)c&I3M1G8<UdP1WWak3VR;bbf^#WS;b8^a~^28>2l2HSGXlQdx@uGs}* zOG~e;HWP=a2B~D8&|#%USko&#zx{Ew!4oe6d*f7vnKRR0U@x}RVQc*O>w?mTyl(eN z^oqx2Fg@ZWf?!T+jF|pd=B&$)z!s;MfJzP)#HWaMAD9S%gL;qI$%gkkOhow2%&KQ8 zhV;6S`yvZ8zX<_f0Ax}l`IW|5ID|(W9_G)kEYu4(U=n>=2h#WCg7~<GNOz9R0(WlY z50_!+<LqYuJcBl0p(qOO1f%sEJ~9g_@rPXPEJNnukO@%qf!xM^*R93=KaPX^yw;od zJKoeFf3zC{BlFYs`66A02%atTt;$B%PRRI5HgUB#x$<K>nIJ(uViZ#~6LVM>6g@Lb zlFN4iV%m@aCEq{eegp2RbhUZ`ki;1sDyUaY)mLMx<w#nfTunw0c>yBC)pNH{eT(J2 zdk~1gvzE;ETu<qEP6LXr*`s+jQQHDKgmxMD4`&%tH1!oUNrRFmpY|hui60w2ZxTmB z4z2`S=IAjsmyOhdKSFqZ9ceGs1=T>KPLGl7943%@#O9rI-HuFZkKIy-ML>CBo$U%* zFlk{(eB~1`i}Zbb{s~TZ`1W>d`#eNrWZWIYlBCC67chzVjkVW%TgImP3mfW7F!}Jj zi>Ex&NFSKakBuoFvX#_RNz0}}t@6umIMzT~MM{1<Q>nDEbSR|yeGj}bGmU`sO%bqI zJ@|dxnvf{3RBG#H91VRFuxt+l`jpKZhLjMujgnud&yrkAZRaLaE1(9D4UqOt+$Zvx z=EDikNR#D~9U2m<TbY=8LtM1htXbOQj3Fd)Xuf4QSU}@F#ilKriHZYu^vAjsWe4#- zyv}UQkixIF@jZdgIghM)qGNbA@8jr@jADNBoccGuV!*sQ*z0#=QG@UtNTp{auIw7i z-!J^QxB4s0znFLV%SYWa;`5wDRT+x`1!YN~+Y@5^(M3BO=IA>e<HJF%a*Y4ULXb== ztvA2#$~tcIUd4FeIhIw2vGMa{P=xczr2Vq#8fWLU3%bm5pX3>vP(uwfe-f%tp=k<Z z!GnT}Wb`&zju4>P>~wQFI=^pC?;sK83SP(VmK&Jn)#R)}kf9FLn6030tpZsemLTKb zFlB9&6T46{o%e?$zMk)lp~jw$BQW5v-&y)Wezc%<&ZTZ5<+h(+{mYk4c(F$D_$v%Z ze7RQQ!+<q}r(%Wwg8*{X^i%EGcC(q6NnX#@leW*f6v;F{05(Y@U1X7evtx#l@^;d# zZdsmhXdTy};YDM0&*CeB^F<E0GcxEKVI>5H&6Q7pbc--uF_iIIJ*M~cwfu0B2=29V zduhER+v_f8#<)|wQAGxhPWYP<ZP~9zoU@zAd6d8m`nn>Gk#TD5F2AbP`qqNlq4Pd? zU!9x!*h*?Y#^2T)*CsuL@qIun_20o)2wKN(1&%)(4rQgAv`Gi%ukKB&;@bl!_kcZH zP73kK2l7f7&aOr0^O!MUtd~G_EuVL2|MErlb;<e3TtXrV@NGe!8J>dGLGIby)kDN$ z%em(c_c?EZ!N33xZPlbmi6>~Ii|hC%KAD~93G5*fZ=`rP1c!JAHllws|NmtRIvNF* z@qJmI^>IdUDX>a^tfXZGB^N8KF))ujmfQ~Buh8BUZ}f@huj&>u=7rGyVNQga<YIsO z{h~}7MJOrL-n5|qvjTD`;V{9jgC}?8!9h>AwJm-#xckUX*Z3Cr>+Tf8s&Nyjm>R-N z7Y$baEHiJGLl99gb-)63Dw!OwPaYSvcc)V!P)=NE!FJubsqX$W*`Xo|ncC2PZv7=H zr|GM=zCY|+jU8NCd}Wv3bL1R`@mN&NXo)SM!rpTOW;e9Pt9!kVa(jl?n$ZW5R@K!C z974xM%orA<BaUBrORIUwlM%sTiBus;_RW;#cbCg)c`bt4Sct~b3@RIW)oNB%(q^Jn zrQpUat+)k|>_64o%PXR>bu^TgdkyrOd4XrkF!9%9-)C;({xl*61<!+|VI3e|62-1) z+OPwH)Wd17F4oAJs<@G-&yyeGn{tAJ&g#yiha{-(mN8?h7WxhRoFSf{oA=+l)Zsu) zfGh7+>;h{;sE%6@WxHx~!5dIIVWN2-Q$9soO}l!+$o258PVrFZskU^fRmhSkJIZz} zt-l*6SHH6{^%6plF~`YETyqN$)<|mob2k5%Y5y>=*0i?6Pi369mrE~@QQ_polN5AM z%{?Hbcn<&NbSBL(Z6Rmb)UP7>dUp3mR$4u@QlrJ()w33-Siz$k13k{x-W%vzHnqfs zEh{U*fBa{c-;+)6_?zEw3d7wNNgPhmJ##qJ)C2&HuDruqoRNSwrOXap{j-!A1<i}z zQklLYGxC+Em2GeJQqx{lglvqtG$N!l?WOk&Tt=uK-aRDXJ4%kVLc7&D#BL|Tcc!N@ zkj5d$CsI@6&#XLA+LqtzxHN+nIF#&&zXhw`-Bu>3wx8;MCz5*iQmx39wUsR3)wb{y zp{k-n<6^0+A2Rnk4Vru-?L0LE@}mcgIZfCYE|M}g&vI?N`}ZupF(r$vUMgeDdh(KW zk;33=+WRCBAa)|s2gy@fc@0i;XTWxRm$`N4QWJGf&=X1RyhOa1ayVuMWjfX#nd6)V z*JfCTb1i1Z!%?1^7l8}MER=wNa?cG|iOAVOL88LIgw_u07T9P%TXcj82rCIYcjZuH zU@VZ=@jCgf3yd2YYiwSS>?9gD_h!9nBuqOgCg`mR+s`Y=(S%+(h_2b7IraW@9aSP| zvsm5pifkG{Re_3QQ}#Va?1awU;6t%vAuTP8+adBieh}~SL?^QoJtcO%MPq_fR)WtC zwCKwPXMLXDEO7@6?s>A)l&il>A8X(LH4ZNFKRy#V{)$l)wqN5y5r^c$O9Zt(LGw!J zfKHO<OM)K<0Vg|=`|)i&(z(J&Sw*%gf&}lCZtOk)*04qAw?+cGv{p`$5z+rbMwAGV zHE(4?fR{axc6R;DC^UUuZ+o1I9*k7?$SB?4)HtSkb=5s+m?Wc`{Js?u|3N^(5(ymx zc7f~!L!KOYM*^jCu4w}1jQCg=SA|}vg^js&R7gY*_&u7S;x^HH*&5u?EfQ}^sJ7V} zWs)47Wg_+FyIIO$AY}T}*5tvl%vlwn>}emgdETU*+7y{C-lF+53;NL!?Tjbv=-0ws zPQ{8K*whnb($)}|bD?Uhld`4VhJU`ge!0mwPjR&p<$_W(i*m7xDP;?cwT;FoQOmDQ zUn4QYR@=?3b8XM>s0@81rQFmElyzu^`6E#;QML!Dt9O&P(Tm)0?$5v3E9GH}*41N| zIf_+7(IB5UGOl`4YA2l`-kj)AX_Xd{BACeS_85@-rUaN%&N0Hquod~1B7&8>C`f8a z8m+@~q-$015nO9F&lv=NiKTv4_^{d9po89FpY`Ius1^MW9QAghIq>~{FL0Op*T;$8 z%#Nq!1a90uu(<>O#IFV6w?gw3M|?0WOTFK;Vsw6&krw~q>z4w3piz3@!@HhqJNHE_ z(%06TzY_~r7CtU#powWCXx0d7&1a4&chHmXX!EXzs6VB^!|?wx{uNd5R#8Q8vuybR z_cfxu{5lrD8NtnQbN(o=5u-IxEMv0T|3oLEZn{~0mUhg?&EmyW#-=^ff%`$d=D4n9 zmgkz6(^~j}Kl*1Oc?J*igq!?%r?hq1NwOtjnYbb98G5olj{yC#p7Dspd|`v^IoL5# zGOy|P)eg<vn;$hB3N^sJ73n+o;V=I{)DVF=ihTCIa{`DjoK8%|VdK{4^neSr-p%0= zQ*XDRDSN=q+?j8uD3o<AF2v~(DR-DbGf-GK&FhClMnoKUD!@&%tIH6>{bnlHupSo> zHBppRS5eqh(rr_b<e+)|odeA1E1ERqgjTe?MZ}g+kyP6p`gl84*)?WjEC8)@5;it7 z;GN+x%~BhkiF<=3E0R^Fys$CfETJe;dm5XxSbV**NSY&2a`)$yU^jDguRG3hzB>>A zTAdMG4^H6?KQCXYSgA?<UVF25H7mg&g%$;gd3oXR5cmha(<iPw-!qgBDi*@&Qhoo) zXcE7q88x|)Z<|{s-^7ozlJ;exG7*BjYf}wRM8x&}n%SrI#W63)d=Nn#2{j8v5!cv& zH#-V79E{$jr{zhWfX=~<hcEZ`r#tgp5n8lnhY6F}7ttwoG(zlA=3RX<1a4r4Wd$O= zzs5f&7k1;4Wfg4tAF*y8(LIgyqob&%{Y>Q?WuN;*Z_62NuZWVPdecq%Sxa60a-LIP zcliQ>)eGA_hIMsb_cWEL#id%p)rNbd^r!Z|s*1cDotd)?MM&Bnzt`(&VxD4_E<}Ux zn?C;>+9)E!Is>uNT(aCzsC*#=t4yfCq7hxh+oR-#{HZfH9b<Zukj9ZX{^AwdQ^<t! z75Fd7Mx)lE)V!>xA$bG9$?VXG@)<b`OBP8feq8TD#0>Fu;pbwkR8ySWS|5bqkvKcE zD*~i&z4o6*s_K&teg@L#yqBT-hvSH6OG{vU_`*Aodqa`m7bCwd#Op+6IXzMEx|^&o zi>q-5%c<D8pC;=qTiun&O{M$gtgQ9>EZ4fIF!8!ClfKOzS}2}`1T$=P_@>xc5u7e* zQ8y==x!ZQ6M*AfaVnyhlF8yw6(fdRVM<Vq8Ph5-3!)^=&ycO*a9fg0j3d!7@B1)#A z<FC)zbj(r_An5=Lvt)9&CA{r82s07ZmR)}mDLh^QEo_|2sxbm3$!BRW5zJ=b<sd2l zKD%6thy@{p`-1ajt;CGuXaGb1(^g)7tv`M0w4|;8o5P**gU&X?CqS}eG2r<41XuWL zB9Q+JY9`DlaN`GlVA~@^XB5_k&vw}M9|%}OB7wko6r#WyGCdlSdF#5*EZiV{RMxAP zmHXS<n7h`fuEej)sj@-T23!N*H?}jKw&U3+wJlOhN(u%1{CXI3qOYgA!lnJNvF1xs zUmud@`-?3Wuy@z56)PUQ-aUDW_GqSjcRd0=c7LjlMpd;_JUyTP{E6(vO6(wAj)Bo6 z?}1!KWM=UA47--7X5l+*BXx1mCCIo*$F3?YbA7h^;6T_Y4)agd`J*wgGM|>~|G>G< zA!rfA-A}<xR4y;mgRWF3Zc^zcz#~)1%-}7%GvS*%r+_0|Xv;>_oMj>$1u(-+5Te<y zof9gID}qu{ANm55z~hb*Iu~DJGRP{1!Dm?_8hUrGsR|AcKNB9$jw98FtGSwSvAA@I z)lh4(C{N@sWZ!A<O0}#&q+9MK<_OjoWBWt(;?t*d*PGcbG_Kd)ZyRi}^x>oQbA@TK z%9+7E92VdTt;9c}&p>cBE%7)GhF@Srv)rUXyP4vabf3UqXG8B2Bv(WG4L4R9D&ZPX zH6IG~T!>MqJ+Hl;>3nqQ*I>#>Ff$_vDeI1X|DX^H;`{WT(F*lXiG;qE_gC$_UjI(T zwbbVrSo}zxv*TsA$uAm~2!MEmdXG~+DulNnZ+8OPaN-|Q`P-adm_U1(2pk2ed<YQm z!sR!01^5{Wm%mipm?GQur|ARkz%A@e>hIc4)Z>^(4}6Xap#<eP&>|it5m{wCn(Uz@ z=V_6p-V|;V*_g_k{q05^(>R_0M;FvZ1zBhBFDnOI*mcef1&r_~^1td*C)tgEa(Gpr z#jaa}QNF}udDSV(EISq(>G=<GIi4JA0Ax9uH4sA2o>TJ#$mRz=qxoOVXr(Y-eZ4<! zG9`2VF-M|^Na0y5@SZ;DojvgwsP%Isy!t=5W>w1st6_O6Ww6biryRWwaF>_$d&Dz% zHgvcNoYr%!-|gEp1LNDP4EPsl8f63+4KuSjv<1r*q8mHqfJ6DEoqM;KJFYKqiKhgn zo!^@y1y9aLeWVecXs1wrWvE196)f`)|4iO{mgAgUx<9Bis-8*)&#G5vu~37pAMksT zlx?8yST(Tw0MbpKrMs*B5;q23t6jtwlPGDHHN|!hP9>Lz;>`VWSpS*qIab?bz08<L zf#9bIj6o|}UasYn`SbSn%thZa&eK|cb4S8XTzjuAr_?cgj-r~>dVZlpt)OKF#-35# z#qZwi?p@k@e(L_RK2mrJF>8{ZmvsmFV8(gn8|?0m+xif9V1s#K_Z9BO5h#8G6@oCc ziRsR8V}FHL))oLYerCg9kK<;Yri{FQ=b$zJEjHGhQkE%GauqP!SVavj=9-pXE%x<# z0|a!Wk{FqL&l)Z#3`4!N<xY2z7fW!B)_3)*&A(|RSs?2czS`>f88Yfmg=*sbmOV+e zIn9&PXVAkUVa1V!Y+Fe88>T>dH8tORHSIsQY&Z17E+H194dKTr8vw6Y)jyaPuyiA5 zi1GV;z64E^kh?xDUkV!3da#&OeW}Xw6vB8KP}P3k{7KnxG@Mflh-z?+olUNwx^|Wr zY2st?LQ`0WmT9!&rjajUWf`$MNoX(<k!{+ortzEIW!nQMZ3X@!y+~n>f+o9Z4V^yq zx)~jSDm8CCcuLhHk*Gg_`*{Pa>(Kzbl%Awz`sK3+%ej$pZog?Jh)nalbLbnAed(He zR<`pURJ8_Ildj_Z9mujmWnG!j%i23`4H<$xD{p~^zFQu_`+22swRK1lH-`OVX@O(8 z(@S?Qi^8dt3GLJx4J{t6>-i6_kD_<oLt!k&?`oriP=p>)^EKrzsAVf<-hZ05Wa8LH zQ-z~iL$hr)VDFYv)GWs#2^*6JKdavigC<^5I7>M!C65?+k^Qf8{$EE9F|GkvHWbH9 z7#<$b>m^CWho(tNDfAbY3ZnKQxQu>QMa#;H%LXzo{RPU}va9;$%IQT$TAa?bektFS zx5_zJ^_ELb^C}qmJ#AHIva5;gd+(n&xQ~{7e9>r{qW(;j$)?&c{=TA2RigK_np_+X zs58Z2_+sVT$H|rccnTf=Myte*tnn(8!l~X^Z`YCdP-(F_P8x=3J=6;O@LrAI@BwCW zx*T8;TX@d9@QHV5v8!(N(=VW1LVn%lPY71Rsn#xr_D436XJb$!wB0J{0%zd}US0mz z%dG<5W`EhA-x5K8IiDk+f<22SyGqkG*I&pGC>u7Ih3m`;cx`}wnJTZn+Th*%<y?-i zShlH`^czmstTl(^LEfn`vMIW)Z1u-Aw3FAgdG|nucHNkY1|}mG-JZo=)Z~eGKWTLe ze>F=F@Qf$^h@f65Prq-jW?DX9N{ul!!g7>0Bnm@@Ezwz3T@KKU<k)r1ZI~D8%>B31 z`ZsL5$|(m*Xco;To$lp(4cX=&@%HW!cvFv#>sL#%44J9y!kL_CA+B)ySW_*1Z6^8u zet<vdMs@f1?(cCM_wpLYS6}i4^i>GZi}u}44(gIm0<en8^h}R5!i-g;ePr>#Th~<l z^)NT7VJT7uL+85HMJ8pKjRr1;p80I$uWix4+3BPVB#Xm^xNm<q@jVQn$H6Ki@bts; zE*?&!fAu9BvUgn`l9Gu3nc&GzRI)VyJ>$G8)vQK9H8uyDQ@B}@XWzlz2XF5df~I1= z^R4_bT6Qd)a+vKqnjbG|)K^7Hv8#utZ}j4+54%#T_V|qG$<+9i-U(0CuMd#?aRM6~ z8zoM%ch8W8-d_H@;A)N~{#^50c&p+dQV&&63qAZ6(rJi(>AajP2uGz8+hC--0v{Ww z8c<@o_M%izCGXQDvxJw_ws;p=JYvtz6Fqzpk-KWZ0FlA;C7wbr7XGG?dZrG8jZFqZ ztQSMnyP&UW)Ki1+T95uq-&Oc2$*|K#D-ZCUa^3ol;KEWL7?TgDC~$r=#x%@JrR1C@ z7t3x5j?Or&ZgyIyl-N=7f0PSdS0pw4UM^B^-?<wKAIH-92YfcnlSb0LXux-5-^1U+ z#ntQ4Mgee{t*k|FRyO#MQ^z0%wlAU%c>dC^`QUpiDsPX^T(|q7nf|pM7ov<0Y*KD@ zdm^r705hu)&Vou6H<PK*^hgq7Clx7#<u$nKjLPSwiCuUyQPnOGGqP4DZPH`eTadxD zOHtD5(5FPTSkee+UY`6fY$CKx2m`9b<-#}QTVk<xPkF7b_+sl*Ta<G>^T2NpLC>u@ z5eYz#SQgAw>93^KK5vCw$JO)uvq%F@A@*!%h+QDW=kV_tqZ>%glb!|%H+DW_UPY}2 zrCH4jK`ouid*HBISi*A?&fMCuEwfmSbfP#Bn5BB~4~oMo2qxQypgrkJbd^f*_DO@5 z#MTO_W<=wWS&?yXmbBj25G%DBk^zODtdAhoexZp-Iu_|aNf>9~GO^l38aU%-nro3& zm%hvCz+aTBOU7kFk55Dr61!X1GyKu5gx5>3JY(1$5HQQtJER_n*Lkr`xY_Bm@53yh zkL_$nLpanZT1gdQ8O$TrU)@7!2MJ*B6iWOzH((eo2j@r5R`KXFQD!`1;pht4lAEA& z60X`NC8_$Zq1u3yld_z}NomwZj?shIpYImWSLJP#1o}a^(^~nzYOLk?6e=6bN=WRM zPIatE^hc}ybmf}#QCI|n!5r%DQ`A8J5o#YL#jBwe{OKRAl2Ej`*b^zmpt=Tih}2-V z3oD^(k*`2eTdQSCc+ZD2G~cnfo;A3=N<cth<yxVL$tTK_y)JTu!8PfJa<M0RCW(ji zBgF1lZzHP(u~Oh}P{*SN+*|)*eGbgYc8rp@=7l_#l}6esty9MWXhTEZHO`G`eddGd zPI@OgVk3&>@$6Ip>~8pu0Q1T-t02}o;ztPUWY@O;RjXFozckX)M3jJjTG<AggZZhe zY#B-FO)Lc?dvRAp!_=;of|0-GV7yeYkO$`&`Bov!5?S=uWw;(4Sv2au{re{VkpFY= zwD{!meiJ`+%GG0v2038%Rv)04U1(d~lh8gdvcuolv-%=^dt;2`?GuDNvxe{(yftQ+ z#P(*e(u$1*i%L0C)9_U89rqR05S)Er7OFjF$POG%w@d%LqgYVu+o(a?X7o!vOL%Um zU|-_J%4K_jDNrIdo9rPfRX^Nrqo}smEfY~&H!SEbW$a~ORB(kWm|(-g<Ah8~QusNK z&C&DZ%!slTx46QjB!pV^XM#q`ns`98tDYc&j}C=aVe>{Jmt`B$(9R#qHs_<`v1>@J zC+UmjNOc7ny$>U1K*+`!uYf5u{hS0K5U*vr&9hcu{Od$Qf*Yf_h5z#qL%tsPO6;qk zE13G%*AB)FrXP-a=MnG2;sjhcNE}#ic4*5}P2N7MJFcv1|1=t(e))CRADj1IT?bP` zPMfZQim=>d?jMbWn?RtAjF@yiIZOFu&Fa<SS#wucam5QiW+K>i&<Fk-ePn*Jp9sxj zkeUOSOUpHf&w?qW+sX9IRSk9HzH@`!{pY(i2I<ivW%m*~w-Q8EPgv)OGwu_YYf!i$ z9qwPV>Yhn<{ikZRHqyCY?ae_rn+M^BK5IskzHq_mJ|sJ}3fi(LX?~>a31^(>Aylpv zkAd$M8pm^r%X4EnH&D`y-}G73NJA|#P2~JC6HMRxZv9}NXm4e_C}{}I-t3>5vq;hT z4U<NP-kOupYgn@k11Q%C^<0-hY*wbtE5@nn5wpRRNhEkA=vkCn<zC?2O96L~_qJ<8 zy%-?t^ttr1-lI_d51-|)uhKgX|H`M<iOXQZmLQ0I=!#hu^8oq8Gt-h_`60Iv%^dpJ zyB9PiSME}&POs|nSX*0m3p&_NdN7;Q>8I0DUfb!nT2Un+plEPkxww!8Xyo*{@Yl<! zIs(#ks5v+(>?WtaKYT*UD^w<Fgbd*fsSB>I$8`|R7(n}#y7?S;J`!g6o~~)!0meS| zrqgTS9>|%y&a1w6fZ44LY`<$4>6NRiJJ?Y=DXhMM@7A38b<F?LP<3oHp1-}oJTY^y zG1GHd@h)2O;{_h;r9X+ByV*s1DB3)b?ruy(FuwRyAnK2>|D@$&wX>`)aJ`c6k2)%E zs<4*-ERDtsh{uDdn9-aguSI?z>G+U-5DaLYXruUkxgrJxA5^rQ)jO{<aDgb+=MFtW zm%g2qV_8SiFK9J8&Zf9dz2+%S(ivSMef@y=M`3~PkBI1r__8;WmN#a(>-om1BpM+M z9(g=d&tiyp_0?OPD_z&l6wGxbMfk!i_5#NBvI$#TeKmK&!Kv?tC-2O#6QW;O<6#i= zm48xy9p2t(rBze5P3w(*SolRLymM(#ZU=e5g@j+MKEf(^qAgr|7d0nUy|VO+_MU<Y zxbkN`fJno=!-cRFwUO_qM@lg`H>WskNwnj1^mwf4peF0fbY)ITJ@HeUB{A;B-b~Ev zSXH=96s?ybe=ftk122eKq1Sp1OV^=j-X=w7g@diqGl~);DuD;d*-hs^I0d;pv8r_P zdSUho5EzO5raef0@!>z`eDo7J8qN6F^>?PnDCLo{vfbd>Lj<^%{B7~8)l`~DlBLcI zD_)?6^qU2?xxqR^!m}ie`Loh&Rp<EAX<P5|{Z!@nP*_;dHhGz*mc+^u{la<&v=t}c z6w%3Im@#|mM7b(6WmWh(`-)Ro2I>iBi|-`&@AA0`nf_Jw2Wi|rxXnuZpq-v%jn|Sm z|I_tFE{r#n=r@@|4bhJ~@{hBerfy)W9B=86r25MCl#12VquXa%I?_K``}iE;PpX&m zcc~V2faga(KP^J?RM`WT(-kbA{dS4;vy28S$Bj~z4E|_kiC7i|G$>y2nIgJs7JwF4 zgw2WtTzy*oQ5R5&ZGSD<>Z^FN31+QpUS7Rnyg+!aje2X>jN6e(nL_OK-JJRLE?k+_ ze$^<1ho^tio;W231G``J8skaXjQ!yFHN6W2<gIxo_fDRAFW=!<>M8diuDYBj{y%Sc zOV3f*^MT{Z!H;D<^r`s5`KegcSWPQ^fk!7th1W+WY-U+O6$fiD)}D$UK`p`g>iRd= zF2D@+2sP{-%p$M(o_L0>Ap<`_BtuIlQ7^2$hlJFP5wZ|V^2r~+RKLQ2iepH;f1qaU z-vC1cIfo>tWtWlUln4kgd1;>YnZ97#F%ZXcU@@h@wJ<=QN1MuxaeamoWw!Ak<1`Nx zj(t-mwqdzC9@n|q!u>2rhv=W?sn3w|)$xK&bIkKEzBU2_K0iNSovkrD_bQ=?2}5>% z4ER!icZc;0)obKEQRKuKp@k(&6dw8)k}#RC|EupE)>y`YuA;jdy@SCZ&uFToW|m&& z!bCv{5HE_C^CriF3b$2;@mwbCq3D2f$FrS|;1$+8n*q^aU@S!P4dZV;W|B8A!pO*H z7lUSa&*vSw_p?|Oq+vj=>ulp{d)uD<{ImAJJ6&aP@)FIhS7Y7vgHaBea<%OII9k7k z`)}z8CG4|nUcB0l0~p)#*4%l#H5jU*DR*ibIQef6NjqHjG9I(Hmqhq}yiPV1{{1W; zKeRRMNf&$xwu4M2<e@JMD0?n=`!?9K+xmme;wc@X1YA#i{-(a9wcBmF4QJ%hTyxFg zb_;7eTJm*mtLEd>!~XhIc{Oudr>lp^Z{1$=Kdf~V`hE)RFS+t7^a-JdDNA1KFXQRt z6&O*zs-Y``&?><7w>hv03}s~~)(x&Vra}ffE1ul*Z2IYijO5rh;T+zZI;d5QJ+zLF zHtvm{cR1TUNHlY`rqV0g7X+=5<H-Dt?A*QCKCiIuejj{svU^0zO(D4XmTA|u!3xg5 zwA5s$N5}Uxf@>q7pSf1HfYnuyfc`gAj*V!(!*j+VJ>jtXOeVAGi;b;SL*?W;_ym7$ z60f&vtcyPZy#KZRvBeCYD!EoaVd68e&1k?aP~51hLUK(!h|v#7Mx!p){vSdRq3@}4 zfz4d?R_yju@lD_kqYBTf$4=$*6Dgb}2hi(K%YRdLcS+O9R=}q!c+W3)>DjIR0*b{q zbl7|K?~QB#*_3r`J3e`odin1)zBOXZ5GD{YVTgw=?9_4*r6|(2nh`nj9Zs;hPFuYH zJ|`OQ{k@>)L~Tx&BSUgKCfdY>ajuu5J5uYg^3VhBKz+K^-$DavH!TM>HQ~3G6KE*q zro)BV-%J?kwEW+DBT0lG9$84aDmq>RzkVLna+YFC{LGm9*Y?QUlV#>Qha)xbzE-g| z#^0&A%vGa=V370)n)9!%JL$BX)gW3d3d{Msq9(30ba1S)o41->C*uE5fc(~IX?$L+ z|Ete`X&_uT5sKI}z4J%(o{D-8P1bntbGDy=$Y@Xb?8X7_kl<Sm9ApiZI^UAg+JxNy zo+i+L`pt5R>pnQlg$V1y4T_Ze?<;_OCa>E~Wo|3@*L%I2uUh^~P@lgC!Unr6g;Vy6 z*5dlr9_}RylKpR|e?J1yf42Sgg8k(i+6d+lGzpBh#(G6GEls?mmng~?A|aws;CXAS zn$7&VVi^c&Ap#C98obBHlaIyLEqkVyXKPYYk;;J%yO|aFlmEV}qM*V<LkjtSj@S5q ztor}QxUT=($X@=E1BLSct9QP7`R4PY!T|SEgF#j5iP>t0h1Pn&z1Dh-V%2x7y>dSl zTEEJgwwz8?nun@>pP{?Xq|0ivi{q>6kG1;q)8ykKpM?&zgPr<sjTLT-*Z#TquR)>n zck>_R4+jSCiyeX=_W`|iFyR@7TxAZ;kqDI1;RS|V6%Jfc2o}=eN&DeR5PeB5t5us! zav|HgrAA%zH?8&t%^LG$TmE-8TiFulE`_V>AP?eitLsAH(S@s7kbQDVK;Gyz*3mcd z-Gi}ey;{ZSp}3n7ejqKOLoOZIC|oXCC1rA=4r5A%TbnvhnU8@ht-@PZcBd@P3EXfr zj8~Yd2u|+!ajFs&j(HyfxX~4@Y0bxLD6YGfU<%D%y>;!WWUi)1`)cK4R`dnBo(aCH z{264W@|Oh~&IKAs+FQ`;TJv#2A~UW6Gt1vXMxxr$r3ig^RP=qnIjEIpAerQxl3hWK ziW&eZD`AbM3x#(aY?x=(Gu}?{H@B;)@izBnE#B&`Cq>6rhL1b5m?R|L2V2p4u%gk= zclH$yLoY8Ed+@6s&CI`*BOvMf-GtV*#dIYjcnhDo;4FP~@0`$$&a8|G8sSf*jQHR0 zpJwY`maALc>6z{?r~QlL_<Q|PV+GL%rV6*nI!>xR5S<_?VKqHKZ6ZS1dt%v*LK{If zZS~%vdh=t&uGciZNGplE;c^g~Kx|-)!W3{wYl~OH*u}rjKWfUyto|hSTieIuV7C7j ze(RLsu+-lyk25o9S6*n)SW#$TWfV5Wg#$n+$rmtb8?u8-=U`P`?`J$artl{=ns79k z5HmW$aLk#1*A*q4WcT&>@dsJ?xx)qs8A8U6djuV&Cw_If>M@x$m4n)w=CKaUH`j(e znZ9ULnSZlfbSEfrKGs#QqTL74>V^aif}99sTMn2^fGp6UEg<x27a3K7E#RUp(DZ5- z7@2|6`tHy1sbd<Q{RR|+ocw^bfiogV{KX_V^3WYMS^><3{Z`fu?X>&=qMm|BYZKZy z6x(PK>ee6YW*W*4rm3T=NeW{l3r|Z^KjTd2t-hCs!Om!D^t@xVc1j$`J{ikyADRqV z$+?CY+UqUaJL+Vz7XxT&scnh{+&9<W#{kShPBhMqI(nazLz8y~WpIq1q{~2~nJ4lS zRluD-QA#T>$soWn>D3az>6$Wykc`Y40KJReH~`C=cY<!XsSF^94Ybj8;t|}5UK?N| z0g&yp_>I<DRvaFX4Zbidb~_ktS-IzKM4tq}1c|o8umLriR<A|JT&2Mr<RLMl2glSY zx4|)*W^sf&@%ubM5+GZ1ad{Jip^`F?J+$7Itn$v?s458$hLD!;YOxne#ON#$5Z+Q7 z9t-dXp=*NLfesb7AwtL00S~IRL==OAbN=P?n-4*AmaLN8zLK1@lFqPWFI$ba68LAD znpS-hh89-SHcRn~(KJsEtbHXcX(d@M|3TaWgdsnrWHg3NFN{qhp3Mx5O$wgP0*nnf zV5te!j)-oBBcG2`eFMfujQz_RtYa8^Wf=PcLnZT<1qQ=f@<ex3O!|aEz|wuYA>B%L zDyn7MQj=1JNT%GOZJxTOtxhTP!WUQ@1i(^C{vZmb9kq-RK?D3rU?@AJW=#vA7-hlc z%K|><LME#E`SbSH*jR<IiwrGe*F<ciT_`((rY-EHQK-0VV7!w_ERGRBcqKm80&8e8 zsS(DfNc)68MaqF+YH0_g)n3(}Ha_unY_QCllI=DgbLbG$Y<OLu;#??2P08WCOGOxL zaVdchWLL0P(E3Y;P$1FtXB>e5ODoPW_DzOLuP^GjfF+eytIx|FRXdwh;Tk>3D${Nx z|Iv@q2CXE6wTZ>EnSimu2Q1-6IQ=F1;+ERtSU@(YdbSV5CoZS9rY)^0c65`-emv1@ zGD6c_1g@}YqY5cpwA~5vV7}cOPD8b###1c34GMq*^n{bX68Wt6IT!Gi&3B_7rgGIz zE0*8w!|CYHw_5vvss|lEtfrHcN!!JM?fp2&<9cs}%&2em-f^@W7HyT12joCcb*Ji$ ziTf@qt;h4{QTwa9+j)U7A0fGoA;E=AYyMH7kKc2+OTKwd_@jH-L-)M(Hs)8t{sEHp z^jay&ft|J_YC-Jnn!^T1mLh<9BY@-6@Co}j`_VOx%n|kG%NKKiM%xKqQ}pJaNvcm9 z<6Z7pPD8cRXxqLdI5k+lB(Me!EI65>EI@zxZ|%GT1H5nbdItgCiE0)B#<5~X19zV9 zm8_dy{Mjq0zZQ?LB#5zX#o3|&mh2Xpcs6`+wAK5M>3t#x^Z1QVRk^J8x8|}M4)3m- zbo#<{_pZjZbLq93ERo{HtR@M}kzrlM?GEe|<-8=A*5p2fB}2Q$wNSO1&Fi&?)UR$< z8fE)bUgcnQxnS4V8BZhgI`0FlCB_Dik}dOHOF?v*ggKY4i+3IUANZq9)M>vP)VCUP zya33X+GwXTcnUA+lHqw7=3wEp`{A?_;q``T3!Ita;Z|92IW6lL0#^rZ$nxqB2;}%y zFhiqfNJHyDO7<bQ=!Gsx`{SjSIXD$uNb1w|?5(RouLu=Suqgj_r>`yF_tU}RrQp^$ z?+6pnS=I{YBKHC}t18i;;)k78x!Alz@x>^831cMUe~2>a$aja<=&^$)m8kwCYj*I^ z6_?I;wEf14orMz@R_fT_q=SYMAMD@89)ti7H6;;lsOZhXqRdq5(S>xs{o-qK;ZK0` zRmpmj=#jup_Y6;LJC_jg^_s^M_2A?%%ew?K5cvy_<WVIk=qfyt4NUZXa32NdLNV%s zNw@K8#T~X$!ZoC*P_p%6(!ANN>D}ZD_|8+tdFp{aV5bgBl!}B}MoeE=%-(CEn{BMr zxHebKYFPoQC)r)O?G0Yiruq$@KZoo${AB-^{`+87iSTl3+&^fJS0y7(>c!iVDu)9& z-+sRfrb`pS1XvN>H&G^Re;7bpav|I_t5)Uv=tB%OZ>w!#bvvVKg~yeOcw9fn+4Al{ zp)4>I(Z5m)xxugYe!t-~yF|tXZ_4=<xtrb3OcR&)9Ut;naF`I$h<uO8PvWAj`=YIU zIQyKnBss`ntBoW%ab+c$8zC9iayBc*x$+H~S1If8jbo(}Pvj!cf+)^g+Y2FDUM!vV z+N#q`>7I#@%?yRi(8+>`_B@Gxc)h-W4rlm^x_2_wfgKcMX4%LAmj3*{CJ(v-%^$$G z$J*wOk;wm9Q+iRv8^Rn)P1GfCQPDZtC{@<(#^yE5XuLwZjBXNwi3d~Le1qifCoT;n zJ*7E%t9a(TWo&C3L5Q64UOb4IS~|5%&@GI5e7UojOi$;(0k{p-RVtQKA9OA7pPXAA z<h$6(8vqUDv~s$v-4rJocpN5cCKbHTfF0B}E5E!?UX6O5-coOThMwL84?HH{fH|j~ zfOi)!|9OE9`;JpJgG>(tU`^}UNr2AmP*(Mg#_Z&n`$zK4s373nw$Zx^dLd+Xa_?kP z?WKIN@m$Bl!{<!)A%3%C_i4)moxygCgi+7;d3)1!YO4AfVJ<9aFgECAN~a{C{l)j8 z$|v>A9_Y4kzTxuzCyw0TzIn~hfBW?ege7JEL%6uo=U_dFvkHhb^pFGY>HPk>=XOwj zQ1ZgayZ^fMcI=>^^{^s*rUEU7n>c(xIF|#gt`;glhe&dO;u!V$$o9B|4Rc_My_ABn zkE=kX3zK*pKmSmEB*dNy-X-mJO6ql@-8md`itcsd{cE4mdu7!>9l!exZYV3FfN+Rl z<f=ZN@8jxVK%8(`9Q0bNdl+g{2!;Wy$AYRSs?~5nk%>yhJZwWBotj0(9CU~uVW@@4 z(HHyX{q=@(BL;-61dIw3N@y3cAq{TmiOKQxLNLIGG#20DhQ@ctXp41&EBeLh)sx6; zzSEQ2(Uc3D>x;Y=vJTed0Ux(V4p7lME9oFhzs8085EXy)@wOhCO2=uviHJV43d86` zGqnoC@C4heqHtAxWJ+BrZso#)a^c!;QrTNgb|EPn7IQ3dU>tgVcJgHL>?EmvQvBt* zaMkAS-PR{u8tXIP{vGSp-Ow??-1%qtNcuVx_nfM)csJE-$qua$Ag0<u;7h)I`13yL zR(@o~{>W67%0vhuzTSijWPx?|ft8xGn8uB6oHF}VDrxJl1Lv4>uTK2wdA?K=)rp(E zi0b_o{7*W@A%d{7h4$`N-eXmpuW8Ezm>arxhurhuJd^OJ!+<(d2`!frVCeARxg+Qs zQuqgb-3h=;i5)a#@SOi@z#@(Nv6~M!RK(<Hii@413R2VyV%Z*)qOzTa1TL8!L|oNN zi3TOG8(SYkIMf|%svo#kf<<;C<VZ-asftBs48cE!;e0yV)C?~9Wo<`60!WXI44u~Q zZQ0>7hrdZP%H@$SfG*~~tu2F+P)B6Ext|^0>8lJyXNwT6)?+--f2av5rVfbKVMu6? z6tfi~i$C6~|4Md<Byd70RoXp*Sr(%m6q3^!9Qi$1ay{3RsuV>UjzkSDk_<F~rs?+l zOJoWKf04%sY6shqb4&__A9sE#g<jnBOd+G>?M&eqv-Ypsy$JnZuG|u`NuBr}O!yX% zL!}ZsT8KaKrz?Vh*`zntM6gP92!Ry!xKcY@givwq6+vVIS4@}b<JLrxyT<*~4(vbr zov0D;(>1`Q167Pb*wW{Pz6`lyb6r<MB|e(=c3ZG~c8QC92(UDhubgLxNZ=PH<IVl$ z_gubyc1P?*@&iGD7p)!l;e0*x`LjMF4^Ps41m4_ND-4nrCp4TXYh8sfaV-Fo^H~`} zMDDrr3RC)UIAKB_^rS8s<Y(-V3LsFxF$F!JJRICYdMiH^Hk93HD?Ks@0QE`zCk;)^ z{ti8|C8AL>{iXl&;jxI*efdij{?HpIJofi}-rZjf0}%xVsL}t;N3<rHP#F`*FS*YK zW`a+SKM8W=upi}$BgA(O&n-8BF|??|>-R4|zx3oAq7MAD__0=kl=zphh@`=O!hMb< zghaBqqt9y)kV*TpeCk=caAN;7f0)}=`xjt3so#&El>JB$(GbT}DLU1!)yPmc%5++N zuW_cdMXTzgQwxA$Cq43s82k|uX`@<8j%abX=$K_X7IaJ#9myPoXu6bvyql<uksT#K zgoz^j*I$bsD}j)$7kq5MF0Rlw@hv3-3?|&x@MjvpJkc_)uT2S*PH6@Ix<w)BSaVB- z?^mAu@j=_3-rryMVD71cws}Ym5ju5KiFGXkt5`-Bo||o}3f!C6!R@v^n%Gf~^{Es? zTboW8vq5y4b+~6*?Rw}W*GISGl7}W~&D2xIYOgf`Qp%cz6XppLVK(C3Tr(KepN0X3 z-{H4)#j%Br<{w`N98QNH2{-(18(Vcut{X&JxjAC~fSAuXGNJ#kt*eh_x_#ps3X6rz zTWI2mHMYD(k1UFcJXt;1nwQO}7$Q-tHil6~OjxDzSb1y1kP)6}A|aKK8Ijk#MBa<o zZ#?IBp7T5B_s@Nu^EuzoeP8!|U)S|H=RWs+z6FDop|g)kFkg>f$MK8<ckDkW+xIWS zJ-jPc4=BNZFV5m5kL^B^OMg_MywYMP+G{znZBpp5!n;q&a6(SzA*Xte)UFivzEA9W zIE`FB?88umHCjmS0@1hQ7`Y>U_kV{oRxFq{txiwG1f5a8`>D*h2HjRCU+fM23%(9P z^x`PW);wf=4)Sp>vLy$}&aG|D0j&a_ym-55Hdss2`L4AOj`cOYkPv`N;pow6V1_^W zWzz~5ez;GgdJ1(w7mTZo^1)}m0W6^mz!+0Z-MZ4f$EC^K=c_j}g^7|aX{GgT6VNmK zqOkYrk}<VQuIxe;eJrVuH|NNcs|r#{3seagLZO0G2=d24pgaWmoroeI@yaw(o3q^b z4A(RisB&2t4M{F@?Fa(KS+`|u|Ct_2`z2>MTrSvv(?4y(ZnokYBj(s|a6qLaeLX19 zGg^NS$~{__y*uWj2p0ul@6k^ywCdxHrUf=!7AE`@$UVw*mn18Wj=Gw!X)r0y&b4hh zpgS_EV3S+VzWK$Rh!wV2<O#tibsrSo4aOpFHCOIF3tF(3VTGHoL76rueV$N~oOFKM ze|nRrR?t7te$gO@Hg$Asr0VUsKc3i49DOE;ekjxCcCx~#`_@3<8wU?9_dP|a8mLU8 z?wgj_{bFzT3~s=hVwmwi@aJy1r+s^4*&xl)r2M|U67=xx^h#W4OKm5;Syuu5XK4Me z==iunMD1U>Sp)6yB`yuG?Alw=$DeXjNGMafbSquM2p-T&qIR4L8LzL&N6qoM=qM7^ z2eKzS7z|WnhBsUD5n#kI7ufLUlsF7*;B(5>IQy=X;E;<l3AA2hrx{&Z+`dX8@Zz_A zeBrnmNsV^O%0R2+D#a2BW)ceK>lJvn0WjLI)d+4;IS(kv8flLwmDs)k*86N3l}?}~ z#umTz*)lXo{C6zC`@;32@Pok0UFEm%9}st>Jv4-`7W*#E%y#9I5A<HIp?%Ey(jGsi z%tMs8%;#$=0z>YpHL(1DqvxLWpcq~VOx9p}1J;7hdfn!L=9LP>F}!J7azO4<6^3hk z9_G2ks`O5J?mgH>bV9~Zr^G&pTf=#SdUPFWX98`NGh61@t7SNc85;BFllNPhVupXA zw<GD(?YL^V!-VoQ9si-CbD_**1p&Ue5U+jrJM+9X!geDF+4;U3(tqNO8>XVLG_^1x z7^_mAc1Qek6<5pCSs^M4bepM5GVWivU+azILsS^-cM)qhJN9}Y`7F>+<su#YhxlKz z?!lESf$qV_$^1}?d)7D0+K$&+W0A1oa;?Ve+XKJcu0Mh8QMhW0jg|B&g7eBC;*Kq1 z?Q3&$y~o;%+2e2-GSB((=`5~)nmsZ*7mh><M-LaA>fY7F0wE*iJB@BYhPM@KnO+8Z zOJFtiu$e=p_UNKea!EQZ$0i%r%0dq1>2$-0ZIh~#Lp^}7GL9^^wl442VQhFGZ-T;$ zdw0~+JFsC}!6^e9?pI;J3dVSileNyZL)TU*YVNoMg_%Ut@T#%rB!GNnAEbP4jh=OO z+1L92nxo!sL>!D?^NJkq0O1;{0iT#{WM+aR&#@{fJuNU@ob>wyPrve9)eFTJQQw~+ z+fi@Z>qOMX0<^@-NBOWUxy;rStg+Bd$IYg+|GcaEbv0DpcT3n#GO~yY!$neI`JbfZ zc}fKxa6*rdZN6qi|4RUlS~as9{~JA4PMj$CZj#6nXKO%M{-{=x=)9Q(=)?VMI2=sR z72Q;Wn5sdx0{MNQHM6^O(cGGP7HA$oUXG!bNNm~`K6h0C=fRqxAX21T8Jb|KpOP%$ zyP`pyiR`m-T50(cVOMHu;cI@^?P;=JdzV6U7bh57=E(Cc@jJydLN9giNxvd4Q6ruY z3Uh<8&idH?3EpC1s?nA40r!^T#HPy2-}k`^<dcjF|KGaImYE02EoaU*XPO5w&Q$hG z(XAuo&hP$bZYTuZeizqZK!>#IpZKH6>7U6N;Cvwd=U{rBJ*>J;uyi^vg@iF<8{xdb z{v^zBn^*~=H<W;}p#*?dr=37`S^Y9}T_p@Px<9TY$|~CDi_PO-!Ri$RR~z*;8|R)w z9!u|Criz;bR#c4F67H`<nd?upC@!#~d+Kx|RGj-7Jc7!o{-sqf!I2n4vEZl}lkYNJ zM54_@``&xlQ^LbLXa}S_QXF^cL3b!IJ^qr?Wmu+!&?Qi^I|4e#bQMpA81qX|Q*u4t z{pOw@&nfi?7XQ%R<)5x99BUDj4XGnC*VhXLlbEI7EtWbL)d++eu0K~AKRF~MMVgRJ z8&1nttPUK^7`h&q>g@5u?Lg(-620pmpA$az-6oh{8*LeCL=PHX-62|6v`&l^ZP)&B zqrO2ab0sY1lfM;tqFQp|PQ|&Q7t`2N>v~QRM(<3q8O&j3qUr33(pz!F>O&Tx#Cf7} zU{%ny#f)z@5f8fNA0{q}5~Q3WYE~Zq^zGB9h-B(s!7na(yiVrqtLb)~^}&jt`@!Kn zs%mDos-*2i7~y=Ke1pey{<!<)arce|cGbd{=e=oG%>6C8)=UF9Uk^MuB5kcIov50A z_1czq2F>&U>%XHGSy60v%$GRDaxXvX3+l&r<L&PX#+jGLnH>xAp5oVrluD6b->P?p zP}H;%B4Vt(#11AD*A!7k9KVjut|frQ+eL9@Qe2&p3&^=$l571b^T<-01)T!#&K%I% zv5EL~;^e0z<XaR^y3K+&%li{cj4tM5vb_@A;i=MIX$Y_3!EyU(bNG6{>O!?*2|T5T zp6GI5uv}GrfOa&wW5(f?_KDNTJSUxVAL@MZ=8rIFS0SBM^tZv&fBobdLl#@A7FwX^ zAsqV1)rZn(RYuvFh&p-aaFkC(2MaXmgUK~+gaNt6y34F5L^#gVZbGwa0q<$&2eFnF z&Nc(AnL-otjn<kd^T7uCa^yJAs9JEou@phLasj4172_Y)b#1TA`MxWY6-6`EeRvYh z1VB{BePeOm@=M&(xa}Qie|^q&bMOt(Ah)yw{r$%fm)|s#1f9Ennz6S&n(-Q+Q&55% z4n?a6z|=^)+%hzP4%+c54wT408U4%zYjtp<wZcB<B<VfL_02AXmrX+(-5};HIhYqk zKbukbw{jdJHT?+w?HR(`eRyYCPB@ff7*%deb5&Du+d>OJo)oSo%eI7abmfQ+xXyg> z;k8?kjN9WN5=E!$LES;V!ti&0JF-H)&WU@MOrU4}a6wyNn2IZQf^wqksua;o1CFk_ zn<CX*4Wey!Znj)`znyt@u<W8%nqkc%!TCi-{z-u{+L>A&%YTX@bf$5;q}=Yy5#@0? zD70n=TGJ8j1R(y1+;4_6+5$Tw$2Ng-nh~7UnFvvTM1@q>OBc@0>#Og>GPQ(`rJ=8< z&cYU-e+WC2JakCmrK~nQgeTEP-Ps0F+KUklT6k1rnK4#Jg9HHYLU+7bpdh*~z!0yM zEH|lkNO2oFuR}TXW;m1<ZUN<(E__wTdAcM&f^<pCP3|%8IwsYHt4JMVYt`iIM(iVH ze+Eww4bHUvyyR8L&^T$Oif*e77-6I9^CSSU-mBauW{b?&tUYza@$C=<EEoWmgv885 z*F8P0I=_PrrP+f?H)-@6&N#;3ga8TP@@=c^#)Imw2D7|3YmcM^GTOYl_Mo=Je*n^u Bao_*| From d27d897e2cf80ef9d165954996646f0480660b22 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 21:10:24 +0100 Subject: [PATCH 39/44] command pas utiles --- .../commands/HalloweenFestivalCommands.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 index 46338e8d4..3845203ac 100644 --- 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 @@ -32,17 +32,17 @@ public void openStoreMenu(Player player) { new WitchShopStoreMenu(player, 1).open(); } - @Subcommand("place store") - @CommandPermission("omc.admins.commands.halloween_festival.place.store") - public void placeStore(Player player) { - HalloweenFestivalManager.placeWitchStore(player.getLocation()); - } - - @Subcommand("remove store") - @CommandPermission("omc.admins.commands.halloween_festival.remove.store") - public void removeStore(Player player) { - HalloweenFestivalManager.removeWitchStore(); - } +// @Subcommand("place store") +// @CommandPermission("omc.admins.commands.halloween_festival.place.store") +// public void placeStore(Player player) { +// HalloweenFestivalManager.placeWitchStore(player.getLocation()); +// } +// +// @Subcommand("remove store") +// @CommandPermission("omc.admins.commands.halloween_festival.remove.store") +// public void removeStore(Player player) { +// HalloweenFestivalManager.removeWitchStore(); +// } @Subcommand("place house") @CommandPermission("omc.admins.commands.halloween_festival.place.house") From 370288f4998382b26d3ae8ee091230e6aedb5805 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 21:16:04 +0100 Subject: [PATCH 40/44] gestion de la mort --- .../festival/listeners/TerrorHouseListener.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 index cc9b5514f..2e85e3937 100644 --- 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 @@ -21,6 +21,7 @@ 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; @@ -43,6 +44,16 @@ public void onPlayerJoin(PlayerJoinEvent event) { 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(); From 3a2735ded2304b819c42d12e973d22ec670ce723 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Thu, 29 Oct 2026 21:18:18 +0100 Subject: [PATCH 41/44] =?UTF-8?q?effet=20du=20diab=C3=A8te=20ajout=C3=A9?= =?UTF-8?q?=20mdr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../contents/halloween/festival/listeners/CandyListener.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 index 74e12212b..152cf2001 100644 --- 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 @@ -7,6 +7,8 @@ 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; @@ -36,7 +38,8 @@ public void onCandyEat(PlayerItemConsumeEvent event) { sugarIdx += candy.getDiabetesIndex(); if (sugarIdx >= 20) { - //TODO faire un truc + 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); From 1461c71e595f3787bbdb1e4a89dd44abe88ddeff Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Fri, 30 Oct 2026 10:31:51 +0100 Subject: [PATCH 42/44] review --- .../contents/halloween/festival/HalloweenFestivalManager.java | 2 -- .../events/contents/halloween/festival/shop/ShopMoney.java | 1 - .../halloween/festival/witchhouse/TerrorHouseManager.java | 4 ++-- .../festival/witchhouse/advancement/floor/Floor.java | 4 ++-- .../festival/witchhouse/chests/menu/LootChestMenu.java | 2 +- 5 files changed, 5 insertions(+), 8 deletions(-) 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 index f67823bac..4287bd91b 100644 --- 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 @@ -44,8 +44,6 @@ public class HalloweenFestivalManager extends Feature implements LoadAfterItemsAdder, HasDatabase, HasListeners, HasCommands { - //TODO quand acheter truc dans shop - @Getter private static HalloweenDB halloweenDB; 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 index a5447aefd..aca4768da 100644 --- 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 @@ -8,7 +8,6 @@ @Getter public enum ShopMoney { - //TODO rajouter les crafts 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), 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 index 712d5ffe0..b509ae20c 100644 --- 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 @@ -76,7 +76,7 @@ public static void updateAdvancement(int increase) { globalAdvancement += increase; floorAdvancement += increase; - CheckForPointRewards(); + checkForPointRewards(); if (finalFloorReach) return; @@ -87,7 +87,7 @@ public static void updateAdvancement(int increase) { updateFloor(); } - private static void CheckForPointRewards() { + private static void checkForPointRewards() { if (currentRewardToReach.equals(PointRewards.NULL)) return; 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 index 63fc7b043..32ef862ec 100644 --- 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 @@ -52,14 +52,14 @@ public void enableSpawn() { clearLag(); if (entities.isEmpty()) { - //OMCLogger.warn("No mob register for the spawn mob, spawn disable for this floor"); + 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"); + OMCLogger.warn("No spawn location register for the spawn mob, spawn disable for this floor"); clearLag(); spawnTask.cancel(); return; 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 index 58884268c..f331c9084 100644 --- 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 @@ -43,7 +43,7 @@ public LootChestMenu(Player owner, LootReward loot) { @Override public String getTexture() { - return ""; //TODO je sais pas quoi mettre + return ""; //il n'a pas besoin de texture } @Override From 120284c2fb423c03d58b85f1c10195cbf8ad1e42 Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Fri, 30 Oct 2026 10:33:51 +0100 Subject: [PATCH 43/44] review 2 --- .../festival/commands/HalloweenFestivalCommands.java | 12 ------------ 1 file changed, 12 deletions(-) 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 index 3845203ac..814eb6ba4 100644 --- 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 @@ -32,18 +32,6 @@ public void openStoreMenu(Player player) { new WitchShopStoreMenu(player, 1).open(); } -// @Subcommand("place store") -// @CommandPermission("omc.admins.commands.halloween_festival.place.store") -// public void placeStore(Player player) { -// HalloweenFestivalManager.placeWitchStore(player.getLocation()); -// } -// -// @Subcommand("remove store") -// @CommandPermission("omc.admins.commands.halloween_festival.remove.store") -// public void removeStore(Player player) { -// HalloweenFestivalManager.removeWitchStore(); -// } - @Subcommand("place house") @CommandPermission("omc.admins.commands.halloween_festival.place.house") public void placeHouse(Player player) { From 82dce693c06bbcf55e4ef37e2076896bcc08c70d Mon Sep 17 00:00:00 2001 From: Nocolm <nocolm77@gmail.com> Date: Fri, 30 Oct 2026 10:40:00 +0100 Subject: [PATCH 44/44] disable pvp --- .../halloween/festival/witchhouse/DimensionGenerator.java | 1 + 1 file changed, 1 insertion(+) 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 index 5a818c105..69d8f8469 100644 --- 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 @@ -43,6 +43,7 @@ private static void setupDimension() { 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);