diff --git a/.github/README.md b/.github/README.md index 560338605..1d7157335 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,50 +1,30 @@ -![](https://images.plugily.xyz/banner/display.php?id=VillageDefense) - -# Village Defense [![Maven Repository](https://maven.plugily.xyz/api/badge/latest/releases/plugily/projects/villagedefense?color=40c14a&name=Maven&prefix=v)](https://maven.plugily.xyz/#/releases/plugily/projects/villagedefense) [![JavaDoc Repository](https://maven.plugily.xyz/api/badge/latest/releases/plugily/projects/villagedefense?color=40c14a&name=JavaDoc&prefix=v)](https://maven.plugily.xyz/javadoc/releases/plugily/projects/villagedefense/latest) [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=Plugily-Projects_Village_Defense&metric=sqale_rating)](https://sonarcloud.io/summary/overall?id=Plugily-Projects_Village_Defense) [![Discord](https://img.shields.io/discord/345628548716822530.svg?color=7289DA&style=for-the-badge&logo=discord)](https://discord.plugily.xyz) [![Patreon]( https://img.shields.io/badge/Patreon-F96854?style=for-the-badge&logo=patreon&logoColor=white)](https://patreon.com/plugily) - -Village Defense is a Minecraft minigame designed for small and big servers. This minigame is unique and very -configurable, 100% free and open source! - -The goal is to protect Villagers from hordes of undead Creatures. However, the game isn't that easy. There are more and -more zombies every wave and more types of them come in higher waves. There is no wave limit so try to survive as long as -you can! - -Have fun using it! Leave a good rating if you really like it. - -## Want to contribute in this project? - -[**🉑 Code Contributions**](https://github.com/Plugily-Projects/Village_Defense/blob/master/.github/CONTRIBUTING.md) -[**💣 Issues Reporting (Discord)**](https://discordapp.com/invite/UXzUdTP) -[**❤ Make Donation**](https://www.paypal.me/plugilyprojects) - -# Credits - -## Open Source Libraries - -| Library | Author | License | -|------------------------------------------------------------------|--------------------------------------------------------|------------------------------------------------------------------------------------| -| [MiniGamesBox](https://github.com/Plugily-Projects/MiniGamesBox) | [Plugily Projets](https://github.com/Plugily-Projects) | [GPLv3](https://github.com/Plugily-Projects/MiniGamesBox/blob/master/LICENSE.md) | -| [ScoreboardLib](https://github.com/TigerHix/ScoreboardLib/) | [TigerHix](https://github.com/TigerHix) | [LGPLv3](https://github.com/TigerHix/ScoreboardLib/blob/master/LICENSE) | -| [HikariCP](https://github.com/brettwooldridge/HikariCP) | [brettwooldridge](https://github.com/brettwooldridge) | [Apache License 2.0](https://github.com/brettwooldridge/HikariCP/blob/dev/LICENSE) | -| [bStats](https://github.com/Bastian/bStats-Metrics) | [Bastian](https://github.com/Bastian) | [LGPLv3](https://github.com/Bastian/bStats-Metrics/blob/master/LICENSE) | -| [Commons Box](https://github.com/Plajer/Commons-Box) | [Plajer](https://github.com/Plajer) | [GPLv3](https://github.com/Plajer/Commons-Box/blob/master/LICENSE.md) | - -## Open Source Licenses - -#### JetBrains - -jetbrains logo - -Thanks to JetBrains for Open Source Program license for open source development. - -#### Code Whale - -jetbrains logo - -Thanks to Code Whale for Open Source license for POEditor project. - -## Contributors - -[List of all contributors here](https://plajer.xyz/contributors/villagedefense.html) - - +# Village Defense Gold + +A hard fork created to implement many new exciting features into Village Defense 4.0.0. + +Formerly known as Village Defense 5.0.0 update this hard fork now focuses on personal upgrades to the codebase with new +gameplay stuff and other features. + +**No support and maintenance obligations are provided for this hard fork as it's only intended for private/limited group +use only.** +**Feel free to compile sources yourself and edit the plugin accordingly to your needs** + +Depends on [MinigamesBoxGold](https://github.com/Plajer/MinigamesBoxGold) + +### List of features done and planned for this version: + +* **Opinionated design choices and hardcoded values and options** +* Many QoL and gameplay loop and pacing improvements +* Drastically improved Look and Feel (sounds & effects) +* Many fixes including ally pets targeting villagers/other pets/players +* Kits balance changes +* Revamped powerups +* Revamped entity upgrades (including hidden & special upgrades) +* Mid-wave special events (shop offer, rotten flesh trader, pinata etc.) +* Arena personal records +* Enemies spawn system revamp +* New and more enjoyable enemies +* Shop auto armor equip +* Bosses between every game state (wave 15, wave 30, wave 50) +* Engineer kit - replacement for Builder kit but with Turrets +* Weekly random challenges \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index ee0f49901..f2d959aba 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ plugins { @@ -28,24 +28,42 @@ repositories { maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") maven("https://oss.sonatype.org/content/repositories/snapshots") maven("https://oss.sonatype.org/content/repositories/central") - maven(uri("https://papermc.io/repo/repository/maven-public/")) + maven(uri("https://repo.papermc.io/repository/maven-public/")) maven(uri("https://maven.plugily.xyz/releases")) maven(uri("https://maven.plugily.xyz/snapshots")) maven(uri("https://repo.citizensnpcs.co/")) maven(uri("https://repo.maven.apache.org/maven2/")) + maven(uri("https://repo.dmulloy2.net/repository/public/")) + maven(uri("https://maven.citizensnpcs.co/repo")) } dependencies { - implementation("plugily.projects:MiniGamesBox-Classic:1.2.0-SNAPSHOT36") { isTransitive = false } - compileOnly("org.spigotmc:spigot-api:1.19.3-R0.1-SNAPSHOT") + implementation(files("lib/box-classic.jar")) + implementation(files("lib/box-db.jar")) + implementation(files("lib/box-inv.jar")) + implementation(files("lib/box-utils.jar")) + implementation("com.github.stefvanschie.inventoryframework:IF:0.10.17") + implementation("org.openjdk.nashorn:nashorn-core:15.1") + implementation("fr.skytasul:glowingentities:1.4.2") + implementation("fr.skytasul:guardianbeam:2.4.0") + compileOnly("net.citizensnpcs:citizens-main:2.0.35-SNAPSHOT") { + isTransitive = false + } + compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT") compileOnly("org.jetbrains:annotations:24.0.1") + + compileOnly("com.mojang:authlib:3.11.50") + compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0") compileOnly(files("lib/spigot/1.8.8-R0.1.jar")) + + compileOnly("org.projectlombok:lombok:1.18.32") + annotationProcessor("org.projectlombok:lombok:1.18.32") } group = "plugily.projects" -version = "4.6.1-SNAPSHOT79" +version = "5.0.1-SNAPSHOT7" description = "VillageDefense" java { withJavadocJar() @@ -56,7 +74,16 @@ tasks { dependsOn(shadowJar) } + jar { + manifest { + attributes["paperweight-mappings-namespace"] = "spigot" + } + } + shadowJar { + manifest { + attributes["paperweight-mappings-namespace"] = "spigot" + } archiveClassifier.set("") relocate("plugily.projects.minigamesbox", "plugily.projects.villagedefense.minigamesbox") relocate("com.zaxxer.hikari", "plugily.projects.villagedefense.database.hikari") @@ -73,6 +100,12 @@ tasks { options.encoding = "UTF-8" } + compileJava { + options.encoding = "UTF-8" + targetCompatibility = JavaVersion.VERSION_17.toString() + sourceCompatibility = JavaVersion.VERSION_17.toString() + } + } publishing { diff --git a/src/main/java/plugily/projects/villagedefense/Main.java b/src/main/java/plugily/projects/villagedefense/Main.java index 3b82dbbad..79155e0c2 100644 --- a/src/main/java/plugily/projects/villagedefense/Main.java +++ b/src/main/java/plugily/projects/villagedefense/Main.java @@ -1,24 +1,25 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense; -import org.bukkit.Bukkit; +import fr.skytasul.glowingentities.GlowingEntities; +import lombok.Getter; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPluginLoader; @@ -27,6 +28,7 @@ import plugily.projects.minigamesbox.classic.handlers.setup.SetupInventory; import plugily.projects.minigamesbox.classic.handlers.setup.categories.PluginSetupCategoryManager; import plugily.projects.minigamesbox.classic.utils.configuration.ConfigUtils; +import plugily.projects.minigamesbox.classic.utils.misc.MiscUtils; import plugily.projects.minigamesbox.classic.utils.services.metrics.Metrics; import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; import plugily.projects.villagedefense.arena.Arena; @@ -34,44 +36,36 @@ import plugily.projects.villagedefense.arena.ArenaManager; import plugily.projects.villagedefense.arena.ArenaRegistry; import plugily.projects.villagedefense.arena.ArenaUtils; -import plugily.projects.villagedefense.arena.managers.enemy.spawner.EnemySpawnerRegistry; -import plugily.projects.villagedefense.arena.managers.enemy.spawner.EnemySpawnerRegistryLegacy; +import plugily.projects.villagedefense.arena.managers.shop.ArenaShopRegistry; +import plugily.projects.villagedefense.arena.managers.spawner.gold.DoorBreakListener; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.EnemiesRegistry; +import plugily.projects.villagedefense.arena.powerup.PowerupEvents; import plugily.projects.villagedefense.boot.AdditionalValueInitializer; import plugily.projects.villagedefense.boot.MessageInitializer; import plugily.projects.villagedefense.boot.PlaceholderInitializer; import plugily.projects.villagedefense.commands.arguments.ArgumentsRegistry; -import plugily.projects.villagedefense.creatures.CreatureUtils; -import plugily.projects.villagedefense.creatures.DoorBreakListener; +import plugily.projects.villagedefense.events.ChatEvents; +import plugily.projects.villagedefense.events.EntityUpgradeListener; import plugily.projects.villagedefense.events.PluginEvents; -import plugily.projects.villagedefense.handlers.powerup.PowerupHandler; +import plugily.projects.villagedefense.handlers.hologram.NewHologramManager; import plugily.projects.villagedefense.handlers.setup.SetupCategoryManager; -import plugily.projects.villagedefense.handlers.upgrade.EntityUpgradeMenu; -import plugily.projects.villagedefense.handlers.upgrade.upgrades.Upgrade; -import plugily.projects.villagedefense.handlers.upgrade.upgrades.UpgradeBuilder; -import plugily.projects.villagedefense.kits.free.KnightKit; -import plugily.projects.villagedefense.kits.free.LightTankKit; -import plugily.projects.villagedefense.kits.level.ArcherKit; -import plugily.projects.villagedefense.kits.level.GolemFriendKit; -import plugily.projects.villagedefense.kits.level.HardcoreKit; -import plugily.projects.villagedefense.kits.level.HealerKit; -import plugily.projects.villagedefense.kits.level.LooterKit; -import plugily.projects.villagedefense.kits.level.MediumTankKit; -import plugily.projects.villagedefense.kits.level.PuncherKit; -import plugily.projects.villagedefense.kits.level.RunnerKit; -import plugily.projects.villagedefense.kits.level.TerminatorKit; -import plugily.projects.villagedefense.kits.level.WorkerKit; -import plugily.projects.villagedefense.kits.level.ZombieFinderKit; -import plugily.projects.villagedefense.kits.premium.BlockerKit; -import plugily.projects.villagedefense.kits.premium.CleanerKit; -import plugily.projects.villagedefense.kits.premium.DogFriendKit; -import plugily.projects.villagedefense.kits.premium.HeavyTankKit; -import plugily.projects.villagedefense.kits.premium.MedicKit; -import plugily.projects.villagedefense.kits.premium.NakedKit; -import plugily.projects.villagedefense.kits.premium.PremiumHardcoreKit; -import plugily.projects.villagedefense.kits.premium.ShotBowKit; -import plugily.projects.villagedefense.kits.premium.TeleporterKit; -import plugily.projects.villagedefense.kits.premium.TornadoKit; -import plugily.projects.villagedefense.kits.premium.WizardKit; +import plugily.projects.villagedefense.handlers.upgrade.EntityUpgradeHandlerEvents; +import plugily.projects.villagedefense.handlers.upgrade.NewEntityUpgradeManager; +import plugily.projects.villagedefense.kits.BuilderKit; +import plugily.projects.villagedefense.kits.CleanerKit; +import plugily.projects.villagedefense.kits.CrusaderKit; +import plugily.projects.villagedefense.kits.KitsMenu; +import plugily.projects.villagedefense.kits.KnightKit; +import plugily.projects.villagedefense.kits.MedicKit; +import plugily.projects.villagedefense.kits.ShotBowKit; +import plugily.projects.villagedefense.kits.TornadoKit; +import plugily.projects.villagedefense.kits.WizardKit; +import plugily.projects.villagedefense.kits.petsfriend.PetsFriendKit; +import plugily.projects.villagedefense.kits.terminator.TerminatorKit; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.user.VDUserManager; +import plugily.projects.villagedefense.utils.ProtocolUtils; import java.io.File; import java.util.logging.Level; @@ -82,11 +76,18 @@ */ public class Main extends PluginMain { - private FileConfiguration entityUpgradesConfig; - private EnemySpawnerRegistryLegacy enemySpawnerRegistry; + private @Getter FileConfiguration entityUpgradesConfig; + private @Getter EnemiesRegistry newEnemiesRegistry; + private @Getter NewEntityUpgradeManager entityUpgradeManager; + private @Getter NewHologramManager newHologramManager; + private @Getter VDUserManager vdUserManager; + private @Getter GlowingEntities glowingEntities; + private @Getter KitsMenu kitsMenu; + private @Getter ArenaShopRegistry arenaShopRegistry; + + private ArgumentsRegistry argumentsRegistry; private ArenaRegistry arenaRegistry; private ArenaManager arenaManager; - private ArgumentsRegistry argumentsRegistry; @TestOnly public Main() { @@ -103,6 +104,9 @@ public void onEnable() { long start = System.currentTimeMillis(); MessageInitializer messageInitializer = new MessageInitializer(this); super.onEnable(); + /*if(!validateStartup()) { + return; + }*/ getDebugger().debug("[System] [Plugin] Initialization start"); new PlaceholderInitializer(this); messageInitializer.registerMessages(); @@ -113,33 +117,48 @@ public void onEnable() { getDebugger().debug("[System] [Plugin] Initialization finished took {0}ms", System.currentTimeMillis() - start); } + private boolean validateStartup() { + if (ServerVersion.Version.isCurrentLower(ServerVersion.Version.v1_12_R1)) { + MiscUtils.sendLineBreaker(this.getName()); + getMessageUtils().thisVersionIsNotSupported(); + MiscUtils.sendVersionInformation(this, this.getName(), this.getDescription()); + getDebugger().sendConsoleMsg(getPluginMessagePrefix() + "&cYour server version is not supported by " + this.getDescription().getName() + "!"); + getDebugger().sendConsoleMsg(getPluginMessagePrefix() + "&cSadly, we must shut off. Maybe you consider changing your server version?"); + MiscUtils.sendLineBreaker(this.getName()); + getServer().getPluginManager().disablePlugin(this); + return false; + } + return true; + } + public void initializePluginClasses() { - addFileName("powerups"); - addFileName("creatures"); Arena.init(this); ArenaUtils.init(this); + arenaShopRegistry = new ArenaShopRegistry(); + arenaShopRegistry.registerItems(); + KitHelper.init(this); + ProtocolUtils.init(this); new ArenaEvents(this); + new PowerupEvents(this); + new ChatEvents(this); + newEnemiesRegistry = new EnemiesRegistry(this); + vdUserManager = new VDUserManager(this); arenaManager = new ArenaManager(this); arenaRegistry = new ArenaRegistry(this); arenaRegistry.registerArenas(); getSignManager().loadSigns(); getSignManager().updateSigns(); argumentsRegistry = new ArgumentsRegistry(this); - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_8_R3)) { - enemySpawnerRegistry = new EnemySpawnerRegistryLegacy(this); - } else { - enemySpawnerRegistry = new EnemySpawnerRegistry(this); - } - if(getConfigPreferences().getOption("UPGRADES")) { - entityUpgradesConfig = ConfigUtils.getConfig(this, "entity_upgrades"); - Upgrade.init(this); - UpgradeBuilder.init(this); - new EntityUpgradeMenu(this); - } + entityUpgradesConfig = ConfigUtils.getConfig(this, "entity_upgrades"); + entityUpgradeManager = new NewEntityUpgradeManager(this); + newHologramManager = new NewHologramManager(this); + kitsMenu = new KitsMenu(this); new DoorBreakListener(this); - CreatureUtils.init(this); - new PowerupHandler(this); + NewCreatureUtils.init(this); new PluginEvents(this); + new EntityUpgradeListener(this); + new EntityUpgradeHandlerEvents(this); + this.glowingEntities = new GlowingEntities(this); addPluginMetrics(); } @@ -147,13 +166,12 @@ public void addKits() { long start = System.currentTimeMillis(); getDebugger().debug("Adding kits..."); addFileName("kits"); - Class[] classKitNames = new Class[]{KnightKit.class, LightTankKit.class, ZombieFinderKit.class, ArcherKit.class, PuncherKit.class, HealerKit.class, LooterKit.class, RunnerKit.class, - MediumTankKit.class, WorkerKit.class, GolemFriendKit.class, TerminatorKit.class, HardcoreKit.class, CleanerKit.class, TeleporterKit.class, HeavyTankKit.class, ShotBowKit.class, - DogFriendKit.class, PremiumHardcoreKit.class, TornadoKit.class, BlockerKit.class, MedicKit.class, NakedKit.class, WizardKit.class}; - for(Class kitClass : classKitNames) { + Class[] classKitNames = new Class[]{KnightKit.class, BuilderKit.class, TornadoKit.class, ShotBowKit.class, MedicKit.class, + CleanerKit.class, PetsFriendKit.class, TerminatorKit.class, CrusaderKit.class, WizardKit.class}; + for (Class kitClass : classKitNames) { try { kitClass.getDeclaredConstructor().newInstance(); - } catch(Exception e) { + } catch (Exception e) { getLogger().log(Level.SEVERE, "Fatal error while registering existing game kit! Report this error to the developer!"); getLogger().log(Level.SEVERE, "Cause: " + e.getMessage() + " (kitClass " + kitClass.getName() + ")"); e.printStackTrace(); @@ -162,23 +180,16 @@ public void addKits() { getDebugger().debug("Kit adding finished took {0}ms", System.currentTimeMillis() - start); } + private void addPluginMetrics() { getMetrics().addCustomChart(new Metrics.SimplePie("hooked_addons", () -> { - if(getServer().getPluginManager().getPlugin("VillageDefense-Enhancements") != null) { + if (getServer().getPluginManager().getPlugin("VillageDefense-Enhancements") != null) { return "Enhancements"; } return "None"; })); } - public FileConfiguration getEntityUpgradesConfig() { - return entityUpgradesConfig; - } - - public EnemySpawnerRegistryLegacy getEnemySpawnerRegistry() { - return enemySpawnerRegistry; - } - @Override public ArenaRegistry getArenaRegistry() { return arenaRegistry; @@ -198,4 +209,5 @@ public ArenaManager getArenaManager() { public PluginSetupCategoryManager getSetupCategoryManager(SetupInventory setupInventory) { return new SetupCategoryManager(setupInventory); } + } diff --git a/src/main/java/plugily/projects/villagedefense/api/event/player/VillagePlayerEntityUpgradeEvent.java b/src/main/java/plugily/projects/villagedefense/api/event/player/VillagePlayerEntityUpgradeEvent.java index b4bde5b77..a1a976106 100644 --- a/src/main/java/plugily/projects/villagedefense/api/event/player/VillagePlayerEntityUpgradeEvent.java +++ b/src/main/java/plugily/projects/villagedefense/api/event/player/VillagePlayerEntityUpgradeEvent.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.api.event.player; @@ -23,7 +23,7 @@ import org.bukkit.event.HandlerList; import plugily.projects.minigamesbox.classic.api.event.PlugilyEvent; import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.handlers.upgrade.upgrades.Upgrade; +import plugily.projects.villagedefense.handlers.upgrade.EntityUpgrade; /** * @author Plajer @@ -31,15 +31,16 @@ *

* Called when player upgrades an entity. */ +@Deprecated public class VillagePlayerEntityUpgradeEvent extends PlugilyEvent { private static final HandlerList HANDLERS = new HandlerList(); private final Entity entity; private final Player player; - private final Upgrade appliedUpgrade; + private final EntityUpgrade appliedUpgrade; private final int tier; - public VillagePlayerEntityUpgradeEvent(Arena eventArena, Entity entity, Player player, Upgrade appliedUpgrade, int tier) { + public VillagePlayerEntityUpgradeEvent(Arena eventArena, Entity entity, Player player, EntityUpgrade appliedUpgrade, int tier) { super(eventArena); this.entity = entity; this.player = player; @@ -63,7 +64,7 @@ public Entity getEntity() { /** * @return upgrade that was applied to entity */ - public Upgrade getAppliedUpgrade() { + public EntityUpgrade getAppliedUpgrade() { return appliedUpgrade; } diff --git a/src/main/java/plugily/projects/villagedefense/arena/Arena.java b/src/main/java/plugily/projects/villagedefense/arena/Arena.java index 4c8313647..0303422dc 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/Arena.java +++ b/src/main/java/plugily/projects/villagedefense/arena/Arena.java @@ -1,56 +1,63 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Location; import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.IronGolem; import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Villager; import org.bukkit.entity.Wolf; +import org.bukkit.metadata.FixedMetadataValue; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import plugily.projects.minigamesbox.classic.arena.ArenaState; import plugily.projects.minigamesbox.classic.arena.PluginArena; import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.managers.CreatureTargetManager; -import plugily.projects.villagedefense.arena.managers.EnemySpawnManager; +import plugily.projects.villagedefense.arena.assist.AssistHandler; import plugily.projects.villagedefense.arena.managers.ScoreboardManager; -import plugily.projects.villagedefense.arena.managers.ShopManager; import plugily.projects.villagedefense.arena.managers.maprestorer.MapRestorerManager; -import plugily.projects.villagedefense.arena.managers.maprestorer.MapRestorerManagerLegacy; +import plugily.projects.villagedefense.arena.managers.shop.ShopManager; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewEnemySpawnerManager; +import plugily.projects.villagedefense.arena.midwave.MidWaveEvent; import plugily.projects.villagedefense.arena.states.EndingState; import plugily.projects.villagedefense.arena.states.InGameState; import plugily.projects.villagedefense.arena.states.RestartingState; import plugily.projects.villagedefense.arena.states.StartingState; -import plugily.projects.villagedefense.creatures.CreatureUtils; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; import java.util.ArrayList; import java.util.EnumMap; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; import java.util.logging.Level; import java.util.stream.Collectors; @@ -66,15 +73,20 @@ public class Arena extends PluginArena { private final List wolves = new ArrayList<>(); private final List villagers = new ArrayList<>(); private final List ironGolems = new ArrayList<>(); + private final List specialEntities = new ArrayList<>(); private final List droppedFleshes = new ArrayList<>(); private final List spawnedEntities = new ArrayList<>(); private MapRestorerManager mapRestorerManager; + private @Getter VillagerAiManager villagerAiManager; + private @Getter + @Setter MidWaveEvent midWaveEvent; + private Map metadataContainer = new HashMap<>(); private final Map> spawnPoints = new EnumMap<>(SpawnPoint.class); private ShopManager shopManager; - private EnemySpawnManager enemySpawnManager; - private CreatureTargetManager creatureTargetManager; + private @Getter NewEnemySpawnerManager newEnemySpawnerManager; + private AssistHandler assistHandler; private boolean fighting = false; @@ -82,13 +94,10 @@ public Arena(String id) { super(id); setPluginValues(); shopManager = new ShopManager(this); - enemySpawnManager = new EnemySpawnManager(this); - creatureTargetManager = new CreatureTargetManager(this); - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_16_R1)) { - mapRestorerManager = new MapRestorerManagerLegacy(this); - } else { - mapRestorerManager = new MapRestorerManager(this); - } + newEnemySpawnerManager = new NewEnemySpawnerManager(this); + mapRestorerManager = new MapRestorerManager(this); + villagerAiManager = new VillagerAiManager(this); + assistHandler = new AssistHandler(plugin); setMapRestorerManager(mapRestorerManager); setScoreboardManager(new ScoreboardManager(this)); @@ -112,7 +121,7 @@ public Main getPlugin() { } private void setPluginValues() { - for(SpawnPoint point : SpawnPoint.values()) { + for (SpawnPoint point : SpawnPoint.values()) { spawnPoints.put(point, new ArrayList<>()); } } @@ -121,17 +130,13 @@ public ShopManager getShopManager() { return shopManager; } - public EnemySpawnManager getEnemySpawnManager() { - return enemySpawnManager; - } - - public CreatureTargetManager getCreatureTargetManager() { - return creatureTargetManager; + public AssistHandler getAssistHandler() { + return assistHandler; } public void clearVillagers() { - for(Entity entity : plugin.getBukkitHelper().getNearbyEntities(getStartLocation(), 50)) { - if(!(entity instanceof Villager)) { + for (Entity entity : plugin.getBukkitHelper().getNearbyEntities(getStartLocation(), 50)) { + if (!(entity instanceof Villager)) { continue; } removeVillager((Villager) entity); @@ -140,18 +145,18 @@ public void clearVillagers() { public void spawnVillagers() { List villagerSpawns = getVillagerSpawns(); - if(villagerSpawns.isEmpty()) { + if (villagerSpawns.isEmpty()) { getPlugin().getDebugger().debug(Level.WARNING, "No villager spawns set for {0} game won't start", getId()); return; } int amount = getPlugin().getConfig().getInt("Limit.Spawn.Villagers", 10); int spawnSize = villagerSpawns.size(); - for(int i = 0; i < amount; i++) { + for (int i = 0; i < amount; i++) { spawnVillager(villagerSpawns.get(i % spawnSize)); } - if(villagers.isEmpty()) { + if (villagers.isEmpty()) { getPlugin().getDebugger().debug(Level.WARNING, "Spawning villagers for {0} failed! Are villager spawns set in safe and valid locations?", getId()); } } @@ -233,101 +238,76 @@ public void setWave(int wave) { } public void spawnVillager(Location location) { - Villager villager = CreatureUtils.getCreatureInitializer().spawnVillager(location); - villager.setCustomNameVisible(getPlugin().getConfigPreferences().getOption("NAME_VISIBILITY_VILLAGER")); - villager.setCustomName(CreatureUtils.getRandomVillagerName()); + Villager villager = NewCreatureUtils.spawnVillager(location); + villager.setCustomNameVisible(true); + String name = NewCreatureUtils.getRandomVillagerName(); + villager.setMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA, new FixedMetadataValue(plugin, name)); + villager.setCustomName(NewCreatureUtils.getHealthNameTag(villager)); + villager.setVillagerLevel(5); + villager.setVillagerType(Villager.Type.values()[ThreadLocalRandom.current().nextInt(Villager.Type.values().length)]); + villager.setProfession(Villager.Profession.values()[ThreadLocalRandom.current().nextInt(Villager.Profession.values().length)]); + villager.setCollidable(false); addVillager(villager); + villagerAiManager.doApplyVillagerPersonality(villager); } - public void spawnWolf(Location location, Player player) { - if(!canSpawnMobForPlayer(player, EntityType.WOLF)) { - return; + @Nullable + public Creature spawnGolem(Location location, Player player) { + if (!canSpawnMobForPlayer(player, EntityType.IRON_GOLEM)) { + return null; } - - Wolf wolf = CreatureUtils.getCreatureInitializer().spawnWolf(location); - wolf.setOwner(player); - wolf.setCustomNameVisible(getPlugin().getConfigPreferences().getOption("NAME_VISIBILITY_WOLF")); - wolf.setCustomName(new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_NAME").asKey().player(player).build()); - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_SPAWN").asKey().player(player).sendPlayer(); - addWolf(wolf); + return spawnGolemForce(location, player); } - public void spawnGolem(Location location, Player player) { - if(!canSpawnMobForPlayer(player, EntityType.IRON_GOLEM)) { - return; - } - - IronGolem ironGolem = CreatureUtils.getCreatureInitializer().spawnGolem(location); - ironGolem.setCustomNameVisible(getPlugin().getConfigPreferences().getOption("NAME_VISIBILITY_GOLEM")); - ironGolem.setCustomName(new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_NAME").asKey().player(player).build()); - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_SPAWN").asKey().player(player).sendPlayer(); + @NotNull + public Creature spawnGolemForce(Location location, Player player) { + IronGolem ironGolem = NewCreatureUtils.spawnIronGolem(location); + ironGolem.setMetadata("VD_OWNER_UUID", new FixedMetadataValue(getPlugin(), player.getUniqueId().toString())); + ironGolem.setMetadata("VD_ALIVE_SINCE_WAVE", new FixedMetadataValue(getPlugin(), getWave())); + ironGolem.setCustomNameVisible(true); + ironGolem.setCustomName(NewCreatureUtils.getHealthNameTag(ironGolem)); addIronGolem(ironGolem); + return ironGolem; } - protected void addWolf(Wolf wolf) { + public void addWolf(Wolf wolf) { wolves.add(wolf); spawnedEntities.add(wolf); } public boolean canSpawnMobForPlayer(Player player, EntityType type) { - if(type != EntityType.IRON_GOLEM && type != EntityType.WOLF) { + if (type != EntityType.IRON_GOLEM && type != EntityType.WOLF) { return false; } - int globalEntityLimit = 0; int entityLimit = 0; - String spawnedName = ""; - switch(type) { + switch (type) { case WOLF: - entityLimit = plugin.getPermissionsManager().getPermissionCategoryValue("PLAYER_SPAWN_LIMIT_WOLVES", player); - spawnedName = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_NAME").asKey().player(player).build(); - globalEntityLimit = plugin.getConfig().getInt("Limit.Spawn.Wolves", 20); + entityLimit = 10; break; case IRON_GOLEM: - entityLimit = plugin.getPermissionsManager().getPermissionCategoryValue("PLAYER_SPAWN_LIMIT_GOLEMS", player); - spawnedName = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_NAME").asKey().player(player).build(); - globalEntityLimit = plugin.getConfig().getInt("Limit.Spawn.Golems", 15); + entityLimit = 5; break; default: break; } - plugin.getDebugger().debug("SpawnMobCheck for {0} and mob {1}, globalLimit {2}, playerLimit {3}", player.getName(), type, globalEntityLimit, entityLimit); - String finalSpawnedName = spawnedName; + plugin.getDebugger().debug("SpawnMobCheck for {0} and mob {1}, globalLimit {2}", player.getName(), type, entityLimit); List entities = new ArrayList<>(spawnedEntities); - if(plugin.getConfigPreferences().getOption("LIMIT_ENTITY_BUY_AFTER_DEATH")) { + if (plugin.getConfigPreferences().getOption("LIMIT_ENTITY_BUY_AFTER_DEATH")) { List entityList = entities.stream().filter(entity -> entity.getType() == type).collect(Collectors.toList()); - entityList = entityList.stream().filter(Entity::isDead).collect(Collectors.toList()); + entityList = entityList + .stream() + .filter(en -> !en.isDead()) + .filter(en -> en.hasMetadata("VD_OWNER_UUID")) + .filter(en -> player.getUniqueId().equals(UUID.fromString(en.getMetadata("VD_OWNER_UUID").get(0).asString()))) + .collect(Collectors.toList()); long spawnedAmount = entityList.size(); - if(spawnedAmount >= globalEntityLimit) { - sendMobLimitReached(player, globalEntityLimit); - return false; - } - - long spawnedPlayerAmount = entityList.stream().filter(entity -> Objects.equals(entity.getCustomName(), finalSpawnedName)).count(); - if(spawnedPlayerAmount >= entityLimit) { - sendMobLimitReached(player, entityLimit); + if (spawnedAmount >= entityLimit) { + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_MOB_LIMIT_REACHED").asKey().player(player).integer(entityLimit).sendPlayer(); return false; } } - boolean finalReturn = false; - switch(type) { - case WOLF: - finalReturn = entityLimit > 0 && wolves.size() < entityLimit; - break; - case IRON_GOLEM: - finalReturn = entityLimit > 0 && ironGolems.size() < entityLimit; - break; - default: - break; - } - if(!finalReturn) { - sendMobLimitReached(player, entityLimit); - } - return finalReturn; - } - - private void sendMobLimitReached(Player player, int entityLimit) { - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_MOB_LIMIT_REACHED").asKey().player(player).integer(entityLimit).sendPlayer(); + return true; } /** @@ -360,17 +340,27 @@ public List getVillagers() { return villagers; } + /** + * Get special alive entities. + * + * @return alive special entities + */ + @NotNull + public List getSpecialEntities() { + return specialEntities; + } + public boolean checkLevelUpRottenFlesh() { String rottenFleshLevelOption = "ROTTEN_FLESH_LEVEL"; int rottenFleshLevel = getArenaOption(rottenFleshLevelOption); int rottenFleshAmount = getArenaOption("ROTTEN_FLESH_AMOUNT"); - if(rottenFleshLevel == 0 && rottenFleshAmount > 50) { + if (rottenFleshLevel == 0 && rottenFleshAmount > 50) { setArenaOption(rottenFleshLevelOption, 1); return true; } - if(rottenFleshLevel * 10 * getPlayers().size() + 10 < rottenFleshAmount) { + if (rottenFleshLevel * 10 * getPlayers().size() + 10 < rottenFleshAmount) { changeArenaOptionBy(rottenFleshLevelOption, 1); return true; } @@ -411,11 +401,37 @@ protected void addIronGolem(IronGolem ironGolem) { public void removeIronGolem(IronGolem ironGolem) { ironGolem.remove(); ironGolems.remove(ironGolem); + spawnedEntities.remove(ironGolem); } public void removeWolf(Wolf wolf) { wolf.remove(); wolves.remove(wolf); + spawnedEntities.remove(wolf); + } + + public void addSpecialEntity(LivingEntity livingEntity) { + specialEntities.add(livingEntity); + } + + public void removeSpecialEntity(LivingEntity entity) { + specialEntities.remove(entity); + } + + public T getMetadata(String key, T defaultValue) { + Object obj = metadataContainer.get(key); + if (obj == null) { + return defaultValue; + } + return (T) obj; + } + + public void setMetadata(String key, Object data) { + metadataContainer.put(key, data); + } + + public void removeMetadata(String key) { + metadataContainer.remove(key); } public enum SpawnPoint { diff --git a/src/main/java/plugily/projects/villagedefense/arena/ArenaEvents.java b/src/main/java/plugily/projects/villagedefense/arena/ArenaEvents.java index ba37599f8..a5782f3d5 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/ArenaEvents.java +++ b/src/main/java/plugily/projects/villagedefense/arena/ArenaEvents.java @@ -1,27 +1,32 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.type.Door; +import org.bukkit.entity.Arrow; import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.IronGolem; import org.bukkit.entity.LivingEntity; @@ -30,12 +35,17 @@ import org.bukkit.entity.Wolf; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityTargetLivingEntityEvent; +import org.bukkit.event.entity.EntityTeleportEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; import plugily.projects.minigamesbox.classic.arena.ArenaState; @@ -46,7 +56,14 @@ import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyEntityPickupItemEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; +import plugily.projects.villagedefense.utils.NearbyUtils; + +import java.util.ArrayList; +import java.util.List; /** * @author Plajer @@ -63,40 +80,216 @@ public ArenaEvents(Main plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } + @EventHandler + public void onBraveTraitRetreat(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Villager villager)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getVillagers().contains(villager)) { + continue; + } + VillagerAiManager aiManager = arena.getVillagerAiManager(); + double healthPercent = villager.getHealth() / villager.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue(); + if (healthPercent <= 0.5) { + villager.setMetadata("VD_BRAVE_RETREAT", new FixedMetadataValue(plugin, true)); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + int homeIndex = villager.getMetadata(VillagerAiManager.VILLAGER_PERSONALITY_CHOSEN_HOME_ID).get(0).asInt(); + Location home = NearbyUtils.getRandomNearbyLocation(aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_HOME_ZONE).get(homeIndex), 2); + aiManager.doStartPathfinder(villager, home, (v, l) -> { + }); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + villager.removeMetadata("VD_BRAVE_RETREAT", plugin); + }, 20 * 10); + }, 20); + } + } + } + + @EventHandler + public void onDoorLockPhysicsBlock(BlockPhysicsEvent event) { + if (!(event.getChangedBlockData() instanceof Door door)) { + return; + } + if (!door.isOpen() && event.getSourceBlock().hasMetadata("VD_DOOR_LOCK")) { + event.setCancelled(true); + } + } + + @EventHandler + public void onCrammingSuffocationDamage(EntityDamageEvent event) { + if (event.getCause() != EntityDamageEvent.DamageCause.CRAMMING && event.getCause() != EntityDamageEvent.DamageCause.SUFFOCATION) { + return; + } + if (event.getEntity().hasMetadata("VD_CUSTOM_ENTITY")) { + event.setCancelled(true); + } + } + + @EventHandler + public void onArrowDecay(ProjectileHitEvent event) { + if (!(event.getEntity() instanceof Arrow arrow)) { + return; + } + if (!(arrow.getShooter() instanceof Player player)) { + return; + } + if (plugin.getArenaRegistry().isInArena(player)) { + Bukkit.getScheduler().runTaskLater(plugin, () -> event.getEntity().remove(), 20 * 4); + } + } + + @EventHandler + public void onWolfTeleport(EntityTeleportEvent event) { + if (!(event.getEntity() instanceof Wolf wolf)) { + return; + } + if (!wolf.hasMetadata("VD_OWNER_UUID")) { + return; + } + if (wolf.hasMetadata("VD_TELEPORT_OVERRIDE_TEMP")) { + return; + } + //is a VD entity, cancel no matter what, unless overridden + event.setCancelled(true); + } + + @EventHandler + public void onDeadTargetAdjust(EntityTargetLivingEntityEvent event) { + if (event.getTarget() == null) { + return; + } + if (event.getTarget().hasMetadata("VD_PET_DEAD")) { + event.setCancelled(true); + } + } + + @EventHandler + public void onPlayerFocusAdjust(EntityTargetLivingEntityEvent event) { + if (!(event.getTarget() instanceof Player)) { + return; + } + Player player = (Player) event.getTarget(); + if (!plugin.getArenaRegistry().isInArena(player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + //cancel targeting of spectators or being targeted by ally pets + if (user.isSpectator() || event.getEntity() instanceof Wolf || event.getEntity() instanceof IronGolem) { + event.setCancelled(true); + } + } + + @EventHandler + public void onAllyFocusAdjust(EntityTargetLivingEntityEvent event) { + if (event.getTarget() instanceof Player) { + //prevent ally pets targeting players + if (event.getEntity() instanceof Wolf || event.getEntity() instanceof IronGolem) { + //cancel no matter which wolf/golem targets player, naively assume it's the same arena entity + if (plugin.getArenaRegistry().isInArena((Player) event.getTarget())) { + event.setCancelled(true); + } + } + } else if (event.getTarget() instanceof Wolf || event.getTarget() instanceof IronGolem) { + //prevent ally pets targeting ally pets + if (event.getEntity() instanceof Wolf || event.getEntity() instanceof IronGolem) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + List allies = new ArrayList<>(); + allies.addAll(arena.getWolves()); + allies.addAll(arena.getIronGolems()); + if (allies.contains(event.getEntity()) && allies.contains(event.getTarget())) { + event.setCancelled(true); + return; + } + } + } + } else if (event.getTarget() instanceof Villager villager) { + //prevent ally pets targeting villagers + if (event.getEntity() instanceof Wolf || event.getEntity() instanceof IronGolem) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + List allies = new ArrayList<>(); + allies.addAll(arena.getWolves()); + allies.addAll(arena.getIronGolems()); + if (allies.contains(event.getEntity()) && arena.getVillagers().contains(villager)) { + event.setCancelled(true); + return; + } + } + } + } + } + //override WorldGuard build deny flag where villagers cannot be damaged @EventHandler(priority = EventPriority.HIGHEST) public void onVillagerDamage(EntityDamageByEntityEvent e) { - if(e.getEntityType() != EntityType.VILLAGER || !(e.getDamager() instanceof Creature)) { + if (e.getEntityType() != EntityType.VILLAGER || !(e.getDamager() instanceof Creature)) { return; } - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(arena.getVillagers().contains(e.getEntity()) && arena.getEnemies().contains(e.getDamager())) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (arena.getVillagers().contains(e.getEntity()) && arena.getEnemies().contains(e.getDamager())) { e.setCancelled(false); + e.getEntity().setCustomName(NewCreatureUtils.getHealthNameTagPreDamage((Creature) e.getEntity(), e.getFinalDamage())); + XSound.ENTITY_VILLAGER_HURT.play(e.getEntity().getLocation(), 10.0f, 1.0f); + + doApplyDamageGlowingWarning(e.getDamager(), arena); break; } } } + private void doApplyDamageGlowingWarning(Entity target, Arena arena) { + String GLOWING_TARGET_METADATA = "VD_RECENT_VILLAGER_DAMAGE_GLOW"; + target.setMetadata(GLOWING_TARGET_METADATA, new FixedMetadataValue(plugin, true)); + new BukkitRunnable() { + boolean toggle = false; + int tick = 0; + + @Override + public void run() { + if (target.isDead() || tick >= 60) { + try { + target.removeMetadata(GLOWING_TARGET_METADATA, plugin); + for (Player player : arena.getPlayers()) { + plugin.getGlowingEntities().unsetGlowing(target, player); + } + } catch (Exception ignored) { + } + cancel(); + return; + } + try { + for (Player player : arena.getPlayers()) { + plugin.getGlowingEntities().setGlowing(target, player, toggle ? ChatColor.YELLOW : ChatColor.RED); + } + } catch (Exception ignored) { + } + toggle = !toggle; + tick += 10; + } + }.runTaskTimer(plugin, 0, 10); + } + + //todo apply kills for golem by VD_OWNER_UUID detection @EventHandler public void onDieEntity(EntityDamageByEntityEvent e) { - if(!(e.getDamager() instanceof Wolf && e.getEntity() instanceof Creature)) { + if (!(e.getDamager() instanceof Wolf && e.getEntity() instanceof Creature)) { return; } - if(e.getDamage() >= ((Creature) e.getEntity()).getHealth()) { + if (e.getDamage() >= ((Creature) e.getEntity()).getHealth()) { //trick to get non player killer of zombie - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(arena.getEnemies().contains(e.getEntity())) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (arena.getEnemies().contains(e.getEntity())) { org.bukkit.entity.AnimalTamer owner = ((Wolf) e.getDamager()).getOwner(); - if(owner instanceof Player) { //prevent offline player cast error + if (owner instanceof Player) { //prevent offline player cast error Player player = (Player) owner; - if(plugin.getArenaRegistry().getArena(player) != null) { + if (plugin.getArenaRegistry().getArena(player) != null) { plugin.getUserManager().addStat(player, plugin.getStatsStorage().getStatisticType("KILLS")); - plugin.getUserManager().addExperience(player, 2 * arena.getArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER")); + plugin.getUserManager().addExperience(player, (int) (2 * Math.log(arena.getWave()))); } } @@ -110,16 +303,16 @@ public void onDieEntity(EntityDamageByEntityEvent e) { public void onItemDrop(ItemSpawnEvent e) { org.bukkit.entity.Item item = e.getEntity(); - if(item.getItemStack().getType() != Material.ROTTEN_FLESH) { + if (item.getItemStack().getType() != Material.ROTTEN_FLESH) { return; } Location itemLoc = item.getLocation(); - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { Location start = arena.getStartLocation(); - if(itemLoc.getWorld() != start.getWorld() || itemLoc.distance(start) > 150) { + if (itemLoc.getWorld() != start.getWorld() || itemLoc.distance(start) > 150) { continue; } @@ -128,63 +321,14 @@ public void onItemDrop(ItemSpawnEvent e) { } @EventHandler - public void onEntityDamage(EntityDamageEvent event) { - if(event.getEntityType() != EntityType.IRON_GOLEM && event.getEntityType() != EntityType.WOLF) - return; - - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - switch(event.getEntityType()) { - case IRON_GOLEM: - if(!arena.getIronGolems().contains(event.getEntity())) { - continue; - } - - IronGolem ironGolem = (IronGolem) event.getEntity(); - - if(ironGolem.getHealth() <= event.getDamage()) { - event.setCancelled(true); - event.setDamage(0); - arena.removeIronGolem(ironGolem); - } - return; - case WOLF: - if(!arena.getWolves().contains(event.getEntity())) { - continue; - } - - Wolf wolf = (Wolf) event.getEntity(); - - if(wolf.getHealth() <= event.getDamage()) { - event.setCancelled(true); - event.setDamage(0); - - java.util.UUID ownerUUID = (wolf.getOwner() != null) ? wolf.getOwner().getUniqueId() : null; - - if(ownerUUID != null) { - Player playerOwner = plugin.getServer().getPlayer(ownerUUID); - - if(playerOwner != null) - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_DEATH").asKey().player(playerOwner).sendPlayer(); - } - - arena.removeWolf(wolf); - } - return; - default: - return; - } - } - } - - @EventHandler - public void onDieEntity(EntityDeathEvent event) { + public void onVillagerDeath(EntityDeathEvent event) { LivingEntity entity = event.getEntity(); - if(!(entity instanceof Creature)) { + if (!(entity instanceof Creature)) { return; } - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(event.getEntityType() == EntityType.VILLAGER) { - if(!arena.getVillagers().contains(entity)) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (event.getEntityType() == EntityType.VILLAGER) { + if (!arena.getVillagers().contains(entity)) { continue; } arena.getStartLocation().getWorld().strikeLightningEffect(entity.getLocation()); @@ -192,37 +336,20 @@ public void onDieEntity(EntityDeathEvent event) { plugin.getRewardsHandler().performReward(null, arena, plugin.getRewardsHandler().getRewardType("VILLAGER_DEATH")); plugin.getHolidayManager().applyHolidayDeathEffects(entity); new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_DIED").asKey().arena(arena).sendArena(); - } else { - if(!arena.getEnemies().contains(entity)) { - continue; - } - arena.removeEnemy((Creature) entity); - arena.changeArenaOptionBy("TOTAL_KILLED_ZOMBIES", 1); - - Player killer = entity.getKiller(); - Arena killerArena = plugin.getArenaRegistry().getArena(killer); - - if(killerArena != null) { - plugin.getUserManager().addStat(killer, plugin.getStatsStorage().getStatisticType("KILLS")); - plugin.getUserManager().addExperience(killer, 2 * arena.getArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER")); - plugin.getRewardsHandler().performReward(killer, plugin.getRewardsHandler().getRewardType("ZOMBIE_KILL")); - plugin.getPowerupRegistry().spawnPowerup(entity.getLocation(), killerArena); - } } - break; } } @EventHandler(priority = EventPriority.HIGH) public void onPlayerDie(PlayerDeathEvent e) { Arena arena = plugin.getArenaRegistry().getArena(e.getEntity()); - if(arena == null) { + if (arena == null) { return; } final Player player = e.getEntity(); - if(player.isDead()) { + if (player.isDead()) { player.setHealth(VersionUtils.getMaxHealth(player)); } plugin.getRewardsHandler().performReward(player, arena, plugin.getRewardsHandler().getRewardType("PLAYER_DEATH")); @@ -230,14 +357,14 @@ public void onPlayerDie(PlayerDeathEvent e) { e.getDrops().clear(); e.setDroppedExp(0); plugin.getHolidayManager().applyHolidayDeathEffects(player); - player.spigot().respawn(); + Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> player.spigot().respawn(), 1); plugin.getServer().getScheduler().runTask(plugin, () -> { - if(arena.getArenaState() == ArenaState.STARTING) { + if (arena.getArenaState() == ArenaState.STARTING) { VersionUtils.teleport(player, arena.getStartLocation()); return; } - if(arena.getArenaState() == ArenaState.ENDING || arena.getArenaState() == ArenaState.RESTARTING) { + if (arena.getArenaState() == ArenaState.ENDING || arena.getArenaState() == ArenaState.RESTARTING) { player.getInventory().clear(); player.setFlying(false); player.setAllowFlight(false); @@ -253,7 +380,8 @@ public void onPlayerDie(PlayerDeathEvent e) { user.setSpectator(true); player.setGameMode(GameMode.SURVIVAL); - modifyUserOrbs(user); + //VD Gold - lose only 40% of orbs on death + user.setStatistic("ORBS", (int) (user.getStatistic("ORBS") * 0.6)); ArenaUtils.hidePlayer(player, arena); player.setAllowFlight(true); @@ -265,7 +393,7 @@ public void onPlayerDie(PlayerDeathEvent e) { plugin.getSpecialItemManager().addSpecialItemsOfStage(player, SpecialItem.DisplayStage.SPECTATOR); - arena.getCreatureTargetManager().unTargetPlayerFromZombies(player, arena); + NewCreatureUtils.unTargetPlayerFromZombies(player, arena); }); } @@ -273,12 +401,12 @@ private void sendSpectatorActionBar(User user, Arena arena) { new BukkitRunnable() { @Override public void run() { - if(arena.getArenaState() == ArenaState.ENDING || !user.isSpectator()) { + if (arena.getArenaState() == ArenaState.ENDING || !user.isSpectator()) { cancel(); return; } Player player = user.getPlayer(); - if(player == null) { + if (player == null) { cancel(); } else { VersionUtils.sendActionBar(player, new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_RESPAWN_ON_NEXT").asKey().player(player).arena(arena).build()); @@ -291,63 +419,33 @@ public void run() { @EventHandler(priority = EventPriority.HIGHEST) public void onRespawn(PlayerRespawnEvent e) { Arena arena = plugin.getArenaRegistry().getArena(e.getPlayer()); - if(arena == null) { + if (arena == null) { return; } Player player = e.getPlayer(); player.setAllowFlight(true); player.setFlying(true); User user = plugin.getUserManager().getUser(player); - if(!user.isSpectator()) { + if (!user.isSpectator()) { user.setSpectator(true); player.setGameMode(GameMode.SURVIVAL); player.removePotionEffect(PotionEffectType.NIGHT_VISION); player.removePotionEffect(PotionEffectType.SPEED); - - modifyUserOrbs(user); } e.setRespawnLocation(arena.getStartLocation()); } - private void modifyUserOrbs(User user) { - int deathValue = plugin.getConfig().getInt("Orbs.Death.Value", 50); - int current = user.getStatistic("ORBS"); - switch(getOrbDeathType()) { - case KEEP: - return; - case AMOUNT: - user.setStatistic("ORBS", (Math.max(current + deathValue, 0))); - break; - case SET: - user.setStatistic("ORBS", deathValue); - break; - case PERCENTAGE: - user.setStatistic("ORBS", current * (deathValue / 100)); - break; - default: - break; - } - } - - private OrbDeathType getOrbDeathType() { - return OrbDeathType.valueOf(plugin.getConfig().getString("Orbs.Death.Type", "KEEP")); - } - - private enum OrbDeathType { - PERCENTAGE, AMOUNT, SET, KEEP - } - @EventHandler public void onPickup(PlugilyEntityPickupItemEvent e) { - if(e.getEntity().getType() != EntityType.PLAYER || e.getItem().getItemStack().getType() != Material.ROTTEN_FLESH) { + if (e.getEntity().getType() != EntityType.PLAYER || e.getItem().getItemStack().getType() != Material.ROTTEN_FLESH) { return; } Player player = (Player) e.getEntity(); Arena arena = plugin.getArenaRegistry().getArena(player); - if(arena == null) { + if (arena == null) { return; } - if(plugin.getUserManager().getUser(player).isSpectator()) { + if (plugin.getUserManager().getUser(player).isSpectator()) { e.setCancelled(true); } arena.removeDroppedFlesh(e.getItem()); diff --git a/src/main/java/plugily/projects/villagedefense/arena/ArenaManager.java b/src/main/java/plugily/projects/villagedefense/arena/ArenaManager.java index afd40fff2..4db3fd808 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/ArenaManager.java +++ b/src/main/java/plugily/projects/villagedefense/arena/ArenaManager.java @@ -1,26 +1,37 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Creature; import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Mob; import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Wolf; +import org.bukkit.metadata.FixedMetadataValue; import org.jetbrains.annotations.NotNull; import plugily.projects.minigamesbox.classic.arena.PluginArena; import plugily.projects.minigamesbox.classic.arena.PluginArenaManager; @@ -28,10 +39,29 @@ import plugily.projects.minigamesbox.classic.handlers.language.TitleBuilder; import plugily.projects.minigamesbox.classic.user.User; import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; import plugily.projects.villagedefense.Main; import plugily.projects.villagedefense.api.event.wave.VillageWaveEndEvent; import plugily.projects.villagedefense.api.event.wave.VillageWaveStartEvent; -import plugily.projects.villagedefense.kits.level.GolemFriendKit; +import plugily.projects.villagedefense.arena.assist.AssistHandler; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.midwave.MidWaveEvent; +import plugily.projects.villagedefense.arena.midwave.PinataZombieEvent; +import plugily.projects.villagedefense.arena.midwave.RottenOfferEvent; +import plugily.projects.villagedefense.arena.midwave.ShopOfferEvent; +import plugily.projects.villagedefense.arena.midwave.TipEvent; +import plugily.projects.villagedefense.arena.record.RecordsManager; +import plugily.projects.villagedefense.handlers.upgrade.EntityUpgrade; +import plugily.projects.villagedefense.kits.terminator.TerminatorAugment; +import plugily.projects.villagedefense.kits.terminator.TerminatorAugmentRegistry; +import plugily.projects.villagedefense.utils.avatars.AvatarCreator; +import plugily.projects.villagedefense.utils.avatars.AvatarSize; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; /** * @author Plajer @@ -40,50 +70,136 @@ */ public class ArenaManager extends PluginArenaManager { + public static final int DEFAULT_VILLAGER_HEAL_POWER = 2; + public static final int DEFAULT_PET_HEAL_POWER = 3; + private final Main plugin; + private final List midWaveEvents = new ArrayList<>(); + private final RecordsManager recordsManager; public ArenaManager(Main plugin) { super(plugin); this.plugin = plugin; + this.midWaveEvents.add(new ShopOfferEvent(plugin)); + this.midWaveEvents.add(new RottenOfferEvent(plugin)); + this.midWaveEvents.add(new PinataZombieEvent(plugin)); + this.midWaveEvents.add(new TipEvent()); + this.recordsManager = new RecordsManager(plugin); } @Override public void additionalSpectatorSettings(Player player, PluginArena arena) { super.additionalSpectatorSettings(player, arena); - if(!plugin.getConfigPreferences().getOption("RESPAWN_IN_GAME_JOIN")) { + if (!plugin.getConfigPreferences().getOption("RESPAWN_IN_GAME_JOIN")) { plugin.getUserManager().getUser(player).setPermanentSpectator(true); } } @Override public void leaveAttempt(@NotNull Player player, @NotNull PluginArena arena) { - if(plugin.getUserManager().getUser(player).getKit() instanceof GolemFriendKit) { - ((Arena) arena).getIronGolems().stream().filter(ironGolem -> ironGolem.getCustomName().contains(player.getName())) - .forEach(IronGolem::remove); + player.removeMetadata(AssistHandler.ASSIST_CONTAINER_METADATA, plugin); + Arena gameArena = (Arena) arena; + List pets = new ArrayList<>(); + pets.addAll(gameArena.getIronGolems()); + pets.addAll(gameArena.getWolves()); + pets + .stream() + .filter(Objects::nonNull) + .filter(pet -> pet.hasMetadata("VD_OWNER_UUID")) + .filter(pet -> UUID.fromString(pet.getMetadata("VD_OWNER_UUID").get(0).asString()).equals(player.getUniqueId())) + .forEach(pet -> { + if (pet instanceof IronGolem) { + gameArena.removeIronGolem((IronGolem) pet); + } else { + gameArena.removeWolf((Wolf) pet); + } + }); + //cleanup every metadata that could be left from any kit + for (TerminatorAugment augment : TerminatorAugmentRegistry.getAugments()) { + player.removeMetadata(augment.getMetadataKey(), plugin); } + player.removeMetadata(TerminatorAugment.METADATA_KEY + "STEADY_SCALING_COUNT", plugin); + player.removeMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY, plugin); super.leaveAttempt(player, arena); } @Override public void stopGame(boolean quickStop, @NotNull PluginArena arena) { int wave = ((Arena) arena).getWave(); - for(Player player : arena.getPlayers()) { + AvatarCreator avatarCreator = new AvatarCreator(); + TextComponent playerCountSummary = Component.text(" "); + for (Player player : arena.getPlayers()) { + User user = plugin.getUserManager().getUser(player); + playerCountSummary = playerCountSummary.append(Component.textOfChildren(avatarCreator.getHead(player.getUniqueId(), AvatarSize.SMALL))) + .append(Component.text(" ")) + .append(player.displayName().color(NamedTextColor.GRAY)) + .append(Component.text(" (").color(NamedTextColor.GRAY)) + .append(Component.text(user.getKit().getName())) + .append(Component.text(") ").color(NamedTextColor.GRAY)); + } + for (Player player : arena.getPlayers()) { User user = plugin.getUserManager().getUser(player); - if(!quickStop) { - if(user.getStatistic("HIGHEST_WAVE") <= wave) { - if(user.isSpectator() && !plugin.getConfigPreferences().getOption("RESPAWN_AFTER_WAVE")) { + if (!quickStop) { + if (user.getStatistic("HIGHEST_WAVE") <= wave) { + if (user.isSpectator() && !plugin.getConfigPreferences().getOption("RESPAWN_AFTER_WAVE")) { continue; } user.setStatistic("HIGHEST_WAVE", wave); } - if(plugin.getConfigPreferences().getOption("LIMIT_WAVE_UNLIMITED") && wave >= plugin.getConfig().getInt("Limit.Wave.Game-End", 25)) { + recordsManager.registerAndAnnounceRecord(player, (Arena) arena); + if (wave == 50) { plugin.getUserManager().addStat(user, plugin.getStatsStorage().getStatisticType("WINS")); + XSound.UI_TOAST_CHALLENGE_COMPLETE.play(player, 1, 1.5f); + for (int i = 0; i < 5; i++) { + Bukkit.getScheduler().runTaskLater(plugin, () -> XSound.ENTITY_VILLAGER_YES.play(player), 10 * (i * 2)); + } + XSound.ENTITY_VILLAGER_YES.play(player); } else { plugin.getUserManager().addStat(user, plugin.getStatsStorage().getStatisticType("LOSES")); + XSound.ENTITY_VILLAGER_NO.play(player); } plugin.getUserManager().addExperience(player, wave); + + for (String msg : plugin.getLanguageConfig().getStringList("In-Game.Messages.Game-End.Summary")) { + TextComponent component; + if (msg.contains("{player_count_summary}")) { + component = playerCountSummary; + } else { + component = (TextComponent) Component.text(new MessageBuilder(msg).player(player).arena(arena).build()) + .replaceText( + TextReplacementConfig.builder() + .match("%zombies_killed_record%") + .replacement( + Component.textOfChildren(avatarCreator.getHead(player.getUniqueId(), AvatarSize.SMALL)) + .append(Component.text(" ")) + .append(player.displayName().color(NamedTextColor.GRAY)) + .append(Component.text(" 0")) + ).build() + ).replaceText( + TextReplacementConfig.builder() + .match("%coins_spent_record%") + .replacement( + Component.textOfChildren(avatarCreator.getHead(player.getUniqueId(), AvatarSize.SMALL)) + .append(Component.text(" ")) + .append(player.displayName().color(NamedTextColor.GRAY)) + .append(Component.text(" 0")) + ).build() + ); + } + player.sendMessage(component); + } } } + List allEntities = new ArrayList<>(); + Arena gameArena = ((Arena) arena); + allEntities.addAll(gameArena.getEnemies()); + allEntities.addAll(gameArena.getIronGolems()); + allEntities.addAll(gameArena.getWolves()); + allEntities.addAll(gameArena.getVillagers()); + for (LivingEntity entity : allEntities) { + entity.setAI(false); + entity.setSilent(true); + } super.stopGame(quickStop, arena); } @@ -97,52 +213,185 @@ public void stopGame(boolean quickStop, @NotNull PluginArena arena) { public void endWave(@NotNull Arena arena) { int wave = arena.getWave(); - if(plugin.getConfigPreferences().getOption("LIMIT_WAVE_UNLIMITED") && wave >= plugin.getConfig().getInt("Limit.Wave.Game-End", 25)) { + if (wave >= 51) { stopGame(false, arena); return; } new TitleBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_END").asKey().arena(arena).integer(wave).sendArena(); - for(User user : plugin.getUserManager().getUsers(arena)) { - if(!user.isSpectator() && !user.isPermanentSpectator()) { + for (User user : plugin.getUserManager().getUsers(arena)) { + if (!user.isSpectator() && !user.isPermanentSpectator()) { Player player = user.getPlayer(); plugin.getRewardsHandler().performReward(player, arena, plugin.getRewardsHandler().getRewardType("END_WAVE")); + user.getKit().reStock(player); } + XSound.ENTITY_VILLAGER_YES.play(user.getPlayer()); } arena.setTimer(plugin.getConfig().getInt("Time-Manager.Cooldown-Before-Next-Wave", 25)); - arena.getEnemySpawnManager().getEnemyCheckerLocations().clear(); + arena.getNewEnemySpawnerManager().doResetSpawnCheck(); arena.setWave(wave + 1); Bukkit.getPluginManager().callEvent(new VillageWaveEndEvent(arena, arena.getWave())); refreshAllPlayers(arena); + refreshAllies(arena); + removeAllAssists(arena); + arena.getVillagerAiManager().doSocializeVillagers(); - if(plugin.getConfigPreferences().getOption("RESPAWN_AFTER_WAVE")) { + if (plugin.getConfigPreferences().getOption("RESPAWN_AFTER_WAVE")) { ArenaUtils.bringDeathPlayersBack(arena); } - for(Player player : arena.getPlayersLeft()) { + for (Player player : arena.getPlayersLeft()) { plugin.getUserManager().addExperience(player, 5); } + + doCheckNewShopOffers(arena); + doApplySecretUpgrades(arena); + prepareMidWaveEvent(arena); + doRetreatPets(arena); + arena.removeMetadata(ArenaMetadata.LAST_POWERUP_DROP_MILLIS); + arena.removeMetadata(ArenaMetadata.POWERUPS_WAVE_COUNT); + } + + private void doCheckNewShopOffers(Arena arena) { + if (!arena.getShopManager().getNewOffersAtWaves().contains(arena.getWave())) { + return; + } + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_NEW_OFFERS_AVAILABLE").asKey().arena(arena).sendArena(); + } + + private void prepareMidWaveEvent(Arena arena) { + for (MidWaveEvent event : midWaveEvents) { + //70% chance to attempt to trigger + if (ThreadLocalRandom.current().nextInt(0, 100) >= 30) { + if (!event.canTrigger(arena)) { + continue; + } + event.initiate(arena); + arena.setMidWaveEvent(event); + return; + } + } + } + + private void doRetreatPets(Arena arena) { + List toMove = arena.getIronGolems(); + //repeated calls so mobs don't lose focus randomly + for (int i = 0; i < 5; i++) { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + for (Mob mob : toMove) { + mob.getPathfinder().moveTo(arena.getStartLocation(), 1.25); + } + }, i * 20); + } + for (Wolf wolf : arena.getWolves()) { + wolf.setMetadata("VD_TELEPORT_OVERRIDE_TEMP", new FixedMetadataValue(plugin, true)); + wolf.teleport(arena.getStartLocation()); + wolf.removeMetadata("VD_TELEPORT_OVERRIDE_TEMP", plugin); + } + } + + private void doApplySecretUpgrades(Arena arena) { + List toUpgrade = new ArrayList<>(); + toUpgrade.addAll(arena.getWolves()); + toUpgrade.addAll(arena.getIronGolems()); + for (LivingEntity livingEntity : toUpgrade) { + if (!livingEntity.hasMetadata("VD_ALIVE_SINCE_WAVE")) { + continue; + } + int wave = livingEntity.getMetadata("VD_ALIVE_SINCE_WAVE").get(0).asInt(); + int aliveWaves = arena.getWave() - wave; + for (EntityUpgrade upgrade : plugin.getEntityUpgradeManager().getRegisteredUpgrades()) { + if (!upgrade.isHidden()) { + continue; + } + if (aliveWaves == upgrade.getSurviveWaves()) { + if (livingEntity.hasMetadata(upgrade.getMetadataKey())) { + continue; + } + Player player = Bukkit.getPlayer(UUID.fromString(livingEntity.getMetadata("VD_OWNER_UUID").get(0).asString())); + plugin.getEntityUpgradeManager().applyUpgradeWithVisuals(livingEntity, player, upgrade); + } + } + } } private void refreshAllPlayers(Arena arena) { int waveStat = arena.getWave() * 10; - String feelRefreshed = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_FEEL_REFRESHED").asKey().build(); - String formatted = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_NEXT_IN").asKey().arena(arena).integer(arena.getTimer()).build(); - - for(Player player : arena.getPlayers()) { - player.sendMessage(formatted); - player.sendMessage(feelRefreshed); - player.setHealth(VersionUtils.getMaxHealth(player)); + String nextWave = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_NEXT_IN").asKey().arena(arena).integer(arena.getTimer()).build(); + for (Player player : arena.getPlayers()) { + int healPower = (int) Math.ceil(VersionUtils.getMaxHealth(player) * 0.25); //25% of max health rounded up + player.sendMessage(nextWave); + player.setHealth(Math.min(player.getHealth() + healPower, VersionUtils.getMaxHealth(player))); plugin.getUserManager().getUser(player).adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), waveStat); } } + private void refreshAllies(Arena arena) { + int healPower = DEFAULT_VILLAGER_HEAL_POWER; //1 heart + for (Villager villager : arena.getVillagers()) { + villager.setHealth(Math.min(villager.getHealth() + healPower, VersionUtils.getMaxHealth(villager))); + villager.setCustomName(NewCreatureUtils.getHealthNameTag(villager)); + } + healPower = DEFAULT_PET_HEAL_POWER; //1.5 hearts + List pets = new ArrayList<>(); + pets.addAll(arena.getWolves()); + pets.addAll(arena.getIronGolems()); + doReviveDeadPets(pets); + for (LivingEntity pet : pets) { + //double heal for golems + double multiplier = getRefreshBonus(pet); + pet.setHealth(Math.min(pet.getHealth() + (healPower * multiplier), VersionUtils.getMaxHealth(pet))); + if (pet instanceof Wolf) { + pet.setCustomName(NewCreatureUtils.getHealthNameTag((Creature) pet)); + } + } + } + + private void doReviveDeadPets(List pets) { + for (LivingEntity pet : pets) { + if (!pet.hasMetadata("VD_PET_DEAD")) { + continue; + } + pet.setAI(true); + pet.setHealth(pet.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue()); + pet.removeMetadata("VD_PET_DEAD", plugin); + pet.setCustomName(NewCreatureUtils.getHealthNameTag((Creature) pet)); + } + } + + private double getRefreshBonus(LivingEntity livingEntity) { + double defaultHeal = livingEntity instanceof IronGolem ? 2.0 : 1.0; + String prefix = livingEntity instanceof IronGolem ? "GOLEM_" : "WOLF_"; + for (int i = 3; i > 0; i--) { + EntityUpgrade heal = plugin.getEntityUpgradeManager().getUpgrade(prefix + "HEALTH_AND_REGEN_" + i); + if (livingEntity.hasMetadata(heal.getMetadataKey())) { + defaultHeal += heal.getUpgradeData().getOrDefault("regen", 0.0); + break; + } + } + EntityUpgrade willToSurvive = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_SURVIVOR"); + if (livingEntity.hasMetadata(willToSurvive.getMetadataKey())) { + defaultHeal += livingEntity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue() * 0.1; + } + return defaultHeal; + } + + private void removeAllAssists(Arena arena) { + List allEntities = new ArrayList<>(); + allEntities.addAll(arena.getPlayers()); + allEntities.addAll(arena.getWolves()); + allEntities.addAll(arena.getIronGolems()); + for (LivingEntity livingEntity : allEntities) { + livingEntity.removeMetadata(AssistHandler.ASSIST_CONTAINER_METADATA, plugin); + } + } + /** * Starts wave in game. * Calls VillageWaveStartEvent event @@ -158,46 +407,25 @@ public void startWave(@NotNull Arena arena) { Bukkit.getPluginManager().callEvent(new VillageWaveStartEvent(arena, wave)); - int zombiesAmount = (int) Math.ceil((arena.getPlayers().size() * 0.5) * (wave * wave) / 2); - int maxzombies = plugin.getConfig().getInt("Limit.Spawn.Creatures", 75); - - if(zombiesAmount > maxzombies) { - int multiplier = (int) Math.ceil((zombiesAmount - (double) maxzombies) / plugin.getConfig().getInt("Creatures.Multiplier-Divider", 18)); - - if(multiplier < 2) multiplier = 2; - - arena.setArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER", multiplier); - - plugin.getDebugger().debug("[{0}] Detected abnormal wave ({1})! Applying zombie limit and difficulty multiplier to {2} | ZombiesAmount: {3} | MaxZombies: {4}", - arena.getId(), wave, arena.getArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER"), zombiesAmount, maxzombies); - - zombiesAmount = maxzombies; - } - - int zombieIdle = (int) Math.floor((double) wave / 15); - - arena.setArenaOption("ZOMBIES_TO_SPAWN", zombiesAmount); - arena.setArenaOption("ZOMBIE_IDLE_PROCESS", zombieIdle); - - if(zombieIdle > 0) { - plugin.getDebugger().debug("[{0}] Spawn idle process initiated to prevent server overload! Value: {1}", arena.getId(), zombieIdle); - } + arena.setArenaOption("ZOMBIES_TO_SPAWN", arena.getNewEnemySpawnerManager().getEnemiesForWave(wave)); - if(plugin.getConfigPreferences().getOption("RESPAWN_AFTER_WAVE")) { + if (plugin.getConfigPreferences().getOption("RESPAWN_AFTER_WAVE")) { ArenaUtils.bringDeathPlayersBack(arena); } new TitleBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_START").asKey().arena(arena).integer(wave).sendArena(); - for(User user : plugin.getUserManager().getUsers(arena)) { + for (User user : plugin.getUserManager().getUsers(arena)) { Player player = user.getPlayer(); - if(!user.isSpectator()) { - user.getKit().reStock(player); - } plugin.getRewardsHandler().performReward(player, arena, plugin.getRewardsHandler().getRewardType("START_WAVE")); new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_STARTED").asKey().arena(arena).integer(wave).player(player).sendPlayer(); } + if (arena.getMidWaveEvent() != null) { + arena.getMidWaveEvent().cleanup(arena); + arena.setMidWaveEvent(null); + } + arena.getVillagerAiManager().doRetreatVillagers(); plugin.getDebugger().debug("[{0}] Wave start event finished took {1}ms", arena.getId(), System.currentTimeMillis() - start); } diff --git a/src/main/java/plugily/projects/villagedefense/arena/ArenaMetadata.java b/src/main/java/plugily/projects/villagedefense/arena/ArenaMetadata.java new file mode 100644 index 000000000..22a144976 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/ArenaMetadata.java @@ -0,0 +1,26 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena; + +public class ArenaMetadata { + + public static final String POWERUPS_WAVE_COUNT = "POWERUPS_WAVE_COUNT"; + public static final String LAST_POWERUP_DROP_MILLIS = "POWERUPS_LAST_DROP_TIME"; + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/ArenaRegistry.java b/src/main/java/plugily/projects/villagedefense/arena/ArenaRegistry.java index 09b053663..8b30485b1 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/ArenaRegistry.java +++ b/src/main/java/plugily/projects/villagedefense/arena/ArenaRegistry.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena; @@ -28,6 +28,7 @@ import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; import plugily.projects.minigamesbox.classic.utils.serialization.LocationSerializer; import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; import java.util.ArrayList; import java.util.List; @@ -80,20 +81,31 @@ public boolean additionalValidatorChecks(ConfigurationSection section, PluginAre } } - ConfigurationSection doorSection = section.getConfigurationSection(id + ".doors"); - if(doorSection != null) { - for(String string : doorSection.getKeys(false)) { - ((Arena) arena).getMapRestorerManager().addDoor(LocationSerializer.getLocation(doorSection.getString(string + ".location")), - (byte) doorSection.getInt(string + ".byte")); - } + List doorSection = section.getStringList(id + ".doors"); + for(String location : doorSection) { + ((Arena) arena).getMapRestorerManager().addDoor(LocationSerializer.getLocation(location)); } if(arena.getStartLocation().getWorld().getDifficulty() == Difficulty.PEACEFUL) { plugin.getDebugger().sendConsoleMsg(new MessageBuilder("VALIDATOR_INVALID_ARENA_CONFIGURATION").asKey().value("THERE IS A WRONG " + - "DIFFICULTY -> SET IT TO ANOTHER ONE THAN PEACEFUL - WE SET IT TO EASY").arena(arena).build()); + "DIFFICULTY -> SET IT TO ANOTHER ONE THAN PEACEFUL - WE SET IT TO EASY").arena(arena).build()); arena.getStartLocation().getWorld().setDifficulty(Difficulty.EASY); } + + for (String location : section.getStringList(id + ".villager-ai.socialZones")) { + ((Arena) arena).getVillagerAiManager().registerArenaPlace(VillagerAiManager.Place.VILLAGER_SOCIAL_ZONE, LocationSerializer.getLocation(location)); + } + for (String location : section.getStringList(id + ".villager-ai.homeZones")) { + ((Arena) arena).getVillagerAiManager().registerArenaPlace(VillagerAiManager.Place.VILLAGER_HOME_ZONE, LocationSerializer.getLocation(location)); + } + //todo + /*for(String location : section.getStringList(id + ".villager-ai.escapeZones")) { + ((Arena) arena).getVillagerAiManager().registerArenaPlace(VillagerAiManager.Place.VILLAGER_ESCAPE_ZONE, LocationSerializer.getLocation(location)); + }*/ + for (String location : section.getStringList(id + ".villager-ai.fishingZones")) { + ((Arena) arena).getVillagerAiManager().registerArenaPlace(VillagerAiManager.Place.VILLAGER_FISHING_ZONE, LocationSerializer.getLocation(location)); + } return true; } @@ -124,4 +136,5 @@ public boolean additionalValidatorChecks(ConfigurationSection section, PluginAre } return arenas; } + } diff --git a/src/main/java/plugily/projects/villagedefense/arena/assist/AssistContainer.java b/src/main/java/plugily/projects/villagedefense/arena/assist/AssistContainer.java new file mode 100644 index 000000000..b461116e5 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/assist/AssistContainer.java @@ -0,0 +1,173 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.assist; + +import org.bukkit.entity.LivingEntity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.StringJoiner; +import java.util.UUID; + +/** + * Metadata container that includes every player + * that assisted in killing an enemy and their + * kill participation (damage/buffing the killer/other) + *

+ * While assists for enemies are always counted, + * assists for players are only counted if time_millis parameter + * is no more than 10 seconds from actual time. + *

+ * Data is stored in the following way: + * uuid,assist_type,value,time_millis|uuid,assist_type,value,time_millis + * + * @author Plajer + *

+ * Created at 29.08.2023 + */ +public class AssistContainer { + + private final List data; + + public AssistContainer() { + this.data = new ArrayList<>(); + } + + public AssistContainer(List data) { + this.data = data; + } + + public static AssistContainer deserialize(String text) { + if(text.isBlank()) { + return new AssistContainer(new ArrayList<>()); + } + List assistData = new ArrayList<>(); + String[] serialized = text.split("\\|"); + for(String assistSerialized : serialized) { + String[] values = assistSerialized.split(","); + assistData.add(new AssistData(UUID.fromString(values[0]), AssistData.AssistType.valueOf(values[1].toUpperCase()), + Double.parseDouble(values[2]), Long.parseLong(values[3]))); + } + return new AssistContainer(assistData); + } + + public List getData() { + return data; + } + + public void updateAssist(LivingEntity entity, AssistData.AssistType type) { + updateAssist(entity, type, 0); + } + + public void updateAssist(LivingEntity entity, AssistData.AssistType type, double value) { + Optional optional = data.stream().filter(a -> a.getUuid().equals(entity.getUniqueId())).findFirst(); + if(optional.isEmpty()) { + data.add(new AssistData(entity.getUniqueId(), type, value, System.currentTimeMillis())); + return; + } + AssistData assistData = optional.get(); + //damage has the highest assist reward, override if any damage is given + if(assistData.getType() != type && type == AssistData.AssistType.DAMAGE) { + assistData.setType(type); + assistData.setValue(value); + assistData.setTimeMillis(System.currentTimeMillis()); + return; + } + //on damage, increase total value of assist + if(type == AssistData.AssistType.DAMAGE) { + assistData.setValue(assistData.getValue() + value); + } + //update time for any type of assist be it buff or damage + assistData.setTimeMillis(System.currentTimeMillis()); + } + + public String serialize() { + StringJoiner joiner = new StringJoiner("|"); + for(AssistData assistData : data) { + joiner.add(assistData.toString()); + } + return joiner.toString(); + } + + public static class AssistData { + + private final UUID uuid; + private AssistType type; + private double value; + private long timeMillis; + + public AssistData(UUID uuid, AssistType type, double value, long timeMillis) { + this.uuid = uuid; + this.type = type; + this.value = value; + this.timeMillis = timeMillis; + } + + public UUID getUuid() { + return uuid; + } + + public AssistType getType() { + return type; + } + + public void setType(AssistType type) { + this.type = type; + } + + public double getValue() { + return value; + } + + public void setValue(double value) { + this.value = value; + } + + public long getTimeMillis() { + return timeMillis; + } + + public void setTimeMillis(long timeMillis) { + this.timeMillis = timeMillis; + } + + @Override + public String toString() { + return uuid.toString() + "," + type.name() + "," + value + "," + timeMillis; + } + + public enum AssistType { + /** + * Assisting ally did damage to killed enemy + */ + DAMAGE, + /** + * Assisting ally did buff ally that killed the enemy + */ + BUFF, + /** + * Assisting ally did debuff enemy that was killed by ally + */ + DEBUFF + } + + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/assist/AssistHandler.java b/src/main/java/plugily/projects/villagedefense/arena/assist/AssistHandler.java new file mode 100644 index 000000000..41aba3a8b --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/assist/AssistHandler.java @@ -0,0 +1,211 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.assist; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.metadata.FixedMetadataValue; +import plugily.projects.villagedefense.Main; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Class dedicated to handle metadata for players who buff + * or help their allies in any other way. + * This class is a middleman between sharing orbs on enemy death + * both for the killer and all assisting players (including + * allies that buffed the killer) + * + * @author Plajer + *

+ * Created at 29.08.2023 + */ +public class AssistHandler { + + public static final String ASSIST_CONTAINER_METADATA = "VD_ASSIST_CONTAINER"; + private Main plugin; + + public AssistHandler(Main plugin) { + this.plugin = plugin; + } + + public void doRegisterDamageOnEnemy(LivingEntity source, Creature target, double damage) { + AssistContainer container = new AssistContainer(); + if(target.hasMetadata(ASSIST_CONTAINER_METADATA)) { + container = AssistContainer.deserialize(target.getMetadata(ASSIST_CONTAINER_METADATA).get(0).asString()); + } + container.updateAssist(source, AssistContainer.AssistData.AssistType.DAMAGE, damage); + target.setMetadata(ASSIST_CONTAINER_METADATA, new FixedMetadataValue(plugin, container.serialize())); + } + + public void doRegisterDebuffOnEnemy(LivingEntity source, Creature target) { + AssistContainer container = new AssistContainer(); + if(target.hasMetadata(ASSIST_CONTAINER_METADATA)) { + container = AssistContainer.deserialize(target.getMetadata(ASSIST_CONTAINER_METADATA).get(0).asString()); + } + container.updateAssist(source, AssistContainer.AssistData.AssistType.DEBUFF); + target.setMetadata(ASSIST_CONTAINER_METADATA, new FixedMetadataValue(plugin, container.serialize())); + } + + public void doRegisterBuffOnAlly(LivingEntity source, LivingEntity target) { + AssistContainer container = new AssistContainer(); + if(target.hasMetadata(ASSIST_CONTAINER_METADATA)) { + container = AssistContainer.deserialize(target.getMetadata(ASSIST_CONTAINER_METADATA).get(0).asString()); + } + container.updateAssist(source, AssistContainer.AssistData.AssistType.BUFF); + target.setMetadata(ASSIST_CONTAINER_METADATA, new FixedMetadataValue(plugin, container.serialize())); + } + + /** + * Distribute orb from killed enemy to all people that assisted the killer. + * Distribution map is a map of player and their percentage contribution. + *

+ * If killer is a pet, owner will receive 100% of kill participation + * unless the pet was assisted by any other ally. + *

+ * If killer is a player, player will receive 100% of kill participation + * unless they were assisted by any other ally. + *

+ * Moreover, deadEnemy is checked for any debuffs it received as well + * so assist is split between people that applied debuffs as well. + * + * @param killer the entity that killed deadEnemy + * @param deadEnemy enemy that died in the event + * @return map of percentage distribution of orbs given by deadEnemy + */ + public Map doDistributeAssistRewards(LivingEntity killer, Creature deadEnemy) { + Player killerOwner = getRealKiller(killer); + if(killerOwner == null) { + plugin.getDebugger().debug("No owner of " + killer.getType() + " found, cannot distribute orb assists."); + return new HashMap<>(); + } + Map damageDone = new LinkedHashMap<>(); + List otherAssists = new ArrayList<>(); + //enemy was debuffed or attacked by someone, check it + if(deadEnemy.hasMetadata(ASSIST_CONTAINER_METADATA)) { + AssistContainer debuffers = AssistContainer.deserialize(deadEnemy.getMetadata(ASSIST_CONTAINER_METADATA).get(0).asString()); + List assistData = debuffers.getData(); + for(AssistContainer.AssistData data : assistData) { + Player assister = getAssisterByUuid(data.getUuid()); + if(assister == null || assister.equals(killerOwner)) { + continue; + } + //only count indirect (debuffs) or damage to the enemy + switch(data.getType()) { + case DAMAGE: + Entity entity = Bukkit.getEntity(data.getUuid()); + damageDone.put(assister, data.getValue()); + break; + case DEBUFF: + otherAssists.add(assister); + break; + } + } + } + //check if killer (either pet or player) has any assist buffs + if(killer.hasMetadata(ASSIST_CONTAINER_METADATA)) { + AssistContainer assisters = AssistContainer.deserialize(killer.getMetadata(ASSIST_CONTAINER_METADATA).get(0).asString()); + List assistData = assisters.getData(); + for(AssistContainer.AssistData data : assistData) { + Player assister = getAssisterByUuid(data.getUuid()); + if(assister == null || data.getType() != AssistContainer.AssistData.AssistType.BUFF) { + continue; + } + //only count buffs (within 10 seconds) to the killer + if(System.currentTimeMillis() - data.getTimeMillis() <= 10000) { + otherAssists.add(assister); + } + } + } + return doDistributeMap(killerOwner, damageDone, otherAssists); + } + + //aims to get owner of the wolf/golem or player if applicable + private Player getRealKiller(LivingEntity killer) { + Player realKiller = null; + if(killer instanceof Player) { + realKiller = (Player) killer; + } else if(killer instanceof Wolf || killer instanceof IronGolem && killer.hasMetadata("VD_OWNER_UUID")) { + realKiller = Bukkit.getPlayer(UUID.fromString(killer.getMetadata("VD_OWNER_UUID").get(0).asString())); + } + return realKiller; + } + + //aims to get the owner of the assisting wolf/golem or player if applicable + private Player getAssisterByUuid(UUID uuid) { + Entity entity = Bukkit.getEntity(uuid); + if(entity == null) { + return null; + } + if(entity instanceof Player) { + return (Player) entity; + } + if(!entity.hasMetadata("VD_OWNER_UUID")) { + return null; + } + return Bukkit.getPlayer(UUID.fromString(entity.getMetadata("VD_OWNER_UUID").get(0).asString())); + } + + //50% / 50% split between killer and assisters + //and 50% split based on damage contribution (weighted) + //and 50% split based on other assists (split evenly) + private Map doDistributeMap(Player killer, Map damage, List otherAssists) { + double total = 100.0; + Map shares = new HashMap<>(); + double killerShare = 50.0; + if(damage.isEmpty() && otherAssists.isEmpty()) { + killerShare = 100.0; + } + shares.put(killer, killerShare); + double totalDamageShare = 0.0; + for(Map.Entry entry : damage.entrySet()) { + double damageDealt = 1.0; + if(entry.getValue() > 0) { + damageDealt = entry.getValue(); + } + totalDamageShare += damageDealt; + } + double assistSplit = 0.5; + //if either is empty then assist should be shared 50/50 not 50/(25/25) + if(damage.isEmpty() || otherAssists.isEmpty()) { + assistSplit = 1.0; + } + for(Map.Entry entry : damage.entrySet()) { + double damageShare = (entry.getValue() / totalDamageShare) * assistSplit * (total - killerShare); + shares.put(entry.getKey(), damageShare); + } + + double otherAssistsShare = assistSplit * (total - killerShare); + for(Player player : otherAssists) { + shares.put(player, otherAssistsShare / otherAssists.size()); + } + return shares; + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/CreatureTargetManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/CreatureTargetManager.java deleted file mode 100644 index 892bb95d3..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/CreatureTargetManager.java +++ /dev/null @@ -1,177 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers; - -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.metadata.MetadataValue; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.EnemySpawner; -import plugily.projects.villagedefense.creatures.v1_9_UP.CustomCreature; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Random; - -/** - * @author Tigerpanzer_02 - *

- * Created at 22.01.2022 - */ -public class CreatureTargetManager { - private final Arena arena; - private final Main plugin; - - public CreatureTargetManager(Arena arena) { - this.arena = arena; - this.plugin = arena.getPlugin(); - } - - public void targetCreatures() { - for(Creature creature : arena.getEnemies()) { - LivingEntity creatureTarget = creature.getTarget(); - if(creatureTarget == null) { - setTarget(creature); - continue; - } - if(creatureTarget.getLocation().distance(creature.getLocation()) > 10 && creatureTarget instanceof Player) { - setTarget(creature); - } - } - } - - public void targetRideableCreatures() { - List creatures = new ArrayList<>(); - creatures.addAll(arena.getWolves()); - creatures.addAll(arena.getIronGolems()); - for(Creature creature : creatures) { - if(arena.getEnemies().isEmpty() || !arena.isFighting()) { - return; - } - LivingEntity creatureTarget = creature.getTarget(); - if(creatureTarget == null) { - creature.setTarget(arena.getEnemies().get(arena.getEnemies().size() > 1 ? plugin.getRandom().nextInt(arena.getEnemies().size() - 1) : 0)); - continue; - } - if(creatureTarget instanceof Player) { - creature.setTarget(arena.getEnemies().get(arena.getEnemies().size() > 1 ? plugin.getRandom().nextInt(arena.getEnemies().size() - 1) : 0)); - } - } - } - - private void setTarget(Creature creature) { - LivingEntity nearestEntity = getNearestEntity(creature); - if(nearestEntity == null) { - return; - } - creature.setTarget(nearestEntity); - plugin.getDebugger().debug("Arena {0} set Target {1} for Entity at Location {2}", arena.getId(), nearestEntity.getType(), creature.getLocation().toString()); - } - - public void unTargetCreature(Creature creature) { - creature.setTarget(null); - } - - public CustomCreature getCustomCreatureFromCreature(Creature creature) { - List metadataValueList = creature.getMetadata("PlugilyProjects-VillageDefense-Name"); - if(metadataValueList.isEmpty()) { - plugin.getDebugger().debug("Arena {0} Couldn't find creature meta data", arena.getId()); - return null; - } - for(MetadataValue metadataValue : metadataValueList) { - Optional spawnerByName = plugin.getEnemySpawnerRegistry().getSpawnerByName(metadataValue.asString()); - if(!spawnerByName.isPresent()) { - continue; - } - EnemySpawner enemySpawner = spawnerByName.get(); - if(enemySpawner instanceof CustomCreature) { - return (CustomCreature) enemySpawner; - } - } - plugin.getDebugger().debug("Arena {0} Couldn't find creature spawner", arena.getId()); - return null; - } - - public LivingEntity getNearestEntity(Creature creature) { - - CustomCreature customCreature = getCustomCreatureFromCreature(creature); - if(customCreature == null) { - plugin.getDebugger().debug("Arena {0} found no custom creature to set target", arena.getId()); - return null; - } - - Location location = creature.getLocation(); - - List entities = new ArrayList<>(); - - switch(customCreature.getPriorityTarget()) { - case ANY: - case VILLAGER: - entities.addAll(arena.getVillagers()); - break; - case IRON_GOLEM: - entities.addAll(arena.getIronGolems()); - break; - case WOLF: - entities.addAll(arena.getWolves()); - break; - case PLAYER: - entities.addAll(arena.getPlayersLeft()); - break; - } - if(entities.isEmpty()) { - entities.addAll(arena.getVillagers()); - } - - if(entities.isEmpty()) { - plugin.getDebugger().debug("Arena {0} found no entity to target", arena.getId()); - return null; - } - - Entity nearestEntity = entities.get(0); - - for(Entity entity : entities) { - double distance = location.distance(entity.getLocation()); - if(distance < location.distance(nearestEntity.getLocation())) { - nearestEntity = entity; - } - } - plugin.getDebugger().debug("Arena {0} found at {1} the nearest villager for creature at {2} with distance of {3}", arena.getId(), nearestEntity.getLocation(), creature.getLocation(), location.distance(nearestEntity.getLocation())); - return (LivingEntity) nearestEntity; - } - - public void unTargetPlayerFromZombies(Player player, Arena arena) { - for(Creature zombie : arena.getEnemies()) { - LivingEntity target = zombie.getTarget(); - - if(!player.equals(target)) { - continue; - } - //set new target as villager so zombies won't stay still waiting for nothing - zombie.setTarget(arena.getVillagers().get(plugin.getRandom().nextInt(arena.getVillagers().size() - 1))); - } - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/EnemySpawnManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/EnemySpawnManager.java deleted file mode 100644 index 7442e710c..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/EnemySpawnManager.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Villager; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.villagedefense.arena.Arena; - -/** - * @author Plajer - *

- * Created at 06.01.2019 - */ -public class EnemySpawnManager { - private final Arena arena; - private int localIdleProcess = 0; - private final List glitchedEnemies = new ArrayList<>(); - private final Map enemyCheckerLocations = new HashMap<>(); - - public EnemySpawnManager(Arena arena) { - this.arena = arena; - } - - public void applyIdle(int idle) { - localIdleProcess = idle; - } - - /** - * Increments ZOMBIE_GLITCH_CHECKER value and attempts to check - * whether any enemies are glitched on spawn point when - * ZOMBIE_GLITCH_CHECKER value is higher or equal than 60 - *

- * Glitch checker also clean ups dead enemies and villagers from the arena - */ - public void spawnGlitchCheck() { - arena.changeArenaOptionBy("ZOMBIE_GLITCH_CHECKER", 1); - if(arena.getArenaOption("ZOMBIE_GLITCH_CHECKER") >= 60) { - Iterator villagerIterator = arena.getVillagers().iterator(); - while(villagerIterator.hasNext()) { - Villager villager = villagerIterator.next(); - if(villager.isDead()) { - villagerIterator.remove(); - arena.removeVillager(villager); - } - } - arena.setArenaOption("ZOMBIE_GLITCH_CHECKER", 0); - - Iterator creatureIterator = arena.getEnemies().iterator(); - while(creatureIterator.hasNext()) { - Creature creature = creatureIterator.next(); - if(creature.isDead()) { - creatureIterator.remove(); - arena.removeEnemy(creature); - continue; - } - if(glitchedEnemies.contains(creature) && creature.getLocation().distance(enemyCheckerLocations.get(creature)) <= 1) { - creatureIterator.remove(); - arena.removeEnemy(creature); - enemyCheckerLocations.remove(creature); - creature.remove(); - } - - Location checkerLoc = enemyCheckerLocations.get(creature); - if(checkerLoc == null) { - enemyCheckerLocations.put(creature, creature.getLocation()); - } else if(creature.getLocation().distance(checkerLoc) <= 1) { - VersionUtils.teleport(creature, arena.getRandomZombieSpawnLocation(arena.getPlugin().getRandom())); - enemyCheckerLocations.put(creature, creature.getLocation()); - glitchedEnemies.add(creature); - } - } - } - } - - public Map getEnemyCheckerLocations() { - return enemyCheckerLocations; - } - - /** - * Spawns some enemies in arena. - *

- * Variety and amount of enemies depends - * on random value and current wave - */ - public void spawnEnemies() { - if(checkForIdle()) { - arena.getPlugin().getEnemySpawnerRegistry().spawnEnemies(arena.getPlugin().getRandom(), arena); - } - } - - private boolean checkForIdle() { - //Idling to ~~save server stability~~ protect against hordes of enemies - if(localIdleProcess > 0) { - localIdleProcess--; - return false; - } - - applyIdle(arena.getArenaOption("ZOMBIE_IDLE_PROCESS")); - //continue spawning - return true; - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/ScoreboardManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/ScoreboardManager.java index ba75f8c9d..7ee27df32 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/ScoreboardManager.java +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/ScoreboardManager.java @@ -1,20 +1,20 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena.managers; @@ -27,6 +27,7 @@ import plugily.projects.minigamesbox.classic.utils.scoreboard.common.EntryBuilder; import plugily.projects.minigamesbox.classic.utils.scoreboard.type.Entry; import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.kits.ScoreboardModifiable; import java.util.List; @@ -51,7 +52,11 @@ public List formatScoreboard(User user) { if(user.getArena().getArenaState() == ArenaState.FULL_GAME) { lines = user.getArena().getPlugin().getLanguageManager().getLanguageList("Scoreboard.Content.Starting"); } else if(user.getArena().getArenaState() == ArenaState.IN_GAME) { - lines = user.getArena().getPlugin().getLanguageManager().getLanguageList("Scoreboard.Content." + user.getArena().getArenaState().getFormattedName() + (((Arena) user.getArena()).isFighting() ? "" : "-Waiting")); + if (user.getKit() instanceof ScoreboardModifiable) { + lines = ((ScoreboardModifiable) user.getKit()).getScoreboardLines(user); + } else { + lines = user.getArena().getPlugin().getLanguageManager().getLanguageList("Scoreboard.Content." + user.getArena().getArenaState().getFormattedName() + (((Arena) user.getArena()).isFighting() ? "" : "-Waiting")); + } } else { lines = user.getArena().getPlugin().getLanguageManager().getLanguageList("Scoreboard.Content." + user.getArena().getArenaState().getFormattedName()); } diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/ShopManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/ShopManager.java deleted file mode 100644 index b1e754063..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/ShopManager.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers; - -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Chest; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.NotNull; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.configuration.ConfigUtils; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.serialization.LocationSerializer; -import plugily.projects.minigamesbox.inventory.normal.NormalFastInv; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; - -import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.stream.Collectors; - -/** - * Created by Tom on 16/08/2014. - */ -public class ShopManager { - - private final String defaultGolemItemName; - private final String defaultWolfItemName; - - private final Main plugin; - private final FileConfiguration config; - private final Arena arena; - private NormalFastInv gui; - private Consumer openMenuConsumer; - - public ShopManager(Arena arena) { - plugin = arena.getPlugin(); - config = ConfigUtils.getConfig(plugin, "arenas"); - this.arena = arena; - - defaultGolemItemName = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_GOLEM_ITEM", false).asKey().build(); - defaultWolfItemName = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_WOLF_ITEM", false).asKey().build(); - - if(config.isSet("instances." + arena.getId() + ".shop")) { - registerShop(); - } - openMenuConsumer = player -> { - if(plugin.getArenaRegistry().getArena(player) == null) { - return; - } - if(gui == null) { - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_NOT_DEFINED").asKey().player(player).sendPlayer(); - return; - } - gui.open(player); - }; - } - - public NormalFastInv getShop() { - return gui; - } - - public void setShop(NormalFastInv gui) { - this.gui = gui; - } - - public void setOpenMenuConsumer(@NotNull Consumer openMenuConsumer) { - this.openMenuConsumer = openMenuConsumer; - } - - /** - * Default name of golem spawn item from language.yml - * - * @return the default golem item name - */ - public String getDefaultGolemItemName() { - return defaultGolemItemName; - } - - /** - * Default name of wolf spawn item from language.yml - * - * @return the default wolf item name - */ - public String getDefaultWolfItemName() { - return defaultWolfItemName; - } - - public void openShop(Player player) { - if(openMenuConsumer != null) { - openMenuConsumer.accept(player); - } - } - - private void registerShop() { - if(!validateShop()) { - return; - } - ItemStack[] contents = ((Chest) LocationSerializer.getLocation(config.getString("instances." + arena.getId() + ".shop")) - .getBlock().getState()).getInventory().getContents(); - gui = new NormalFastInv(plugin.getBukkitHelper().serializeInt(contents.length), new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_GUI").asKey().build()); - gui.addClickHandler(inventoryClickEvent -> inventoryClickEvent.setCancelled(true)); - for(int slot = 0; slot < contents.length; slot++) { - ItemStack itemStack = contents[slot]; - if(itemStack == null || itemStack.getType() == Material.REDSTONE_BLOCK) { - continue; - } - - String costString = ""; - ItemMeta meta = itemStack.getItemMeta(); - //seek for item price - if(meta != null && meta.hasLore()) { - for(String s : ComplementAccessor.getComplement().getLore(meta)) { - if(s.contains(new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_CURRENCY").asKey().build()) || s.contains("orbs")) { - costString = ChatColor.stripColor(s).replaceAll("&[0-9a-zA-Z]", "").replaceAll("[^0-9]", ""); - break; - } - } - } - - int cost; - try { - cost = Integer.parseInt(costString); - } catch(NumberFormatException e) { - plugin.getDebugger().debug(Level.WARNING, "No price set for shop item in arena {0} skipping item!", arena.getId()); - continue; - } - - gui.setItem(slot, itemStack, event -> { - Player player = (Player) event.getWhoClicked(); - - if(!arena.getPlayers().contains(player)) { - return; - } - - User user = plugin.getUserManager().getUser(player); - int orbs = user.getStatistic("ORBS"); - - if(cost > orbs) { - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_NOT_ENOUGH_CURRENCY").asKey().player(player).sendPlayer(); - return; - } - - if(ItemUtils.isItemStackNamed(itemStack)) { - String name = ComplementAccessor.getComplement().getDisplayName(itemStack.getItemMeta()); - if(name.contains(new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_GOLEM_ITEM", false).asKey().build()) - || name.contains(defaultGolemItemName)) { - if(!arena.canSpawnMobForPlayer(player, EntityType.IRON_GOLEM)) { - return; - } - arena.spawnGolem(arena.getStartLocation(), player); - adjustOrbs(user, cost); - return; - } - if(name.contains(new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_WOLF_ITEM", false).asKey().build()) - || name.contains(defaultWolfItemName)) { - if(!arena.canSpawnMobForPlayer(player, EntityType.WOLF)) { - return; - } - arena.spawnWolf(arena.getStartLocation(), player); - adjustOrbs(user, cost); - return; - } - } - - ItemStack stack = itemStack.clone(); - ItemMeta itemMeta = stack.getItemMeta(); - - if(itemMeta != null) { - if(itemMeta.hasLore()) { - ComplementAccessor.getComplement().setLore(itemMeta, ComplementAccessor.getComplement().getLore(itemMeta).stream().filter(lore -> - !lore.contains(new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_CURRENCY").asKey().build())) - .collect(Collectors.toList())); - } - - stack.setItemMeta(itemMeta); - } - - player.getInventory().addItem(stack); - adjustOrbs(user, cost); - }); - } - } - - private void adjustOrbs(User user, int cost) { - user.adjustStatistic("ORBS", -cost); - arena.changeArenaOptionBy("TOTAL_ORBS_SPENT", cost); - } - - private boolean validateShop() { - String shop = config.getString("instances." + arena.getId() + ".shop", ""); - if(!shop.contains(",")) { - plugin.getDebugger().debug(Level.WARNING, "There is no shop for arena {0}! Aborting registering shop!", arena.getId()); - return false; - } - Location location = LocationSerializer.getLocation(shop); - if(location.getWorld() == null || !(location.getBlock().getState() instanceof Chest)) { - plugin.getDebugger().debug(Level.WARNING, "Shop failed to load, invalid location for location {0}", LocationSerializer.locationToString(location)); - return false; - } - return true; - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/enemy/spawner/EnemySpawnerRegistry.java b/src/main/java/plugily/projects/villagedefense/arena/managers/enemy/spawner/EnemySpawnerRegistry.java deleted file mode 100644 index b4462a273..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/enemy/spawner/EnemySpawnerRegistry.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package plugily.projects.villagedefense.arena.managers.enemy.spawner; - -import org.bukkit.attribute.Attribute; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.configuration.ConfigUtils; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.creatures.v1_9_UP.CustomCreature; -import plugily.projects.villagedefense.creatures.v1_9_UP.CustomCreatureEvents; -import plugily.projects.villagedefense.creatures.v1_9_UP.CustomRideableCreature; -import plugily.projects.villagedefense.creatures.v1_9_UP.Equipment; -import plugily.projects.villagedefense.creatures.v1_9_UP.Rate; - -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.List; -import java.util.logging.Level; - -/** - * @author Tigerpanzer_02 - *

- * Created at 01.05.2022 - */ -public class EnemySpawnerRegistry extends EnemySpawnerRegistryLegacy { - private static final String CREATURES_MISSING_SECTION = "Creatures section {0} is missing! Was it manually removed?"; - - public EnemySpawnerRegistry(Main plugin) { - super(plugin); - } - - @Override - public void registerRideableCreatures() { - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_8_R3)) { - return; - } - FileConfiguration config = ConfigUtils.getConfig(plugin, "creatures"); - ConfigurationSection village = config.getConfigurationSection("Creatures.Village"); - if(village == null) { - plugin.getDebugger().debug(Level.WARNING, CREATURES_MISSING_SECTION, "Creatures.Village"); - return; - } - for(String rideable : village.getKeys(false)) { - CustomRideableCreature.RideableType rideableType = CustomRideableCreature.RideableType.valueOf(rideable.toUpperCase().replace("RIDEABLE_", "")); - boolean holidayEffects = village.getBoolean(rideable + ".holiday_effects", false); - EnumMap attributes = new EnumMap<>(Attribute.class); - ConfigurationSection attributeSection = village.getConfigurationSection(rideable + ".attributes"); - if(attributeSection == null) { - plugin.getDebugger().debug(Level.WARNING, CREATURES_MISSING_SECTION, "Creatures.Village." + rideable + ".attributes"); - continue; - } - for(String attribute : attributeSection.getKeys(false)) { - try { - attributes.put(Attribute.valueOf(attribute.toUpperCase()), attributeSection.getDouble(attribute)); - } catch(IllegalArgumentException exception) { - plugin.getDebugger().debug(Level.WARNING, "Creatures attribute {0} not found! Check JavaDocs?", "Creatures.Village." + rideable + ".attributes." + attribute); - } - } - - String item = village.getString(rideable + ".drop_item", null); - ItemStack dropItem = null; - if(item != null) { - dropItem = XMaterial.matchXMaterial(item).orElse(XMaterial.BEDROCK).parseItem(); - } - plugin.getDebugger().debug("Registered CustomRideableCreature of type {0}", rideableType); - rideableCreatures.add(new CustomRideableCreature(rideableType, holidayEffects, attributes, dropItem)); - } - } - - @Override - public void registerCreatures() { - new CustomCreatureEvents(plugin); - FileConfiguration config = ConfigUtils.getConfig(plugin, "creatures"); - - ConfigurationSection content = config.getConfigurationSection("Creatures.Content"); - if(content == null) { - plugin.getDebugger().debug(Level.WARNING, CREATURES_MISSING_SECTION, "Creatures.Content"); - return; - } - for(String creature : content.getKeys(false)) { - boolean enabled = content.getBoolean(creature + ".enabled", false); - if(!enabled) { - continue; - } - - int waveMin = content.getInt(creature + ".wave.min", 0); - int waveMax = content.getInt(creature + ".wave.max", 0); - - CustomCreature.PriorityTarget priorityTarget = CustomCreature.PriorityTarget.valueOf(content.getString(creature + ".priority_type", "ANY")); - - boolean explodeTarget = content.getBoolean(creature + ".explosive_hit", false); - - String key = creature.toUpperCase(); - - EntityType entityType = EntityType.valueOf(content.getString(creature + ".entity_type", "ZOMBIE").toUpperCase()); - - boolean baby = content.getBoolean(creature + ".baby", false); - boolean breed = content.getBoolean(creature + ".breed", false); - int age = content.getInt(creature + ".age", 0); - boolean ageLook = content.getBoolean(creature + ".age_lock", false); - boolean holidayEffects = content.getBoolean(creature + ".holiday_effects", true); - int expDrop = content.getInt(creature + ".exp", 0); - - List rates = new ArrayList<>(); - ConfigurationSection rate = content.getConfigurationSection(creature + ".rates"); - if(rate == null) { - plugin.getDebugger().debug(Level.WARNING, CREATURES_MISSING_SECTION, "Creatures.Content." + creature + ".rates"); - continue; - } - for(String rateType : rate.getKeys(false)) { - int phase = rate.getInt(rateType + ".phase", 0); - int waveHigher = rate.getInt(rateType + ".wave_higher", 0); - int waveLower = rate.getInt(rateType + ".wave_lower", 0); - int spawnLower = rate.getInt(rateType + ".spawn_lower", 0); - int rateInt = rate.getInt(rateType + ".rate", 0); - int division = rate.getInt(rateType + ".division", 0); - int reduce = rate.getInt(rateType + ".reduce", 0); - Rate.RateType rateTypeValue = Rate.RateType.valueOf(rateType.toUpperCase()); - rates.add(new Rate(phase, waveHigher, waveLower, spawnLower, rateInt, division, reduce, rateTypeValue)); - } - - EnumMap attributes = new EnumMap<>(Attribute.class); - ConfigurationSection attributeSection = content.getConfigurationSection(creature + ".attributes"); - if(attributeSection == null) { - plugin.getDebugger().debug(Level.WARNING, CREATURES_MISSING_SECTION, "Creatures.Content." + creature + ".attributes"); - continue; - } - for(String attribute : attributeSection.getKeys(false)) { - try { - attributes.put(Attribute.valueOf(attribute.toUpperCase()), attributeSection.getDouble(attribute)); - } catch(IllegalArgumentException exception) { - plugin.getDebugger().debug(Level.WARNING, "Creatures attribute {0} not found! Check JavaDocs?", "Creatures.Content." + creature + ".attributes" + attribute); - } - } - - List equipments = new ArrayList<>(); - ConfigurationSection equipmentSection = content.getConfigurationSection(creature + ".equipment"); - if(equipmentSection == null) { - plugin.getDebugger().debug(Level.WARNING, CREATURES_MISSING_SECTION, "Creatures.Content." + creature + ".equipment"); - continue; - } - for(String equipmentType : equipmentSection.getKeys(false)) { - String item = equipmentSection.getString(equipmentType + ".item", null); - if(item == null) { - continue; - } - ItemStack itemStack = XMaterial.matchXMaterial(item).orElse(XMaterial.BEDROCK).parseItem(); - int dropChance = equipmentSection.getInt(equipmentType + ".drop_chance", 0); - Equipment.EquipmentType equipmentTypeValue = Equipment.EquipmentType.valueOf(equipmentType.toUpperCase()); - equipments.add(new Equipment(itemStack, dropChance, equipmentTypeValue)); - } - - String item = content.getString(creature + ".drop_item", null); - ItemStack dropItem = null; - if(item != null) { - dropItem = XMaterial.matchXMaterial(item).orElse(XMaterial.BEDROCK).parseItem(); - } - plugin.getDebugger().debug("Registered CustomCreature named {0}", key); - enemySpawnerSet.add(new CustomCreature(plugin, waveMin, waveMax, priorityTarget, explodeTarget, key, entityType, baby, breed, age, ageLook, expDrop, holidayEffects, rates, attributes, equipments, dropItem)); - } - - } - - -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/enemy/spawner/EnemySpawnerRegistryLegacy.java b/src/main/java/plugily/projects/villagedefense/arena/managers/enemy/spawner/EnemySpawnerRegistryLegacy.java deleted file mode 100644 index 5da57293d..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/enemy/spawner/EnemySpawnerRegistryLegacy.java +++ /dev/null @@ -1,145 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers.enemy.spawner; - -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.EnemySpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.BabyZombieSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.FastZombieSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.GolemBusterSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.HalfInvisibleZombieSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.HardZombieSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.KnockbackResistantZombieSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.PlayerBusterSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.SoftHardZombieSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.VillagerBusterSpawner; -import plugily.projects.villagedefense.creatures.v1_8_R3.spawner.VillagerSlayerSpawner; -import plugily.projects.villagedefense.creatures.v1_9_UP.CustomRideableCreature; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; - -/** - * The registry for all {@link EnemySpawner} - */ -public class EnemySpawnerRegistryLegacy { - final Set enemySpawnerSet = new TreeSet<>(Collections.reverseOrder()); - final Set rideableCreatures = new HashSet<>(); - final Main plugin; - - public EnemySpawnerRegistryLegacy(Main plugin) { - this.plugin = plugin; - registerCreatures(); - registerRideableCreatures(); - } - - public void registerRideableCreatures() { - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_8_R3)) { - return; - } - } - - public void registerCreatures() { - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_8_R3)) { - enemySpawnerSet.add(new BabyZombieSpawner()); - enemySpawnerSet.add(new FastZombieSpawner()); - enemySpawnerSet.add(new GolemBusterSpawner()); - enemySpawnerSet.add(new HalfInvisibleZombieSpawner()); - enemySpawnerSet.add(new HardZombieSpawner()); - enemySpawnerSet.add(new KnockbackResistantZombieSpawner()); - enemySpawnerSet.add(new PlayerBusterSpawner()); - enemySpawnerSet.add(new SoftHardZombieSpawner()); - enemySpawnerSet.add(new VillagerBusterSpawner()); - enemySpawnerSet.add(new VillagerSlayerSpawner()); - return; - } - } - - /** - * Spawn the enemies at the arena - * - * @param random the random instance - * @param arena the arena - */ - public void spawnEnemies(Random random, Arena arena) { - int spawn = arena.getWave(); - int zombiesLimit = plugin.getConfig().getInt("Limit.Spawn.Creatures", 75); - if(zombiesLimit < spawn) { - spawn = (int) Math.ceil(zombiesLimit / 2.0); - } - String zombieSpawnCounterOption = "ZOMBIE_SPAWN_COUNTER"; - arena.changeArenaOptionBy(zombieSpawnCounterOption, 1); - if(arena.getArenaOption(zombieSpawnCounterOption) == 20) { - arena.setArenaOption(zombieSpawnCounterOption, 0); - } - - List enemySpawners = new ArrayList<>(enemySpawnerSet); - Collections.shuffle(enemySpawners); - for(EnemySpawner enemySpawner : enemySpawners) { - plugin.getDebugger().debug("Trying enemy spawn for " + enemySpawner.getName()); - enemySpawner.spawn(random, arena, spawn); - } - } - - /** - * Get the set of enemy spawners - * - * @return the set of enemy spawners - */ - public Set getEnemySpawnerSet() { - return enemySpawnerSet; - } - - public Set getRideableCreatures() { - return rideableCreatures; - } - - /** - * Get the rideable creature by its type - * - * @param type the tyoe - * @return the rideable creature - */ - public Optional getRideableCreatureByName(CustomRideableCreature.RideableType type) { - return rideableCreatures.stream() - .filter(creature -> creature.getRideableType().equals(type)) - .findFirst(); - } - - /** - * Get the enemy spawner by its name - * - * @param name the name - * @return the enemy spawner - */ - public Optional getSpawnerByName(String name) { - return enemySpawnerSet.stream() - .filter(enemySpawner -> enemySpawner.getName().equals(name)) - .findFirst(); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManager.java index 889733911..a0d5af473 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManager.java +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManager.java @@ -1,60 +1,59 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena.managers.maprestorer; import org.bukkit.Location; -import org.bukkit.TreeSpecies; +import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.material.Door; import plugily.projects.minigamesbox.classic.arena.managers.PluginMapRestorerManager; import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.utils.Utils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.DoorBreakListener; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; /** - * @author Plajer + * @author Tigerpanzer_02 *

- * Created at 14.02.2019 + * Created at 13.01.2021 */ @SuppressWarnings("deprecation") public class MapRestorerManager extends PluginMapRestorerManager { - protected final Map doorBlocks = new LinkedHashMap<>(); - public final Arena arena; + private final List doorBlocks = new ArrayList<>(); + private final Arena arena; public MapRestorerManager(Arena arena) { super(arena); this.arena = arena; } - public final void addDoor(Location location, byte data) { - doorBlocks.put(location, data); + public final void addDoor(Location location) { + doorBlocks.add(location); } - public final Map getGameDoorLocations() { + public final List getGameDoorLocations() { return doorBlocks; } @@ -71,14 +70,13 @@ public void fullyRestoreArena() { } public final void clearEnemiesFromArena() { - arena.getEnemySpawnManager().applyIdle(0); arena.getEnemies().forEach(org.bukkit.entity.Creature::remove); arena.getEnemies().clear(); } public final void clearDroppedEntities() { - for(Entity entity : arena.getPlugin().getBukkitHelper().getNearbyEntities(arena.getStartLocation(), 200)) { - if(entity.getType() == EntityType.EXPERIENCE_ORB || entity.getType() == EntityType.DROPPED_ITEM) { + for (Entity entity : arena.getPlugin().getBukkitHelper().getNearbyEntities(arena.getStartLocation(), 200)) { + if (entity.getType() == EntityType.EXPERIENCE_ORB || entity.getType() == EntityType.DROPPED_ITEM) { entity.remove(); } } @@ -101,56 +99,52 @@ public final void clearWolvesFromArena() { public void restoreDoors() { int i = 0; - for(Map.Entry entry : doorBlocks.entrySet()) { - Block block = entry.getKey().getBlock(); - Byte doorData = entry.getValue(); + for (Location location : doorBlocks) { + Block block = location.getBlock(); try { - if(block.getType() != XMaterial.AIR.parseMaterial()) { + if (block.getType() != XMaterial.AIR.parseMaterial()) { i++; continue; } - if(doorData == (byte) 8) { - restoreTopHalfDoorPart(block); - i++; - continue; + Block relative = block.getRelative(BlockFace.DOWN).getLocation().getBlock(); + boolean isAirBelow = relative.getType().equals(XMaterial.AIR.parseMaterial()); + boolean relativeTopHalf = false; + if (!isAirBelow) { + relative = block.getRelative(BlockFace.UP).getLocation().getBlock(); + relativeTopHalf = true; + } + if (relativeTopHalf) { + restoreDoor(relative, block); + } else { + restoreDoor(block, relative); } - restoreBottomHalfDoorPart(block, doorData); - i++; - } catch(Exception ex) { + } catch (Exception ex) { arena.getPlugin().getDebugger().debug(Level.WARNING, "Door has failed to load for arena {0} message {1} type {2} skipping!", arena.getId(), ex.getMessage(), ex.getCause()); } } - if(i != doorBlocks.size()) { + if (i != doorBlocks.size()) { arena.getPlugin().getDebugger().debug(Level.WARNING, "Failed to load doors for {0}! Expected {1} got {2}", arena.getId(), doorBlocks.size(), i); } } - public void restoreTopHalfDoorPart(Block block) { - block.setType(Utils.getCachedDoor(block)); - BlockState doorBlockState = block.getState(); - Door doorBlockData = new Door(TreeSpecies.GENERIC, arena.getPlugin().getBukkitHelper().getFacingByByte((byte) 8)); + public void restoreDoor(Block top, Block bottom) { + top.setType(Material.OAK_DOOR, false); + bottom.setType(Material.OAK_DOOR, false); - doorBlockData.setTopHalf(true); - doorBlockData.setFacingDirection(doorBlockData.getFacing()); - - doorBlockState.setType(doorBlockData.getItemType()); - doorBlockState.setData(doorBlockData); - - doorBlockState.update(true); - } + org.bukkit.block.data.type.Door d2 = (org.bukkit.block.data.type.Door) top.getBlockData(); + org.bukkit.block.data.type.Door d1 = (org.bukkit.block.data.type.Door) bottom.getBlockData(); - public void restoreBottomHalfDoorPart(Block block, byte doorData) { - block.setType(Utils.getCachedDoor(block)); - BlockState doorBlockState = block.getState(); - Door doorBlockData = new Door(TreeSpecies.GENERIC, arena.getPlugin().getBukkitHelper().getFacingByByte(doorData)); + d2.setHalf(org.bukkit.block.data.Bisected.Half.TOP); + d1.setHalf(org.bukkit.block.data.Bisected.Half.BOTTOM); - doorBlockData.setTopHalf(false); - doorBlockData.setFacingDirection(doorBlockData.getFacing()); + d2.setFacing(top.getRelative(BlockFace.WEST).getType() == Material.AIR ? BlockFace.EAST : BlockFace.NORTH); + d1.setFacing(top.getRelative(BlockFace.WEST).getType() == Material.AIR ? BlockFace.EAST : BlockFace.NORTH); - doorBlockState.setType(doorBlockData.getItemType()); - doorBlockState.setData(doorBlockData); + top.setBlockData(d2); + bottom.setBlockData(d1); - doorBlockState.update(true); + top.removeMetadata(DoorBreakListener.CREATURE_DOOR_BULLDOZER_METADATA, arena.getPlugin()); + bottom.removeMetadata(DoorBreakListener.CREATURE_DOOR_BULLDOZER_METADATA, arena.getPlugin()); } } diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManagerLegacy.java b/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManagerLegacy.java deleted file mode 100644 index f5ab3be34..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/maprestorer/MapRestorerManagerLegacy.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers.maprestorer; - -import java.util.Map; -import java.util.logging.Level; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.TreeSpecies; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.material.Door; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.utils.Utils; - -/** - * @author Tigerpanzer_02 - *

- * Created at 13.01.2021 - */ -@SuppressWarnings("deprecation") -public class MapRestorerManagerLegacy extends MapRestorerManager { - - public MapRestorerManagerLegacy(Arena arena) { - super(arena); - } - - @Override - public void restoreDoors() { - int i = 0; - for(Map.Entry entry : doorBlocks.entrySet()) { - Block block = entry.getKey().getBlock(); - Byte doorData = entry.getValue(); - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_11_R1) && block.getType() != org.bukkit.Material.AIR) { - Material mat = Utils.getCachedDoor(block); - try { - int id = (int) mat.getClass().getDeclaredMethod("getId").invoke(mat); - block.getClass().getDeclaredMethod("setTypeIdAndData", int.class, byte.class, boolean.class) - .invoke(block, id, doorData, false); - } catch(Exception e) { - e.printStackTrace(); - } - i++; - } else { - try { - if(block.getType() != XMaterial.AIR.parseMaterial()) { - i++; - continue; - } - if(doorData == (byte) 8) { - restoreTopHalfDoorPart(block); - i++; - continue; - } - restoreBottomHalfDoorPart(block, doorData); - i++; - } catch(Exception ex) { - arena.getPlugin().getDebugger().debug(Level.WARNING, "Door has failed to load for arena {0} message {1} type {2} skipping!", arena.getId(), ex.getMessage(), ex.getCause()); - } - } - } - if(i != doorBlocks.size()) { - arena.getPlugin().getDebugger().debug(Level.WARNING, "Failed to load doors for {0}! Expected {1} got {2}", arena.getId(), doorBlocks.size(), i); - } - } - - @Override - public void restoreTopHalfDoorPart(Block block) { - block.setType(Utils.getCachedDoor(block)); - - Door doorBlockData = null; - try { - doorBlockData = new Door(TreeSpecies.GENERIC, arena.getPlugin().getBukkitHelper().getFacingByByte((byte) 8)); - } catch (NoSuchMethodError e) { - try { - doorBlockData = Door.class.getDeclaredConstructor(Material.class, byte.class) - .newInstance(XMaterial.OAK_DOOR, arena.getPlugin().getBukkitHelper().getFacingByByte((byte) 8)); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - if (doorBlockData == null) - return; - - BlockState doorBlockState = block.getState(); - - doorBlockData.setTopHalf(true); - doorBlockData.setFacingDirection(doorBlockData.getFacing()); - doorBlockState.setType(doorBlockData.getItemType()); - doorBlockState.setData(doorBlockData); - doorBlockState.update(true); - } - - @Override - public void restoreBottomHalfDoorPart(Block block, byte doorData) { - block.setType(Utils.getCachedDoor(block)); - - Door doorBlockData = null; - try { - doorBlockData = new Door(TreeSpecies.GENERIC, arena.getPlugin().getBukkitHelper().getFacingByByte(doorData)); - } catch (NoSuchMethodError e) { - try { - doorBlockData = Door.class.getDeclaredConstructor(Material.class, byte.class) - .newInstance(XMaterial.OAK_DOOR.parseMaterial(), arena.getPlugin().getBukkitHelper().getFacingByByte(doorData)); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - if (doorBlockData == null) - return; - - BlockState doorBlockState = block.getState(); - - doorBlockData.setTopHalf(false); - doorBlockData.setFacingDirection(doorBlockData.getFacing()); - doorBlockState.setType(doorBlockData.getItemType()); - doorBlockState.setData(doorBlockData); - doorBlockState.update(true); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ArenaShopRegistry.java b/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ArenaShopRegistry.java new file mode 100644 index 000000000..c350e1646 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ArenaShopRegistry.java @@ -0,0 +1,781 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.shop; + +import lombok.Getter; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.potion.PotionEffectType; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.villagedefense.Main; + +import java.util.ArrayList; +import java.util.List; + +public class ArenaShopRegistry { + + private final @Getter List shopItems = new ArrayList<>(); + + public void registerItems() { + registerSwords(); + registerBows(); + registerCrossbows(); + registerHelmets(); + registerChestplate(); + registerLeggings(); + registerBoots(); + registerConsumables(); + } + + private void registerSwords() { + shopItems.add(new ShopItem("WeaponT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.STONE_SWORD) + .name(color("&7Stone Sword &e&l(Tier I)")) + .enchantment(Enchantment.DAMAGE_ALL, 1) + .build()), "WeaponT1"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 150, 3, 1, null, true, false + )); + shopItems.add(new ShopItem("WeaponT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_SWORD) + .name(color("&7Iron Sword &e&l(Tier II)")) + .build()), "WeaponT2"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 250, 3, 1, "WeaponT1", true, false + )); + shopItems.add(new ShopItem("WeaponT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_SWORD) + .name(color("&7Iron Sword &e&l(Tier III)")) + .enchantment(Enchantment.DAMAGE_ALL, 1) + .build()), "WeaponT3"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 450, 3, 1, "WeaponT2", true, false + )); + shopItems.add(new ShopItem("WeaponT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_SWORD) + .name(color("&7Iron Sword &e&l(Tier IV)")) + .enchantment(Enchantment.DAMAGE_ALL, 2) + .enchantment(Enchantment.KNOCKBACK, 1) + .build()), "WeaponT4"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 650, 3, 1, "WeaponT3", true, false + )); + shopItems.add(new ShopItem("WeaponT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_SWORD) + .name(color("&dDiamond Sword &e&l(Tier V)")) + .enchantment(Enchantment.DAMAGE_ALL, 2) + .enchantment(Enchantment.KNOCKBACK, 1) + .build()), "WeaponT5"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 850, 3, 1, "WeaponT4", true, false + )); + shopItems.add(new ShopItem("WeaponT6", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_SWORD) + .name(color("&dDiamond Sword &e&l(Tier VI)")) + .enchantment(Enchantment.DAMAGE_ALL, 3) + .enchantment(Enchantment.KNOCKBACK, 1) + .build()), "WeaponT6"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 1050, 3, 1, "WeaponT5", true, false + )); + shopItems.add(new ShopItem("WeaponT7", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_SWORD) + .name(color("&dDiamond Sword &e&l(Tier VII)")) + .enchantment(Enchantment.DAMAGE_ALL, 3) + .enchantment(Enchantment.FIRE_ASPECT, 1) + .enchantment(Enchantment.KNOCKBACK, 1) + .build()), "WeaponT7"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 1250, 3, 1, "WeaponT6", true, false + )); + shopItems.add(new ShopItem("WeaponT8", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_SWORD) + .name(color("&8Netherite Sword &e&l(Tier VIII)")) + .enchantment(Enchantment.DAMAGE_ALL, 3) + .enchantment(Enchantment.FIRE_ASPECT, 1) + .enchantment(Enchantment.KNOCKBACK, 1) + .build()), "WeaponT8"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 1450, 3, 1, "WeaponT7", true, false + )); + shopItems.add(new ShopItem("WeaponT9", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_SWORD) + .name(color("&8Netherite Sword &e&l(Tier IX)")) + .enchantment(Enchantment.DAMAGE_ALL, 4) + .enchantment(Enchantment.FIRE_ASPECT, 1) + .enchantment(Enchantment.KNOCKBACK, 1) + .build()), "WeaponT9"), + ShopItem.PurchasableItem.Position.INVENTORY + ), + 1650, 3, 1, "WeaponT8", true, true + )); + } + + private void registerBows() { + shopItems.add(new ShopItem("BowT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.BOW) + .name(color("&7Bow &e&l(Tier I)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 1) + .build()), "BowT1"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 4, 1, null, true, false + )); + shopItems.add(new ShopItem("BowT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.BOW) + .name(color("&7Bow &e&l(Tier II)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 2) + .build()), "BowT2"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 4, 1, "BowT1", true, false + )); + shopItems.add(new ShopItem("BowT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.BOW) + .name(color("&7Bow &e&l(Tier III)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .build()), "BowT3"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 4, 1, "BowT2", true, false + )); + shopItems.add(new ShopItem("BowT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.BOW) + .name(color("&7Bow &e&l(Tier IV)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.ARROW_KNOCKBACK, 1) + .build()), "BowT4"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 4, 1, "BowT3", true, false + )); + shopItems.add(new ShopItem("BowT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.BOW) + .name(color("&7Bow &e&l(Tier V)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.ARROW_KNOCKBACK, 1) + .enchantment(Enchantment.ARROW_FIRE, 1) + .build()), "BowT5"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 4, 1, "BowT4", true, true + )); + } + + private void registerCrossbows() { + shopItems.add(new ShopItem("CrossbowT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier I)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 1) + .build()), "CrossbowT1"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, null, true, false + )); + shopItems.add(new ShopItem("CrossbowT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier II)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 2) + .build()), "CrossbowT2"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT1", true, false + )); + shopItems.add(new ShopItem("CrossbowT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier III)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 2) + .enchantment(Enchantment.QUICK_CHARGE, 1) + .build()), "CrossbowT3"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT2", true, false + )); + shopItems.add(new ShopItem("CrossbowT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier IV)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 2) + .enchantment(Enchantment.QUICK_CHARGE, 1) + .enchantment(Enchantment.PIERCING, 1) + .build()), "CrossbowT4"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT3", true, false + )); + shopItems.add(new ShopItem("CrossbowT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier V)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.QUICK_CHARGE, 1) + .enchantment(Enchantment.PIERCING, 1) + .build()), "CrossbowT5"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT4", true, false + )); + shopItems.add(new ShopItem("CrossbowT6", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier VI)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.QUICK_CHARGE, 2) + .enchantment(Enchantment.PIERCING, 1) + .build()), "CrossbowT6"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT5", true, false + )); + shopItems.add(new ShopItem("CrossbowT7", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier VII)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.QUICK_CHARGE, 2) + .enchantment(Enchantment.PIERCING, 2) + .build()), "CrossbowT7"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT6", true, false + )); + shopItems.add(new ShopItem("CrossbowT8", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier VIII)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.QUICK_CHARGE, 2) + .enchantment(Enchantment.PIERCING, 2) + .enchantment(Enchantment.ARROW_FIRE, 1) + .build()), "CrossbowT8"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT7", true, false + )); + shopItems.add(new ShopItem("CrossbowT9", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CROSSBOW) + .name(color("&7Crossbow &e&l(Tier IX)")) + .enchantment(Enchantment.ARROW_INFINITE, 1) + .enchantment(Enchantment.ARROW_DAMAGE, 3) + .enchantment(Enchantment.QUICK_CHARGE, 2) + .enchantment(Enchantment.PIERCING, 2) + .enchantment(Enchantment.ARROW_FIRE, 1) + .enchantment(Enchantment.MULTISHOT, 1) + .build()), "CrossbowT9"), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 1, "CrossbowT8", true, true + )); + } + + private void registerHelmets() { + shopItems.add(new ShopItem("HelmetT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CHAINMAIL_HELMET) + .name(color("&7Chainmail Helmet &e&l(Tier I)")) + .build()), "HelmetT1"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, null, true, false + )); + shopItems.add(new ShopItem("HelmetT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_HELMET) + .name(color("&7Iron Helmet &e&l(Tier II)")) + .build()), "HelmetT2"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT1", true, false + )); + shopItems.add(new ShopItem("HelmetT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_HELMET) + .name(color("&7Iron Helmet &e&l(Tier III)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build()), "HelmetT3"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT2", true, false + )); + shopItems.add(new ShopItem("HelmetT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_HELMET) + .name(color("&7Iron Helmet &e&l(Tier IV)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .build()), "HelmetT4"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT3", true, false + )); + shopItems.add(new ShopItem("HelmetT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_HELMET) + .name(color("&7Iron Helmet &e&l(Tier V)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "HelmetT5"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT4", true, false + )); + shopItems.add(new ShopItem("HelmetT6", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_HELMET) + .name(color("&dDiamond Helmet &e&l(Tier VI)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "HelmetT6"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT5", true, false + )); + shopItems.add(new ShopItem("HelmetT7", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_HELMET) + .name(color("&dDiamond Helmet &e&l(Tier VII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "HelmetT7"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT6", true, false + )); + shopItems.add(new ShopItem("HelmetT8", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_HELMET) + .name(color("&dDiamond Helmet &e&l(Tier VIII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "HelmetT8"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT7", true, false + )); + shopItems.add(new ShopItem("HelmetT9", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_HELMET) + .name(color("&8Netherite Helmet &e&l(Tier IX)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "HelmetT9"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT8", true, false + )); + shopItems.add(new ShopItem("HelmetT10", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_HELMET) + .name(color("&8Netherite Helmet &e&l(Tier X)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 4) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "HelmetT10"), + ShopItem.PurchasableItem.Position.ARMOR_HELMET + ), 100, 2, 2, "HelmetT9", true, true + )); + } + + private void registerChestplate() { + shopItems.add(new ShopItem("ChestplateT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CHAINMAIL_CHESTPLATE) + .name(color("&7Chainmail Chestplate &e&l(Tier I)")) + .build()), "ChestplateT1"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, null, true, false + )); + shopItems.add(new ShopItem("ChestplateT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_CHESTPLATE) + .name(color("&7Iron Chestplate &e&l(Tier II)")) + .build()), "ChestplateT2"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT1", true, false + )); + shopItems.add(new ShopItem("ChestplateT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_CHESTPLATE) + .name(color("&7Iron Chestplate &e&l(Tier III)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build()), "ChestplateT3"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT2", true, false + )); + shopItems.add(new ShopItem("ChestplateT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_CHESTPLATE) + .name(color("&7Iron Chestplate &e&l(Tier IV)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .build()), "ChestplateT4"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT3", true, false + )); + shopItems.add(new ShopItem("ChestplateT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_CHESTPLATE) + .name(color("&7Iron Chestplate &e&l(Tier V)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "ChestplateT5"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT4", true, false + )); + shopItems.add(new ShopItem("ChestplateT6", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_CHESTPLATE) + .name(color("&dDiamond Chestplate &e&l(Tier VI)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "ChestplateT6"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT5", true, false + )); + shopItems.add(new ShopItem("ChestplateT7", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_CHESTPLATE) + .name(color("&dDiamond Chestplate &e&l(Tier VII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "ChestplateT7"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT6", true, false + )); + shopItems.add(new ShopItem("ChestplateT8", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_CHESTPLATE) + .name(color("&dDiamond Chestplate &e&l(Tier VIII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "ChestplateT8"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT7", true, false + )); + shopItems.add(new ShopItem("ChestplateT9", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_CHESTPLATE) + .name(color("&8Netherite Chestplate &e&l(Tier IX)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "ChestplateT9"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT8", true, false + )); + shopItems.add(new ShopItem("ChestplateT10", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_CHESTPLATE) + .name(color("&8Netherite Chestplate &e&l(Tier X)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 4) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "ChestplateT10"), + ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE + ), 100, 3, 2, "ChestplateT9", true, true + )); + } + + private void registerLeggings() { + shopItems.add(new ShopItem("LeggingsT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CHAINMAIL_LEGGINGS) + .name(color("&7Chainmail Leggings &e&l(Tier I)")) + .build()), "LeggingsT1"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, null, true, false + )); + shopItems.add(new ShopItem("LeggingsT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_LEGGINGS) + .name(color("&7Iron Leggings &e&l(Tier II)")) + .build()), "LeggingsT2"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT1", true, false + )); + shopItems.add(new ShopItem("LeggingsT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_LEGGINGS) + .name(color("&7Iron Leggings &e&l(Tier III)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build()), "LeggingsT3"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT2", true, false + )); + shopItems.add(new ShopItem("LeggingsT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_LEGGINGS) + .name(color("&7Iron Leggings &e&l(Tier IV)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .build()), "LeggingsT4"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT3", true, false + )); + shopItems.add(new ShopItem("LeggingsT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_LEGGINGS) + .name(color("&7Iron Leggings &e&l(Tier V)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "LeggingsT5"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT4", true, false + )); + shopItems.add(new ShopItem("LeggingsT6", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_LEGGINGS) + .name(color("&dDiamond Leggings &e&l(Tier VI)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "LeggingsT6"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT5", true, false + )); + shopItems.add(new ShopItem("LeggingsT7", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_LEGGINGS) + .name(color("&dDiamond Leggings &e&l(Tier VII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "LeggingsT7"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT6", true, false + )); + shopItems.add(new ShopItem("LeggingsT8", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_LEGGINGS) + .name(color("&dDiamond Leggings &e&l(Tier VIII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "LeggingsT8"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT7", true, false + )); + shopItems.add(new ShopItem("LeggingsT9", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_LEGGINGS) + .name(color("&8Netherite Leggings &e&l(Tier IX)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "LeggingsT9"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT8", true, false + )); + shopItems.add(new ShopItem("LeggingsT10", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_LEGGINGS) + .name(color("&8Netherite Leggings &e&l(Tier X)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 4) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "LeggingsT10"), + ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS + ), 100, 5, 2, "LeggingsT9", true, true + )); + } + + private void registerBoots() { + shopItems.add(new ShopItem("BootsT1", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.CHAINMAIL_BOOTS) + .name(color("&7Chainmail Boots &e&l(Tier I)")) + .build()), "BootsT1"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, null, true, false + )); + shopItems.add(new ShopItem("BootsT2", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_BOOTS) + .name(color("&7Iron Boots &e&l(Tier II)")) + .build()), "BootsT2"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT1", true, false + )); + shopItems.add(new ShopItem("BootsT3", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_BOOTS) + .name(color("&7Iron Boots &e&l(Tier III)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 1) + .build()), "BootsT3"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT2", true, false + )); + shopItems.add(new ShopItem("BootsT4", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_BOOTS) + .name(color("&7Iron Boots &e&l(Tier IV)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .build()), "BootsT4"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT3", true, false + )); + shopItems.add(new ShopItem("BootsT5", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.IRON_BOOTS) + .name(color("&7Iron Boots &e&l(Tier V)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "BootsT5"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT4", true, false + )); + shopItems.add(new ShopItem("BootsT6", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_BOOTS) + .name(color("&dDiamond Boots &e&l(Tier VI)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.THORNS, 1) + .build()), "BootsT6"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT5", true, false + )); + shopItems.add(new ShopItem("BootsT7", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_BOOTS) + .name(color("&dDiamond Boots &e&l(Tier VII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 2) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "BootsT7"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT6", true, false + )); + shopItems.add(new ShopItem("BootsT8", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.DIAMOND_BOOTS) + .name(color("&dDiamond Boots &e&l(Tier VIII)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "BootsT8"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT7", true, false + )); + shopItems.add(new ShopItem("BootsT9", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_BOOTS) + .name(color("&8Netherite Boots &e&l(Tier IX)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 3) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "BootsT9"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT8", true, false + )); + shopItems.add(new ShopItem("BootsT10", + new ShopItem.PurchasableItem( + metadata(unbreakable(new ItemBuilder(Material.NETHERITE_BOOTS) + .name(color("&8Netherite Boots &e&l(Tier X)")) + .enchantment(Enchantment.PROTECTION_ENVIRONMENTAL, 4) + .enchantment(Enchantment.PROTECTION_EXPLOSIONS, 1) + .enchantment(Enchantment.THORNS, 1) + .build()), "BootsT10"), + ShopItem.PurchasableItem.Position.ARMOR_BOOTS + ), 100, 6, 2, "BootsT9", true, true + )); + } + + private void registerConsumables() { + shopItems.add(new ShopItem("Food", + new ShopItem.PurchasableItem( + new ItemBuilder(Material.COOKED_PORKCHOP) + .name(color("&6Cooked Porkchop")) + .amount(3) + .build(), + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 3, 3, null, false, true + )); + ItemStack splashPotion1 = new ItemBuilder(Material.SPLASH_POTION) + .name(color("&6Splash Potion of Slowness")) + .amount(1) + .build(); + PotionMeta meta1 = (PotionMeta) splashPotion1.getItemMeta(); + meta1.addCustomEffect(PotionEffectType.SLOW.createEffect(20 * 10, 0), true); + splashPotion1.setItemMeta(meta1); + shopItems.add(new ShopItem("SplashPotion1", + new ShopItem.PurchasableItem( + splashPotion1, + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 4, 3, null, false, true + )); + ItemStack splashPotion2 = new ItemBuilder(Material.SPLASH_POTION) + .name(color("&6Splash Potion of Healing")) + .amount(1) + .build(); + PotionMeta meta2 = (PotionMeta) splashPotion2.getItemMeta(); + meta2.addCustomEffect(PotionEffectType.HEAL.createEffect(1, 0), true); + splashPotion2.setItemMeta(meta2); + shopItems.add(new ShopItem("SplashPotion2", + new ShopItem.PurchasableItem( + splashPotion2, + ShopItem.PurchasableItem.Position.INVENTORY + ), 100, 5, 3, null, false, true + )); + } + + private ItemStack unbreakable(ItemStack stack) { + ItemMeta meta = stack.getItemMeta(); + meta.setUnbreakable(true); + stack.setItemMeta(meta); + return stack; + } + + private ItemStack metadata(ItemStack stack, String key) { + ItemMeta meta = stack.getItemMeta(); + PersistentDataContainer container = meta.getPersistentDataContainer(); + container.set(new NamespacedKey(JavaPlugin.getProvidingPlugin(Main.class), key), PersistentDataType.STRING, "true"); + stack.setItemMeta(meta); + return stack; + } + + private String color(String msg) { + return ChatColor.translateAlternateColorCodes('&', msg); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ShopItem.java b/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ShopItem.java new file mode 100644 index 000000000..4adaf29d3 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ShopItem.java @@ -0,0 +1,31 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.shop; + +import org.bukkit.inventory.ItemStack; + +public record ShopItem(String id, PurchasableItem item, int cost, int xPos, int yPos, String requiresId, boolean requiresMetadata, boolean finalTier) { + + public record PurchasableItem(ItemStack itemStack, Position position) { + public enum Position { + INVENTORY, ARMOR_HELMET, ARMOR_CHESTPLATE, ARMOR_LEGGINGS, ARMOR_BOOTS + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ShopManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ShopManager.java new file mode 100644 index 000000000..7e724f80c --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/shop/ShopManager.java @@ -0,0 +1,186 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.shop; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import com.github.stefvanschie.inventoryframework.gui.type.ChestGui; +import com.github.stefvanschie.inventoryframework.pane.StaticPane; +import lombok.Getter; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by Tom on 16/08/2014. + */ +public class ShopManager { + + public static final String SHOP_OFFER_METADATA = "VD_SHOP_SPECIAL_OFFER"; + + private final String defaultOrbsName; + private final String defaultWaveLockName = "wave_lock"; + private final String itemLockedMessage; + private final String specialOfferMessage; + + private final @Getter Set newOffersAtWaves = new HashSet<>(); + private final Main plugin; + private final Arena arena; + + public ShopManager(Arena arena) { + plugin = arena.getPlugin(); + this.arena = arena; + + defaultOrbsName = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_CURRENCY").asKey().build(); + itemLockedMessage = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_ITEM_LOCKED").asKey().build(); + specialOfferMessage = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_SPECIAL_OFFER").asKey().build(); + } + + public void openShop(Player player, Villager source) { + User user = plugin.getUserManager().getUser(player); + if (user == null || user.getArena() == null) { + return; + } + boolean hasSpecialOffer = source.hasMetadata(ShopManager.SHOP_OFFER_METADATA); + openShop(user, hasSpecialOffer); + } + + private void openShop(User user, boolean hasPromo) { + Player player = user.getPlayer(); + StaticPane pane = new StaticPane(0, 0, 9, 5); + Set ownedMetadatas = new HashSet<>(); + for (ItemStack itemStack : player.getInventory()) { + if (itemStack == null || !itemStack.hasItemMeta()) { + continue; + } + PersistentDataContainer container = itemStack.getItemMeta().getPersistentDataContainer(); + if (container.isEmpty()) { + continue; + } + for (ShopItem item : plugin.getArenaShopRegistry().getShopItems()) { + if (container.has(new NamespacedKey(plugin, item.id()))) { + ownedMetadatas.add(item.id()); + } + } + } + for (ShopItem item : plugin.getArenaShopRegistry().getShopItems()) { + boolean owned = ownedMetadatas.contains(item.id()); + if (owned && !item.finalTier() && !item.requiresMetadata()) { + continue; + } + if (item.requiresId() != null && !ownedMetadatas.contains(item.requiresId()) && !owned) { + continue; + } + pane.addItem(new GuiItem(renderItem(item, owned), e -> { + e.setCancelled(true); + int orbs = user.getStatistic("ORBS"); + if (owned) { + XSound.ENTITY_VILLAGER_NO.play(player); + return; + } + if (orbs < item.cost()) { + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_NOT_ENOUGH_CURRENCY").asKey().player(player).sendPlayer(); + XSound.ENTITY_VILLAGER_NO.play(player); + return; + } + + applyOrGiveItem(player, item); + adjustOrbs(user, item.cost()); + openShop(user, hasPromo); + }), item.xPos(), item.yPos()); + } + ChestGui gui = new ChestGui(5, new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_SHOP_GUI").asKey().build()); + gui.addPane(pane); + gui.show(player); + } + + private ItemStack renderItem(ShopItem item, boolean owned) { + plugily.projects.villagedefense.utils.ItemBuilder builder = new plugily.projects.villagedefense.utils.ItemBuilder(item.item().itemStack()) + .addFlag(ItemFlag.HIDE_ATTRIBUTES); + if (item.requiresId() == null && !owned) { + builder = builder.appendLore(Arrays.asList("", "§7Purchase this item", "§7for §e§l" + item.cost() + " ORBS", "")); + } else { + builder = builder.appendLore(Arrays.asList("", "§7Upgrade item to this tier", "§7for §e§l" + item.cost() + " ORBS", "")); + } + if (owned) { + builder = builder.appendLore(Arrays.asList("", "§c(You already own this item)")); + } + return builder.build(); + } + + private void applyOrGiveItem(Player player, ShopItem item) { + ShopItem.PurchasableItem.Position position = item.item().position(); + ItemStack itemStack = item.item().itemStack(); + if (position == ShopItem.PurchasableItem.Position.INVENTORY) { + if (item.requiresMetadata() && item.requiresId() != null) { + replaceItem(player, item); + return; + } + player.getInventory().addItem(itemStack); + } + if (position == ShopItem.PurchasableItem.Position.ARMOR_HELMET) { + player.getInventory().setHelmet(item.item().itemStack()); + } else if (position == ShopItem.PurchasableItem.Position.ARMOR_CHESTPLATE) { + player.getInventory().setChestplate(item.item().itemStack()); + } else if (position == ShopItem.PurchasableItem.Position.ARMOR_LEGGINGS) { + player.getInventory().setLeggings(item.item().itemStack()); + } else if (position == ShopItem.PurchasableItem.Position.ARMOR_BOOTS) { + player.getInventory().setBoots(item.item().itemStack()); + } + } + + private void replaceItem(Player player, ShopItem item) { + ItemStack itemStack = item.item().itemStack(); + List items = Arrays.stream(player.getInventory().getContents()) + .filter(stack -> { + if (stack == null || !stack.hasItemMeta()) { + return false; + } + PersistentDataContainer container = stack.getItemMeta().getPersistentDataContainer(); + return container.has(new NamespacedKey(plugin, item.requiresId())); + }).collect(Collectors.toList()); + if (items.isEmpty()) { + player.getInventory().addItem(itemStack); + return; + } + ItemStack toReplace = items.get(0); + player.getInventory().remove(toReplace); + player.getInventory().addItem(itemStack); + } + + private void adjustOrbs(User user, int cost) { + user.adjustStatistic("ORBS", -cost); + arena.changeArenaOptionBy("TOTAL_ORBS_SPENT", cost); + XSound.ENTITY_VILLAGER_YES.play(user.getPlayer()); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/EnemySpawner.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/EnemySpawner.java deleted file mode 100644 index 18a2c9abd..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/EnemySpawner.java +++ /dev/null @@ -1,69 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers.spawner; - -import java.util.Random; - -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.arena.Arena; - -/** - * The interface for enemy spawner - */ -public interface EnemySpawner extends Comparable { - /** - * Get the name of the spawner - * - * @return the name - */ - String getName(); - - /** - * Get the priority of the spawner (the higher the sooner) - */ - default int getPriority() { - return 0; - } - - /** - * Handle the spawn - * - * @param random the random number generator - * @param arena the arena the manager is trying to spawn enemies - * @param spawn the amount to spawn - */ - void spawn(Random random, Arena arena, int spawn); - - /** - * Get the defined itemstack for drop reasons - * does NOT work on 1.8.8 or lower - * @return ItemStack that gets dropped on enemey death - */ - ItemStack getDropItem(); - - @Override - default int compareTo(EnemySpawner spawner) { - int compareValue = Integer.compare(getPriority(), spawner.getPriority()); - if (compareValue == 0) { - return getName().compareTo(spawner.getName()); - } - return compareValue; - } -} \ No newline at end of file diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/SimpleEnemySpawner.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/SimpleEnemySpawner.java deleted file mode 100644 index 34e60807d..000000000 --- a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/SimpleEnemySpawner.java +++ /dev/null @@ -1,178 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.arena.managers.spawner; - -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.jetbrains.annotations.Nullable; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -import java.util.Random; - -/** - * The interface for simple enemy spawner - */ -public interface SimpleEnemySpawner extends EnemySpawner { - /** - * Get the minimum wave to spawn the enemies - * - * @return the wave - */ - default int getMinWave() { - return 1; - } - - /** - * Get the maximum wave to spawn the enemies (stop spawning when exceeding this value) - * - * @return the wave - */ - default int getMaxWave() { - return -1; - } - - /** - * Can the enemies be applied some holiday effects? - * - * @return true if they can - */ - default boolean canApplyHolidayEffect() { - return false; - } - - /** - * Can the enemies be applied arena attributes? - * - * @return true if they can - */ - default boolean canApplyAttributes() { - return true; - } - - /** - * How often the enemies will be spawned? Amount between 0.0 and 1.0 - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return the spawn rate in double - */ - double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount); - - /** - * Get the final amount of enemies to spawn, after some workaround - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return the final amount - */ - int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount); - - /** - * Check if the enemies can be spawned on this phase - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return true if they can - */ - boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount); - - /** - * Spawn the enemy at the location - * - * @param location the location - * @return the spawned enemy - */ - @Nullable - Creature spawn(Location location); - - /** - * Get the weight of the enemy in the arena. - * Basically mean this enemy is worth how many normal enemies in the arena. - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return the weight of the enemy - */ - default int getSpawnWeight(Arena arena, int wave, int phase, int spawnAmount) { - return 1; - } - - /** - * Spawn the enemy at the location of the arena. - * - * @param location the location - * @param arena the arena - */ - default void spawn(Location location, Arena arena) { - Creature creature = spawn(location); - if(creature == null) { - return; - } - if(canApplyAttributes()) { - CreatureUtils.applyAttributes(creature, arena); - } - if(canApplyHolidayEffect()) { - arena.getPlugin().getHolidayManager().applyHolidayCreatureEffects(creature); - } - arena.getEnemies().add(creature); - } - - //TODO Simplify creature spawn reduce to one method e.g. spawn; add weight to creatures configurable! - @Override - default void spawn(Random random, Arena arena, int spawn) { - int wave = arena.getWave(); - int phase = arena.getArenaOption("ZOMBIE_SPAWN_COUNTER"); - arena.getPlugin().getDebugger().debug("Current Wave: " + wave + " Current Phase: " + phase + " Current spawn: " + spawn + " CHECK PHASE: " + checkPhase(arena, wave, phase, spawn)); - if(!checkPhase(arena, wave, phase, spawn)) { - return; - } - - - int maxWave = getMaxWave(); - arena.getPlugin().getDebugger().debug("Current Wave: " + wave + " Max wave: " + maxWave + " CHECK WAVE: " + (wave < getMinWave() || (maxWave > 0 && wave > maxWave))); - - if(wave < getMinWave() || (maxWave > 0 && wave > maxWave)) { - return; - } - int spawnAmount = getFinalAmount(arena, wave, phase, spawn); - double spawnRate = getSpawnRate(arena, wave, phase, spawn); - int weight = getSpawnWeight(arena, wave, phase, spawn); - arena.getPlugin().getDebugger().debug("Current Wave: " + wave + " Current Spawn amount: " + spawnAmount + " Current spawnRate: " + spawnRate + " Current Spawn Weight: " + weight); - - for(int i = 0; i < spawnAmount; i++) { - int zombiesToSpawn = arena.getArenaOption("ZOMBIES_TO_SPAWN"); - arena.getPlugin().getDebugger().debug("Current Wave: " + wave + " Current Spawn amount: " + spawnAmount + " Current i: " + i + " CHECK SPAWN: " + (zombiesToSpawn >= weight && spawnRate != 0 && (spawnRate == 1 || random.nextDouble() < spawnRate))); - if(zombiesToSpawn >= weight && spawnRate != 0 && (spawnRate == 1 || random.nextDouble() < spawnRate)) { - Location location = arena.getRandomZombieSpawnLocation(random); - spawn(location, arena); - arena.setArenaOption("ZOMBIES_TO_SPAWN", zombiesToSpawn - weight); - } - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/DoorBreakListener.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/DoorBreakListener.java new file mode 100644 index 000000000..f0cdabeee --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/DoorBreakListener.java @@ -0,0 +1,180 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.utils.ProtocolUtils; +import plugily.projects.villagedefense.utils.Utils; + +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +/** + * Created by Tom on 14/08/2014. + */ +public class DoorBreakListener extends BukkitRunnable { + + public static final String CREATURE_DOOR_BULLDOZER_METADATA = "VD_DOOR_BULLDOZER_BUFF"; + + private static final String DESTROY_STATE_METADATA = "VD_DOOR_DESTROY_STATE"; + private final Main plugin; + + public DoorBreakListener(Main plugin) { + this.plugin = plugin; + runTaskTimer(plugin, 1, 30); + } + + @Override + public void run() { + for(World world : plugin.getArenaRegistry().getArenaIngameWorlds()) { + List entities = world.getLivingEntities() + .stream() + .filter(NewCreatureUtils::isEnemy) + .collect(Collectors.toList()); + for(LivingEntity entity : entities) { + for(Block block : plugin.getBukkitHelper().getNearbyBlocks(entity, 1)) { + Material door = Utils.getCachedDoor(block); + if(block.getType() != door) { + continue; + } + if(entity.hasMetadata("VD_DOOR_BLOCK_BAN")) { + Arena arena = findArenaForEntity(entity); + Player player = Bukkit.getPlayer(UUID.fromString(entity.getMetadata("VD_DOOR_BLOCK_BAN_SOURCE").get(0).asString())); + if(arena == null || player == null) { + continue; + } + arena.getAssistHandler().doRegisterDebuffOnEnemy(player, (Creature) entity); + } + + Location location = block.getLocation(); + VersionUtils.sendParticles("SMOKE_LARGE", null, location, 5, 0.1, 0.1, 0.1); + VersionUtils.playSound(location, "ENTITY_ZOMBIE_ATTACK_WOODEN_DOOR"); + int destroyState = getDoorDestroyState(block); + int doubleAttackChance = 15; + if(entity.hasMetadata(CREATURE_DOOR_BULLDOZER_METADATA)) { + doubleAttackChance = 8; + } + if(ThreadLocalRandom.current().nextInt(20) >= doubleAttackChance) { + destroyState++; + } + destroyState++; + block.setMetadata(CREATURE_DOOR_BULLDOZER_METADATA, new FixedMetadataValue(plugin, destroyState)); + doPerformDoorDamage(block, door, destroyState); + if(destroyState >= 10) { + doPerformDoorBreak(block, door); + } + final int finalState = destroyState; + Bukkit.getScheduler().runTaskLater(plugin, () -> { + //block was already destroyed + if(block.getType() == XMaterial.AIR.parseMaterial() || !block.hasMetadata(CREATURE_DOOR_BULLDOZER_METADATA)) { + return; + } + //block wasn't touched for a while, remove the destruction + if(block.getMetadata(CREATURE_DOOR_BULLDOZER_METADATA).get(0).asInt() == finalState) { + doPerformDamageRemoval(block, door); + } + }, 20L * 5); + } + } + } + } + + private Arena findArenaForEntity(LivingEntity entity) { + for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if(arena.getEnemies().contains(entity)) { + return arena; + } + } + return null; + } + + private int getDoorDestroyState(Block block) { + int destroyState; + if(!block.hasMetadata(CREATURE_DOOR_BULLDOZER_METADATA)) { + destroyState = 0; + block.setMetadata(CREATURE_DOOR_BULLDOZER_METADATA, new FixedMetadataValue(plugin, destroyState)); + } else { + destroyState = block.getMetadata(CREATURE_DOOR_BULLDOZER_METADATA).get(0).asInt(); + } + return destroyState; + } + + private void doPerformDoorDamage(Block block, Material door, int destroyState) { + ProtocolUtils.sendBlockBreakAnimation(block, destroyState); + + Block relative = block.getRelative(BlockFace.UP); + + if(relative.getType() == door) { + ProtocolUtils.sendBlockBreakAnimation(relative, destroyState); + } else if((relative = block.getRelative(BlockFace.DOWN)).getType() == door) { + ProtocolUtils.sendBlockBreakAnimation(relative, destroyState); + } + } + + private void doPerformDamageRemoval(Block block, Material door) { + block.removeMetadata(CREATURE_DOOR_BULLDOZER_METADATA, plugin); + ProtocolUtils.removeBlockBreakAnimation(block); + + Block relative = block.getRelative(BlockFace.UP); + + if(relative.getType() == door) { + ProtocolUtils.removeBlockBreakAnimation(relative); + relative.removeMetadata(CREATURE_DOOR_BULLDOZER_METADATA, plugin); + } else if((relative = block.getRelative(BlockFace.DOWN)).getType() == door) { + ProtocolUtils.removeBlockBreakAnimation(relative); + relative.removeMetadata(CREATURE_DOOR_BULLDOZER_METADATA, plugin); + } + } + + private void doPerformDoorBreak(Block block, Material door) { + Location location = block.getLocation(); + VersionUtils.sendParticles("SMOKE_LARGE", null, location, 15, 0.1, 0.1, 0.1); + VersionUtils.sendParticles("EXPLOSION_HUGE", null, location, 1, 0.1, 0.1, 0.1); + + Block relative = block.getRelative(BlockFace.UP); + + //break order matters + if(relative.getType() == door) { + block.setType(Material.AIR); + relative.setType(Material.AIR); + } else if((relative = block.getRelative(BlockFace.DOWN)).getType() == door) { + relative.setType(Material.AIR); + block.setType(Material.AIR); + } + + VersionUtils.playSound(location, "ENTITY_ZOMBIE_BREAK_WOODEN_DOOR"); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewCreatureEvents.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewCreatureEvents.java new file mode 100644 index 000000000..992142d88 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewCreatureEvents.java @@ -0,0 +1,255 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.entity.EntityTargetLivingEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.jetbrains.annotations.Nullable; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; +import plugily.projects.villagedefense.kits.utils.KitHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class NewCreatureEvents implements Listener { + + private final Main plugin; + + public NewCreatureEvents(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onRetargetBlock(EntityTargetLivingEntityEvent event) { + if (event.getEntity().hasMetadata(NewEnemySpawnerManager.CREATURE_PERSISTENT_TARGETING) && event.getReason() != EntityTargetEvent.TargetReason.CUSTOM) { + event.setCancelled(true); + } + } + + @EventHandler + public void onCreatureDamagingEntity(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Creature yourself)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.isFighting()) { + continue; + } + VDEnemy enemy = NewCreatureUtils.getEnemyFromCreature(yourself); + if (enemy == null) { + return; + } + enemy.getOnDamaging().onDamaging(event, arena); + } + } + + @EventHandler + public void onEntityDamagingCreature(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Creature yourself)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.isFighting()) { + continue; + } + VDEnemy enemy = NewCreatureUtils.getEnemyFromCreature(yourself); + if (enemy == null) { + return; + } + enemy.getOnDamageBy().onBeingDamaged(event, arena); + } + } + + @EventHandler + public void onEntityDeath(EntityDeathEvent event) { + if (!(event.getEntity() instanceof Creature yourself)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.isFighting()) { + continue; + } + VDEnemy enemy = NewCreatureUtils.getEnemyFromCreature(yourself); + if (enemy == null) { + return; + } + enemy.getOnDeath().onDeath(event, arena); + } + } + + @EventHandler + public void onTntDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof TNTPrimed primed)) { + return; + } + if (!primed.hasMetadata("VD_PRIMED_TNT")) { + return; + } + if (NewCreatureUtils.isEnemy(event.getEntity())) { + event.setCancelled(true); + return; + } + if (!(event.getEntity() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user == null || user.getArena() == null) { + return; + } + if (primed.hasMetadata("VD_TNT_DAMAGE_PERCENT")) { + event.setDamage(0); + player.damage(0); + double percent = primed.getMetadata("VD_TNT_DAMAGE_PERCENT").get(0).asDouble(); + KitHelper.maxHealthPercentDamage(player, percent); + } + } + + //todo improve the code structure + @EventHandler + @Deprecated + public void onCreatureDeathEvent(EntityDeathEvent event) { + LivingEntity entity = event.getEntity(); + if (!(entity instanceof Creature creature)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getEnemies().contains(creature)) { + continue; + } + VDEnemy enemy = NewCreatureUtils.getEnemyFromCreature(creature); + if (enemy == null) { + continue; + } + arena.removeEnemy(creature); + arena.changeArenaOptionBy("TOTAL_KILLED_ZOMBIES", 1); + + Player killer = creature.getKiller(); + if (killer == null) { + killer = performKillerDetection(event); + } + applyKillMetadata(event); + Arena killerArena = plugin.getArenaRegistry().getArena(killer); + + if (killerArena != null) { + plugin.getUserManager().addStat(killer, plugin.getStatsStorage().getStatisticType("KILLS")); + plugin.getUserManager().addExperience(killer, (int) (2 * Math.log(arena.getWave()))); + plugin.getRewardsHandler().performReward(killer, plugin.getRewardsHandler().getRewardType("ZOMBIE_KILL")); + } + + event.setDroppedExp(0); + filterDrops(event, killer); + if (killer != null) { + User user = plugin.getUserManager().getUser(killer); + if (user == null || !user.getArena().equals(arena)) { + continue; + } + Map contribution = arena.getAssistHandler().doDistributeAssistRewards(killer, creature); + for (Map.Entry entry : contribution.entrySet()) { + double share = entry.getValue() / 100.0; + double multiplier = 1 + Math.log10(arena.getPlayers().size()); + int amount = (int) Math.ceil(10 * share * multiplier); + User targetUser = plugin.getUserManager().getUser(entry.getKey()); + targetUser.adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), amount); + } + } + } + } + + @Nullable + private Player performKillerDetection(EntityDeathEvent event) { + EntityDamageEvent cause = event.getEntity().getLastDamageCause(); + if (!(cause instanceof EntityDamageByEntityEvent)) { + return null; + } + Entity entity = ((EntityDamageByEntityEvent) cause).getDamager(); + if (entity instanceof Player) { + return (Player) entity; + } else if (entity instanceof Wolf || entity instanceof IronGolem) { + if (!entity.hasMetadata("VD_OWNER_UUID")) { + return null; + } + UUID uuid = UUID.fromString(entity.getMetadata("VD_OWNER_UUID").get(0).asString()); + return Bukkit.getServer().getPlayer(uuid); + } + return null; + } + + private void applyKillMetadata(EntityDeathEvent event) { + EntityDamageEvent cause = event.getEntity().getLastDamageCause(); + if (!(cause instanceof EntityDamageByEntityEvent)) { + return; + } + Entity entity = ((EntityDamageByEntityEvent) cause).getDamager(); + if (entity instanceof Wolf || entity instanceof IronGolem) { + if (!entity.hasMetadata("VD_OWNER_UUID")) { + return; + } + if (!entity.hasMetadata("VD_ENTITY_KILLS")) { + entity.setMetadata("VD_ENTITY_KILLS", new FixedMetadataValue(plugin, 1)); + } else { + int kills = entity.getMetadata("VD_ENTITY_KILLS").get(0).asInt(); + entity.removeMetadata("VD_ENTITY_KILLS", plugin); + entity.setMetadata("VD_ENTITY_KILLS", new FixedMetadataValue(plugin, kills + 1)); + } + } + } + + private void filterDrops(EntityDeathEvent event, Player player) { + List filtered = new ArrayList<>(); + for (ItemStack itemStack : event.getDrops()) { + if (itemStack == null || !XMaterial.ROTTEN_FLESH.isSimilar(itemStack)) { + continue; + } + itemStack.setAmount(1); + filtered.add(itemStack); + } + event.getDrops().clear(); + if (filtered.isEmpty() || player == null) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.isSpectator()) { + return; + } + player.getInventory().addItem(filtered.toArray(new ItemStack[]{})); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewCreatureUtils.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewCreatureUtils.java new file mode 100644 index 000000000..7f7da010b --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewCreatureUtils.java @@ -0,0 +1,264 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Wolf; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; +import plugily.projects.villagedefense.arena.midwave.PinataZombieEvent; +import plugily.projects.villagedefense.arena.midwave.RottenOfferEvent; +import plugily.projects.villagedefense.arena.villager.CompletionCallback; +import plugily.projects.villagedefense.handlers.upgrade.EntityUpgrade; + +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public class NewCreatureUtils { + + private static String[] villagerNames = ("Jagger,Kelsey,Kelton,Haylie,Harlow,Howard,Wulffric,Winfred,Ashley,Bailey,Beckett,Alfredo,Alfred,Adair,Edgar,ED,Eadwig,Edgaras,Buckley,Stanley,Nuffley," + + "Mary,Jeffry,Rosaly,Elliot,Harry,Sam,Rosaline,Tom,Ivan,Kevin,Adam,Emma,Mira,Jeff,Isac,Nico").split(","); + private static Main plugin; + + private NewCreatureUtils() { + } + + public static void init(Main plugin) { + NewCreatureUtils.plugin = plugin; + villagerNames = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_NAMES").asKey().build().split(","); + } + + /** + * Check if the given entity is a arena's enemy. + * We define the enemy as it's not the player, the villager, the wolf and the iron golem + * + * @param entity the entity + * @return true if it is + */ + //todo improve detection + public static boolean isEnemy(Entity entity) { + return entity instanceof Creature + && !(entity instanceof Player || entity instanceof Villager || entity instanceof Wolf + || entity instanceof IronGolem || entity.hasMetadata(PinataZombieEvent.PINATA_METADATA) + || entity.hasMetadata(RottenOfferEvent.ROTTEN_SALE_METADATA)); + } + + public static void doFrenzyEnemy(Creature creature, int seconds) { + if (creature.hasMetadata("VD_FRENZY") || creature.hasMetadata("VD_UNSTUNNABLE") || creature.hasMetadata("VD_ENEMY_ABILITY_CASTING")) { + return; + } + creature.setMetadata("VD_FRENZY", new FixedMetadataValue(plugin, true)); + doSetCustomNameTemporarily(creature, new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_ZOMBIE_FRENZY_NAME").asKey().build(), seconds * 20, () -> { + creature.removeMetadata("VD_FRENZY", plugin); + creature.setTarget(null); + }); + for (Entity entity : creature.getNearbyEntities(10, 10, 10)) { + if (isEnemy(entity)) { + Creature nearbyCreature = (Creature) entity; + if (nearbyCreature.hasMetadata(NewEnemySpawnerManager.CREATURE_ID_METADATA)) { + VDEnemy enemy = getEnemyFromCreature(nearbyCreature); + if (enemy != null) { + nearbyCreature.setTarget(creature.getTarget()); + } + } + } + } + } + + public static void doStunEnemy(Creature creature, int seconds) { + if (creature.hasMetadata("VD_STUNNED") || creature.hasMetadata("VD_UNSTUNNABLE") || creature.hasMetadata("VD_ENEMY_ABILITY_CASTING")) { + return; + } + creature.setMetadata("VD_STUNNED", new FixedMetadataValue(plugin, true)); + creature.setAI(false); + doSetCustomNameTemporarily(creature, new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_ZOMBIE_STUNNED_NAME").asKey().build(), seconds * 20, () -> { + creature.setAI(true); + creature.removeMetadata("VD_STUNNED", plugin); + }); + } + + public static void doSetCustomNameTemporarily(Creature creature, String customName, int ticks, CompletionCallback completionCallback) { + final String cachedName = creature.getMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA).get(0).asString(); + creature.setMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA, new FixedMetadataValue(plugin, customName)); + creature.setCustomName(getHealthNameTag(creature)); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + creature.setMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA, new FixedMetadataValue(plugin, cachedName)); + creature.setCustomName(getHealthNameTag(creature)); + completionCallback.onComplete(); + }, ticks); + } + + public static void doMarkPetDead(Creature creature) { + if (creature.hasMetadata("VD_PET_DEAD")) { + return; + } + creature.setMetadata("VD_PET_DEAD", new FixedMetadataValue(plugin, true)); + creature.setAI(false); + creature.setCustomName(ChatColor.translateAlternateColorCodes('&', "&8&lDEAD")); + } + + public static String getHealthNameTag(Creature creature) { + return getHealthNameTagPreDamage(creature, 0); + } + + /** + * In damage events, health is modified after all events are listened to + * we must apply health bar change pre damage event + * + * @param creature target to generate health bar for + * @param damage final damage taken by enemy before all events have finished + * @return health bar adjusted to the events' damage + */ + public static String getHealthNameTagPreDamage(Creature creature, double damage) { + double health = creature.getHealth() - damage; + if (health < 0) { + health = 0; + } + double maxHealth = creature.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue(); + ChatColor hpColor; + if (health >= maxHealth * 0.75) { + hpColor = ChatColor.GREEN; + } else if (health >= maxHealth * 0.5) { + hpColor = ChatColor.GOLD; + } else if (health >= maxHealth * 0.25) { + hpColor = ChatColor.YELLOW; + } else { + hpColor = ChatColor.RED; + } + if (creature instanceof Wolf || creature instanceof IronGolem) { + return renderPetHealthTag(creature, hpColor, health, maxHealth); + } + String name = creature.getMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA).get(0).asString(); + long rounded = Math.round(health); + String roundedStr = String.valueOf(rounded); + if (rounded == 0 && !creature.isDead()) { + roundedStr = "0.5"; + } + return ChatColor.GRAY + name + " " + hpColor + "" + ChatColor.BOLD + "" + roundedStr + ChatColor.GREEN + "" + ChatColor.BOLD + "/" + ChatColor.GREEN + "" + Math.round(maxHealth) + " ❤"; + } + + private static String renderPetHealthTag(Creature creature, ChatColor hpColor, double health, double maxHealth) { + UUID ownerId = UUID.fromString(creature.getMetadata("VD_OWNER_UUID").get(0).asString()); + Player player = Bukkit.getPlayer(ownerId); + long rounded = Math.round(health); + String roundedStr = String.valueOf(rounded); + if (rounded == 0 && !creature.isDead()) { + roundedStr = "0.5"; + } + String healthPlaceholder = hpColor + "" + ChatColor.BOLD + "" + roundedStr + ChatColor.GREEN + "" + ChatColor.BOLD + "/" + ChatColor.GREEN + Math.round(maxHealth) + " ❤"; + int totalLevel = 0; + for (EntityUpgrade entityUpgrade : plugin.getEntityUpgradeManager().getRegisteredUpgrades()) { + if (entityUpgrade.getApplicableEntity() == creature.getType() && creature.hasMetadata(entityUpgrade.getMetadataKey())) { + totalLevel++; + } + } + if (creature instanceof Wolf) { + String name = creature.getMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA).get(0).asString(); + if (((Wolf) creature).isAdult()) { + return ChatColor.GRAY + name + " " + healthPlaceholder; + } + return ChatColor.GRAY + name + ChatColor.GRAY + " (Baby) " + healthPlaceholder; + } + return new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_NAME").asKey().integer(totalLevel).player(player).value(healthPlaceholder).build(); + } + + public static String[] getVillagerNames() { + return villagerNames.clone(); + } + + public static String getRandomVillagerName() { + return getVillagerNames()[villagerNames.length == 1 ? 0 : ThreadLocalRandom.current().nextInt(villagerNames.length)]; + } + + public static Villager spawnVillager(Location location) { + Creature creature = (Creature) VersionUtils.spawnEntity(location, EntityType.VILLAGER); + creature.getAttribute(Attribute.GENERIC_FOLLOW_RANGE).setBaseValue(200D); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.3); + creature.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(25.0); + creature.setHealth(25.0); + creature.setRemoveWhenFarAway(false); + creature.setInvisible(false); + return (Villager) creature; + } + + public static IronGolem spawnIronGolem(Location location) { + Creature creature = (Creature) VersionUtils.spawnEntity(location, EntityType.IRON_GOLEM); + creature.getAttribute(Attribute.GENERIC_FOLLOW_RANGE).setBaseValue(200D); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.25); + creature.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(100.0); + creature.setHealth(100.0); + creature.setRemoveWhenFarAway(false); + creature.setInvisible(false); + return (IronGolem) creature; + } + + public static Wolf spawnWolf(Location location) { + Creature creature = (Creature) VersionUtils.spawnEntity(location, EntityType.WOLF); + creature.getAttribute(Attribute.GENERIC_FOLLOW_RANGE).setBaseValue(200D); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.25); + creature.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(30.0); + creature.setHealth(30.0); + creature.setRemoveWhenFarAway(false); + creature.setInvisible(false); + return (Wolf) creature; + } + + public static VDEnemy getEnemyFromCreature(Creature creature) { + if (!creature.hasMetadata(NewEnemySpawnerManager.CREATURE_ID_METADATA)) { + return null; + } + return JavaPlugin.getPlugin(Main.class) + .getNewEnemiesRegistry() + .getEnemyById( + creature + .getMetadata(NewEnemySpawnerManager.CREATURE_ID_METADATA) + .get(0) + .asString() + ); + } + + //todo retarget to focused targets + public static void unTargetPlayerFromZombies(Player player, Arena arena) { + for (Creature zombie : arena.getEnemies()) { + LivingEntity target = zombie.getTarget(); + + if (!player.equals(target)) { + continue; + } + //set new target as villager so zombies won't stay still waiting for nothing + zombie.setTarget(arena.getVillagers().get(arena.getPlugin().getRandom().nextInt(arena.getVillagers().size() - 1))); + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewEnemySpawnerManager.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewEnemySpawnerManager.java new file mode 100644 index 000000000..f90eb3352 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/NewEnemySpawnerManager.java @@ -0,0 +1,359 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffectType; +import plugily.projects.minigamesbox.classic.utils.configuration.ConfigUtils; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.ArmorPiece; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; + +@Slf4j +public class NewEnemySpawnerManager { + + public static final String CREATURE_ID_METADATA = "VD_CREATURE_ID"; + public static final String CREATURE_CUSTOM_NAME_METADATA = "VD_CREATURE_CUSTOM_NAME"; + public static final String CREATURE_PERSISTENT_TARGETING = "VD_CREATURE_PERSIST_TARGET"; + + private final Random random = new Random(); + private final Arena arena; + private final List glitchedEnemies = new ArrayList<>(); + private final Map enemyCheckerLocations = new HashMap<>(); + private Map> spawnsMap = new HashMap<>(); + private boolean spawning = false; + private int stage = 1; + private int stageCounter = 0; + private int stageCompleted = 0; + + public NewEnemySpawnerManager(Arena arena) { + this.arena = arena; + registerSpawnsMap(); + } + + private void registerSpawnsMap() { + FileConfiguration config = ConfigUtils.getConfig(arena.getPlugin(), "internal/enemies_map"); + for (String waveKey : config.getConfigurationSection("classic_gold").getKeys(false)) { + List waveEnemies = new LinkedList<>(); + int sumCount = 0; + for (String stageKey : config.getConfigurationSection("classic_gold." + waveKey).getKeys(false)) { + Map localSpawns = new HashMap<>(); + for (String zombieData : config.getStringList("classic_gold." + waveKey + "." + stageKey)) { + String zombieId = zombieData.split(";")[0]; + int count = Integer.parseInt(zombieData.split(";")[1]); + VDEnemy enemy = arena.getPlugin().getNewEnemiesRegistry().getEnemyById(zombieId); + if (enemy == null) { + log.warn("Enemy with id {} not found in registry!", zombieId); + continue; + } + localSpawns.put(enemy, count); + sumCount += count; + } + waveEnemies.add(new WaveEnemies(Integer.parseInt(stageKey), localSpawns)); + } + spawnsMap.put(Integer.parseInt(waveKey), waveEnemies); + log.info("Registered {} total enemies for wave {} at mode {}", sumCount, waveKey, "Classic Gold"); + } + } + + public boolean hasSpawningStarted() { + return spawning; + } + + public void doResetSpawnCheck() { + spawning = false; + stage = 1; + stageCounter = 0; + stageCompleted = 0; + } + + public void doSpawnEnemies() { + for (Creature creature : arena.getEnemies()) { + LivingEntity creatureTarget = creature.getTarget(); + VDEnemy enemy = NewCreatureUtils.getEnemyFromCreature(creature); + if (creatureTarget == null || creatureTarget.isDead()) { + setTargetPriority(enemy, creature); + } + } + doPetsTargeting(); + + if (!spawning) { + spawning = true; + } + if (stageCompleted != stage) { + for (WaveEnemies waveEnemies : spawnsMap.getOrDefault(arena.getWave(), new LinkedList<>())) { + if (waveEnemies.getStage() != stage) { + continue; + } + for (Map.Entry entry : waveEnemies.getEnemies().entrySet()) { + doSpawnEnemy(entry.getKey(), entry.getValue()); + } + } + } + stageCompleted = stage; + stageCounter++; + if (stageCounter >= 5) { + stageCounter = 0; + stage++; + } + } + + public int getEnemiesForWave(int wave) { + int count = 0; + for (WaveEnemies waveEnemies : spawnsMap.getOrDefault(wave, new ArrayList<>())) { + for (Map.Entry entry : waveEnemies.getEnemies().entrySet()) { + count += entry.getValue(); + } + } + return count; + } + + /** + * Spawns enemy outside zombie spawner manager, for example to be used for Pop Zombie that spawns bonus zombie on kill + */ + public Creature doSpawnEnemyOutsideManagement(VDEnemy enemy, Location location) { + Creature creature = doLocalSpawn(enemy, location); + arena.getPlugin().getHolidayManager().applyHolidayCreatureEffects(creature); + arena.getEnemies().add(creature); + return creature; + } + + private void doSpawnEnemy(VDEnemy enemy, int count) { + if (arena.getWave() < enemy.getWaveMinimum() || arena.getWave() > enemy.getWaveMaximum()) { + log.warn("Enemy spawned outside suggested wave limits! Wave {} but limited to {}-{}", arena.getWave(), enemy.getWaveMinimum(), enemy.getWaveMaximum()); + } + for (int i = 0; i < count; i++) { + Creature creature = doLocalSpawn(enemy, arena.getRandomZombieSpawnLocation(random)); + arena.getPlugin().getHolidayManager().applyHolidayCreatureEffects(creature); + arena.changeArenaOptionBy("ZOMBIES_TO_SPAWN", -1); + arena.setArenaOption("ZOMBIES_TO_SPAWN", arena.getArenaOption("ZOMBIES_TO_SPAWN") - 1); + arena.getEnemies().add(creature); + } + } + + //todo can spawn func + //todo damage scaling & with players + private Creature doLocalSpawn(VDEnemy enemy, Location location) { + Creature creature = (Creature) VersionUtils.spawnEntity(location, enemy.getType()); + creature.setMetadata(CREATURE_CUSTOM_NAME_METADATA, new FixedMetadataValue(arena.getPlugin(), ChatColor.translateAlternateColorCodes('&', enemy.getName()))); + creature.setMetadata(CREATURE_ID_METADATA, new FixedMetadataValue(arena.getPlugin(), enemy.getId())); + creature.setMetadata("VD_CUSTOM_ENTITY", new FixedMetadataValue(arena.getPlugin(), true)); + if (creature instanceof Ageable ageable) { + if (enemy.isBaby()) { + ageable.setBaby(); + } else { + ageable.setAdult(); + } + ageable.setAgeLock(true); + } + int wave = arena.getWave(); + creature.setCanPickupItems(false); + creature.getEquipment().clear(); + for (Map.Entry> entry : enemy.getWaveArmorPieces().entrySet()) { + List piecesOrdered = entry.getValue() + .stream() + .sorted(Comparator.comparing(ArmorPiece::getPriority).reversed()) + .toList(); + for (ArmorPiece piece : piecesOrdered) { + if (wave < piece.getWaveMinimum()) { + continue; + } + if (random.nextDouble(0, 100) > piece.getChance()) { + continue; + } + switch (entry.getKey()) { + case HELMET -> creature.getEquipment().setHelmet(piece.getItemStack()); + case CHESTPLATE -> creature.getEquipment().setChestplate(piece.getItemStack()); + case LEGGINGS -> creature.getEquipment().setLeggings(piece.getItemStack()); + case BOOTS -> creature.getEquipment().setBoots(piece.getItemStack()); + } + break; + } + } + if (enemy.isImpostorHead()) { + List players = new ArrayList<>(arena.getPlayers()); + Player randomPlayer = players.get(random.nextInt(players.size())); + ItemStack head = new ItemStack(Material.PLAYER_HEAD); + SkullMeta meta = (SkullMeta) head.getItemMeta(); + meta.setPlayerProfile(randomPlayer.getPlayerProfile()); + head.setItemMeta(meta); + creature.getEquipment().setHelmet(head); + } + for (VDEnemy.WeaponPiece piece : enemy.getWeaponParts()) { + if (wave >= piece.getWaveMinimum() && wave <= piece.getWaveMaximum()) { + VersionUtils.setItemInHand(creature, piece.getItemStack()); + } + } + enemy.getOnSpawn().accept(creature); + double baseHealth = enemy.getHealthFunction().apply(wave); + if (arena.getPlayers().size() > 1) { + baseHealth += baseHealth * (0.1 * (arena.getPlayers().size() - 1)); + } + creature.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(baseHealth); + creature.getAttribute(Attribute.GENERIC_FOLLOW_RANGE).setBaseValue(200D); + creature.setHealth(baseHealth); + creature.setRemoveWhenFarAway(false); + creature.setCustomNameVisible(true); + creature.setCustomName(NewCreatureUtils.getHealthNameTag(creature)); + setTargetPriority(enemy, creature); + if (enemy.isPersistentTargeting()) { + creature.setMetadata(CREATURE_PERSISTENT_TARGETING, new FixedMetadataValue(arena.getPlugin(), true)); + } + //todo door bulldozer trait + /*if(doorBulldozing) { + creature.setMetadata(DoorBreakListener.CREATURE_DOOR_BULLDOZER_METADATA, new FixedMetadataValue(arena.getPlugin(), true)); + }*/ + return creature; + } + + private void setTargetPriority(VDEnemy enemy, Creature creature) { + List targets = new ArrayList<>(); + if (enemy.getTargetPriority() == null) { + targets.addAll(arena.getVillagers()); + } else { + switch (enemy.getTargetPriority()) { + case VILLAGER -> targets.addAll(arena.getVillagers()); + case IRON_GOLEM -> targets.addAll( + arena.getIronGolems() + .stream() + .filter(golem -> !golem.hasMetadata("VD_PET_DEAD")) + .toList() + ); + case WOLF -> targets.addAll( + arena.getWolves() + .stream() + .filter(wolf -> !wolf.hasMetadata("VD_PET_DEAD")) + .toList() + ); + case PLAYER -> targets.addAll(arena.getPlayersLeft()); + } + } + LivingEntity nearestEntity = targets.get(0); + + Location location = creature.getLocation(); + for (LivingEntity entity : targets) { + double distance = location.distance(entity.getLocation()); + if (distance < location.distance(nearestEntity.getLocation())) { + nearestEntity = entity; + } + } + creature.setTarget(nearestEntity); + } + + private void doPetsTargeting() { + List pets = new ArrayList<>(); + pets.addAll(arena.getWolves()); + pets.addAll(arena.getIronGolems()); + if (arena.getEnemies().isEmpty()) { + return; + } + List targets = arena.getEnemies() + .stream() + .filter(enemy -> !enemy.hasPotionEffect(PotionEffectType.INVISIBILITY)) + .toList(); + for (Creature pet : pets) { + LivingEntity currentTarget = pet.getTarget(); + if (!NewCreatureUtils.isEnemy(currentTarget)) { + pet.setTarget(targets.get(targets.size() > 1 ? random.nextInt(targets.size() - 1) : 0)); + } + } + } + + /** + * Increments ZOMBIE_GLITCH_CHECKER value and attempts to check + * whether any enemies are glitched on spawn point when + * ZOMBIE_GLITCH_CHECKER value is higher or equal than 60 + *

+ * Glitch checker also clean ups dead enemies and villagers from the arena + */ + public void doGlitchCheck() { + arena.changeArenaOptionBy("ZOMBIE_GLITCH_CHECKER", 1); + if (arena.getArenaOption("ZOMBIE_GLITCH_CHECKER") >= 60) { + Iterator villagerIterator = arena.getVillagers().iterator(); + while (villagerIterator.hasNext()) { + Villager villager = villagerIterator.next(); + if (villager.isDead()) { + villagerIterator.remove(); + arena.removeVillager(villager); + } + } + arena.setArenaOption("ZOMBIE_GLITCH_CHECKER", 0); + + Iterator creatureIterator = arena.getEnemies().iterator(); + while (creatureIterator.hasNext()) { + Creature creature = creatureIterator.next(); + if (creature.isDead()) { + creatureIterator.remove(); + arena.removeEnemy(creature); + continue; + } + if (glitchedEnemies.contains(creature) && creature.getLocation().distance(enemyCheckerLocations.get(creature)) <= 1) { + creatureIterator.remove(); + arena.removeEnemy(creature); + enemyCheckerLocations.remove(creature); + creature.remove(); + } + + Location checkerLoc = enemyCheckerLocations.get(creature); + if (checkerLoc == null) { + enemyCheckerLocations.put(creature, creature.getLocation()); + } else if (creature.getLocation().distance(checkerLoc) <= 1) { + VersionUtils.teleport(creature, arena.getRandomZombieSpawnLocation(arena.getPlugin().getRandom())); + enemyCheckerLocations.put(creature, creature.getLocation()); + glitchedEnemies.add(creature); + } + } + } + } + + @Data + @AllArgsConstructor + public static class WaveEnemies { + + private int stage; + private Map enemies; + + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/RideableCreatureEvents.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/RideableCreatureEvents.java new file mode 100644 index 000000000..468c79d94 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/RideableCreatureEvents.java @@ -0,0 +1,102 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.ListenerPriority; +import com.comphenix.protocol.events.PacketAdapter; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Wolf; +import org.bukkit.util.Vector; +import plugily.projects.villagedefense.Main; + +/** + * @author Plajer + *

+ * Created at 04.08.2023 + */ +public class RideableCreatureEvents { + + public RideableCreatureEvents(Main plugin) { + if(plugin.getServer().getPluginManager().getPlugin("ProtocolLib") == null) { + return; + } + ProtocolManager manager = ProtocolLibrary.getProtocolManager(); + manager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.STEER_VEHICLE) { + @Override + public void onPacketReceiving(PacketEvent event) { + handlePreSteer(event); + } + }); + } + + private void handlePreSteer(PacketEvent event) { + Entity vehicle = event.getPlayer().getVehicle(); + if (!(vehicle instanceof Villager) && !(vehicle instanceof IronGolem) && !(vehicle instanceof Wolf)) { + return; + } + handleSteer(event, vehicle); + } + + private void handleSteer(PacketEvent event, Entity vehicle) { + Player player = event.getPlayer(); + PacketContainer packet = event.getPacket(); + //https://wiki.vg/Protocol#Player_Input + float sideways = packet.getFloat().read(0); + float forward = packet.getFloat().read(1); + boolean jump = packet.getBooleans().read(0); + boolean unmount = packet.getBooleans().read(1); + if(unmount) { + return; + } + Location location = player.getLocation(); + double radians = Math.toRadians(location.getYaw()); + double x = -forward * Math.sin(radians) + sideways * Math.cos(radians); + double z = forward * Math.cos(radians) + sideways * Math.sin(radians); + double multiplier = 0.4; + if (vehicle instanceof Villager) { + multiplier = 0.25; + } + Vector velocity = new Vector(x, 0.0, z).normalize().multiply(multiplier); + velocity.setY(vehicle.getVelocity().getY()); + if(!Double.isFinite(velocity.getX())) { + velocity.setX(0); + } + if(!Double.isFinite(velocity.getZ())) { + velocity.setZ(0); + } + if(jump && vehicle.isOnGround()) { + velocity.setY(0.45); + } + try { + velocity.checkFinite(); + vehicle.setVelocity(velocity); + } catch(Exception ignored) { + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/ArmorPiece.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/ArmorPiece.java new file mode 100644 index 000000000..cf2a9d4e6 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/ArmorPiece.java @@ -0,0 +1,60 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.bukkit.Color; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.LeatherArmorMeta; + +@Data +@Accessors(chain = true) +public class ArmorPiece { + private int waveMinimum; + private int priority = 1; + private double chance = 100; + private ItemStack itemStack; + + public ArmorPiece withEnchants(Enchant... enchants) { + for (Enchant enchant : enchants) { + this.itemStack.addUnsafeEnchantment(enchant.enchantment(), enchant.level()); + } + return this; + } + + public ArmorPiece withArmorDye(Color color) { + ItemMeta meta = itemStack.getItemMeta(); + if (!(meta instanceof LeatherArmorMeta leatherArmorMeta)) { + return this; + } + leatherArmorMeta.setColor(color); + itemStack.setItemMeta(meta); + return this; + } + + public enum PiecePart { + HELMET, CHESTPLATE, LEGGINGS, BOOTS + } + + public record Enchant(Enchantment enchantment, int level) { + } +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/EnemiesRegistry.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/EnemiesRegistry.java new file mode 100644 index 000000000..46d0be0d8 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/EnemiesRegistry.java @@ -0,0 +1,433 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy; + +import lombok.SneakyThrows; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.attribute.Attribute; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureEvents; +import plugily.projects.villagedefense.arena.managers.spawner.gold.RideableCreatureEvents; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type.BlinkerZombie; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type.GravityZombie; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type.PopZombie; +import plugily.projects.villagedefense.kits.utils.KitHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class EnemiesRegistry { + + private final Set registeredEnemies = new HashSet<>(); + private final Main plugin; + + public EnemiesRegistry(Main plugin) { + this.plugin = plugin; + registerEnemies(); + registerNewEnemies(); + } + + private void registerNewEnemies() { + registeredEnemies.add(new BlinkerZombie().getEnemy()); + registeredEnemies.add(new GravityZombie().getEnemy()); + registeredEnemies.add(new PopZombie().getEnemy()); + } + + public void registerEnemies() { + new NewCreatureEvents(plugin); + new RideableCreatureEvents(plugin); + registeredEnemies.add( + new VDEnemyBuilder("VD_ZOMBIE") + .withName("Zombie") + .withWaveMinimum(0) + .withWaveMaximum(50) + .withFullArmor(VDEnemyBuilder.ArmorType.LEATHER, 11, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.GOLD, 16, 2) + .withFullArmor(VDEnemyBuilder.ArmorType.CHAINMAIL, 26, 3) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 36, 4) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 41, 5, 75.0, new ArmorPiece.Enchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1)) + .withFullArmor(VDEnemyBuilder.ArmorType.DIAMOND, 46, 6, 35.0) + .withScalingHealth(wave -> { + if (wave <= 15) { + return 20.0; + } + return 20.0 + ((wave - 15) * 2.0); + }) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_HORDE_ZOMBIE") + .withName("Horde Zombie") + .withWaveMinimum(10) + .withWaveMaximum(40) + .withFullArmor(VDEnemyBuilder.ArmorType.LEATHER, 26) + .withScalingHealth(wave -> { + if (wave <= 15) { + return 20.0; + } + return 20.0 + ((wave - 15) * 1.5); + }) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_BABY_ZOMBIE") + .withName("Baby Zombie") + .withWaveMinimum(3) + .withWaveMaximum(35) + .setBaby() + .withScalingHealth(wave -> 3.0) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE).setBaseValue(2.0); + creature.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(5.0); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_PLAYER_BUSTER") + .withName("Player Buster") + .withWaveMinimum(6) + .withWaveMaximum(35) + .withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.TNT)).setWaveMinimum(6)) + .withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_CHESTPLATE)).setWaveMinimum(6)) + .withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_LEGGINGS)).setWaveMinimum(6)) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_BOOTS)).setWaveMinimum(6)) + .withScalingHealth(wave -> 1.0) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }) + .onDamageByEntity((event, arena) -> { + if (!(event.getDamager() instanceof Player player)) { + return; + } + event.setCancelled(true); + Creature yourself = (Creature) event.getEntity(); + yourself.setInvulnerable(true); + yourself.setAI(false); + yourself.getWorld().playSound(yourself.getLocation(), Sound.ENTITY_TNT_PRIMED, 1, 0.75f); + new BukkitRunnable() { + boolean toggle = false; + int ticks = 0; + + @SneakyThrows + @Override + public void run() { + if (ticks >= 40) { + yourself.getWorld().spawnParticle(Particle.EXPLOSION_HUGE, yourself.getLocation().add(0, 0.5, 0), 2); + for (Entity nearby : yourself.getNearbyEntities(3, 3, 3)) { + if (!(nearby instanceof Player nearbyPlayer)) { + continue; + } + nearbyPlayer.playSound(nearbyPlayer, Sound.ENTITY_GENERIC_EXPLODE, 1, 1.5f); + nearbyPlayer.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 20 * 5, 0)); + nearbyPlayer.addPotionEffect(new PotionEffect(PotionEffectType.CONFUSION, 20 * 6, 0)); + nearbyPlayer.damage(0, yourself); + KitHelper.maxHealthPercentDamage(player, yourself, 12.5); + } + yourself.remove(); + yourself.setKiller(player); + Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent(yourself, new ArrayList<>(Collections.singletonList(new ItemStack(Material.ROTTEN_FLESH))))); + cancel(); + return; + } + ChatColor color = toggle ? ChatColor.YELLOW : ChatColor.RED; + for (Player targetPlayer : arena.getPlayers()) { + plugin.getGlowingEntities().setGlowing(yourself, targetPlayer, color); + } + toggle = !toggle; + ticks += 10; + } + }.runTaskTimer(plugin, 0, 10); + }) + .build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_RUNNER_ZOMBIE") + .withName("Runner Zombie") + .withWaveMinimum(10) + .withWaveMaximum(25) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_BOOTS)).setWaveMinimum(10).setPriority(1)) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_BOOTS)).setWaveMinimum(16).setPriority(2)) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_BOOTS)).setWaveMinimum(21).setPriority(3)) + .withScalingHealth(wave -> { + if (wave <= 15) { + return 15.0; + } + return 15.0 + ((wave - 15) * 1.75); + }) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.26); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_MEDIUM_ZOMBIE") + .withName("Medium Zombie") + .withWaveMinimum(5) + .withWaveMaximum(30) + .withFullArmor(VDEnemyBuilder.ArmorType.LEATHER, 5, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.GOLD, 11, 2) + .withFullArmor(VDEnemyBuilder.ArmorType.CHAINMAIL, 16, 3) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 26, 4) + .withScalingHealth(wave -> { + if (wave <= 15) { + return 20.0; + } + return 20.0 + ((wave - 15) * 2.25); + }) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_GOLEM_BUSTER") + .withName("Golem Buster") + .withWaveMinimum(10) + .withWaveMaximum(35) + .withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.TNT)).setWaveMinimum(10)) + .withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_CHESTPLATE)).setWaveMinimum(10)) + .withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_CHESTPLATE)).setWaveMinimum(10)) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_CHESTPLATE)).setWaveMinimum(10)) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(15.0); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }) + .onDamageByEntity((event, arena) -> { + if (!(event.getDamager() instanceof IronGolem ironGolem)) { + return; + } + Creature yourself = (Creature) event.getEntity(); + ironGolem.damage(20.0); + yourself.getWorld().spawnParticle(Particle.EXPLOSION_HUGE, yourself.getLocation().add(0, 0.5, 0), 2); + for (Player player : arena.getPlayers()) { + player.playSound(ironGolem.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1, 1); + } + yourself.remove(); + Player owner = Bukkit.getPlayer(UUID.fromString(ironGolem.getMetadata("VD_OWNER_UUID").get(0).asString())); + yourself.setKiller(owner); + Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent(yourself, new ArrayList<>(Collections.singletonList(new ItemStack(Material.ROTTEN_FLESH))))); + }) + .canSpawn(arena -> !arena.getIronGolems().isEmpty()) + .build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_HARD_ZOMBIE") + .withName("Hard Zombie") + .withWaveMinimum(15) + .withWaveMaximum(35) + .withFullArmor(VDEnemyBuilder.ArmorType.GOLD, 15, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.CHAINMAIL, 21, 2) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 26, 3) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 31, 4, 75.0, new ArmorPiece.Enchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1)) + .withScalingHealth(wave -> 20.0 + ((wave - 15) * 2.5)) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_TANK_ZOMBIE") + .withName("Tank Zombie") + .withWaveMinimum(20) + .withWaveMaximum(40) + .withFullArmor(VDEnemyBuilder.ArmorType.CHAINMAIL, 20, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 26, 2) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 31, 3, 75.0, new ArmorPiece.Enchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1)) + .withFullArmor(VDEnemyBuilder.ArmorType.DIAMOND, 36, 4, 35.0) + .withScalingHealth(wave -> { + return 20.0 + ((wave - 15) * 3.0); + }) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_INVISIBLE_BABY_ZOMBIE") + .withName("Invisible Baby") + .withWaveMinimum(36) + .withWaveMaximum(50) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_BOOTS)).setWaveMinimum(36)) + .setBaby() + .withScalingHealth(wave -> 3.0) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE).setBaseValue(2.0); + creature.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(5.0); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }) + .onSpawn(creature -> creature.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false))).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_KAMIKAZE_ZOMBIE") + .withName("Kamikaze Zombie") + .withWaveMinimum(25) + .withWaveMaximum(50) + .withTargetPriority(EntityType.PLAYER) + .withPersistentTargeting() + .withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.TNT)).withArmorDye(Color.BLACK).setWaveMinimum(25)) + .withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_CHESTPLATE)).withArmorDye(Color.BLACK).setWaveMinimum(25)) + .withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_LEGGINGS)).withArmorDye(Color.BLACK).setWaveMinimum(25)) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_BOOTS)).withArmorDye(Color.BLACK).setWaveMinimum(25)) + .withScalingHealth(wave -> 5.0) + .onDamagingEntity((event, arena) -> { + if (!(event.getEntity() instanceof Player player)) { + return; + } + Creature yourself = (Creature) event.getDamager(); + TNTPrimed primed = (TNTPrimed) yourself.getWorld().spawnEntity(yourself.getLocation(), EntityType.PRIMED_TNT); + primed.setSource(yourself); + primed.setMetadata("VD_PRIMED_TNT", new FixedMetadataValue(arena.getPlugin(), true)); + primed.setMetadata("VD_TNT_DAMAGE_PERCENT", new FixedMetadataValue(arena.getPlugin(), 20.0)); + primed.setFuseTicks(65); + yourself.remove(); + yourself.setKiller(player); + Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent(yourself, new ArrayList<>(Collections.singletonList(new ItemStack(Material.ROTTEN_FLESH))))); + new BukkitRunnable() { + boolean toggle = false; + int ticks = 0; + + @SneakyThrows + @Override + public void run() { + if (ticks >= 60) { + cancel(); + return; + } + ChatColor color = toggle ? ChatColor.YELLOW : ChatColor.RED; + for (Player targetPlayer : arena.getPlayers()) { + plugin.getGlowingEntities().setGlowing(primed, targetPlayer, color); + } + toggle = !toggle; + ticks += 10; + } + }.runTaskTimer(plugin, 0, 10); + }) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.32); + }) + .build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_INVISIBLE_RUNNER_ZOMBIE") + .withName("Invisible Runner") + .withWaveMinimum(30) + .withWaveMaximum(50) + .withScalingHealth(wave -> 15.0 + ((wave - 15) * 1.75)) + .withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_LEGGINGS)).setWaveMinimum(30)) + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_BOOTS)).setWaveMinimum(30)) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.26); + creature.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_CONQUEROR_ZOMBIE") + .withName("Conqueror Zombie") + .withWaveMinimum(36) + .withWaveMaximum(50) + .setImpostorHead() + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 36, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 41, 2, 75.0, new ArmorPiece.Enchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1)) + .withFullArmor(VDEnemyBuilder.ArmorType.DIAMOND, 46, 3, 35.0) + .withScalingHealth(wave -> 25.0 + ((wave - 15) * 2.75)) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_CONQUEROR_BOSS_ZOMBIE") + .withName("Conqueror Zombie (&7&l✶&f)") + .withWaveMinimum(36) + .withWaveMaximum(50) + .setImpostorHead() + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 36, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.IRON, 41, 2, 75.0, new ArmorPiece.Enchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1)) + .withFullArmor(VDEnemyBuilder.ArmorType.DIAMOND, 46, 3, 35.0) + .withScalingHealth(wave -> 25.0 + ((wave - 15) * 2.75)) + .onSpawn(creature -> { + creature.setMetadata("VD_UNSTUNNABLE", new FixedMetadataValue(plugin, true)); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + creature.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE).setBaseValue(1); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_VILLAGER_SLAYER") + .withName("Villager Slayer (&4&l☄ &7&l✶&f)") + .withWaveMinimum(45) + .withWaveMaximum(50) + .withTargetPriority(EntityType.VILLAGER) + .withPersistentTargeting() + .withFullArmor(VDEnemyBuilder.ArmorType.CHAINMAIL, 45, 1) + .withFullArmor(VDEnemyBuilder.ArmorType.CHAINMAIL, 45, 2, 75.0, new ArmorPiece.Enchant(Enchantment.PROTECTION_ENVIRONMENTAL, 1)) + .withScalingHealth(wave -> 35.0 + ((wave - 15) * 2.75)) + .onSpawn(creature -> { + creature.setMetadata("VD_UNSTUNNABLE", new FixedMetadataValue(plugin, true)); + creature.setMetadata("VD_UNPOPPABLE", new FixedMetadataValue(plugin, true)); + creature.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE).setBaseValue(1.0); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + registeredEnemies.add( + new VDEnemyBuilder("VD_INVISIBLE_VILLAGER_SLAYER") + .withName("Invisible Slayer (&4&l☄ &7&l✶&f)") + .withWaveMinimum(50) + .withWaveMaximum(50) + .withTargetPriority(EntityType.VILLAGER) + .withPersistentTargeting() + .withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_BOOTS)).setWaveMinimum(50)) + .withScalingHealth(wave -> 35.0 + ((wave - 15) * 2.75)) + .onSpawn(creature -> { + creature.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 0, false, false)); + creature.setMetadata("VD_UNSTUNNABLE", new FixedMetadataValue(plugin, true)); + creature.setMetadata("VD_UNPOPPABLE", new FixedMetadataValue(plugin, true)); + creature.getAttribute(Attribute.GENERIC_KNOCKBACK_RESISTANCE).setBaseValue(1.0); + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }).build() + ); + } + + public VDEnemy getEnemyById(String id) { + return registeredEnemies.stream() + .filter(e -> e.getId().equals(id)) + .findFirst() + .orElse(null); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VDEnemy.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VDEnemy.java new file mode 100644 index 000000000..4960fc7c2 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VDEnemy.java @@ -0,0 +1,96 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.bukkit.entity.Creature; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; +import plugily.projects.villagedefense.arena.Arena; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +@Getter +@Setter +public class VDEnemy { + + private String id; + private String name; + private EntityType type = EntityType.ZOMBIE; + private EntityType targetPriority = null; + private boolean persistentTargeting = false; + private int waveMinimum; + private int waveMaximum; + private Map> waveArmorPieces = new HashMap<>(); + private List weaponParts = new ArrayList<>(); + + private boolean baby = false; + private boolean impostorHead = false; + + private Function canSpawn = arena -> true; + private Consumer onSpawn; + private Function healthFunction = wave -> 21.0; + private OnDeathFunction onDeath = (event, arena) -> { + }; + private OnDamageByFunction onDamageBy = (event, arena) -> { + }; + private OnDamagingEntityFunction onDamaging = (event, arena) -> { + }; + private OnAbilityTickFunction onAbilityTick = (creature, arena) -> { + }; + + @FunctionalInterface + public interface OnDeathFunction { + void onDeath(EntityDeathEvent event, Arena arena); + } + + @FunctionalInterface + public interface OnDamageByFunction { + void onBeingDamaged(EntityDamageByEntityEvent event, Arena arena); + } + + @FunctionalInterface + public interface OnDamagingEntityFunction { + void onDamaging(EntityDamageByEntityEvent event, Arena arena); + } + + @FunctionalInterface + public interface OnAbilityTickFunction { + void onAbilityTick(Creature creature, Arena arena); + } + + @Data + @Accessors(chain = true) + public static class WeaponPiece { + private int waveMinimum; + private int waveMaximum; + private ItemStack itemStack; + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VDEnemyBuilder.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VDEnemyBuilder.java new file mode 100644 index 000000000..02d61780d --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VDEnemyBuilder.java @@ -0,0 +1,226 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy; + +import org.bukkit.Material; +import org.bukkit.entity.Creature; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import plugily.projects.villagedefense.arena.Arena; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.function.Function; + +public class VDEnemyBuilder { + + private final VDEnemy vdEnemy = new VDEnemy(); + + public VDEnemyBuilder(String id) { + vdEnemy.setId(id); + } + + public VDEnemyBuilder withName(String name) { + vdEnemy.setName(name); + return this; + } + + public VDEnemyBuilder withTargetPriority(EntityType priority) { + vdEnemy.setTargetPriority(priority); + return this; + } + + public VDEnemyBuilder withPersistentTargeting() { + vdEnemy.setPersistentTargeting(true); + return this; + } + + public VDEnemyBuilder withWaveMinimum(int waveMinimum) { + vdEnemy.setWaveMinimum(waveMinimum); + return this; + } + + public VDEnemyBuilder withWaveMaximum(int waveMaximum) { + vdEnemy.setWaveMaximum(waveMaximum); + return this; + } + + public VDEnemyBuilder withFullArmor(ArmorType armorType, int waveMin) { + return withFullArmor(armorType, waveMin, 1, 100); + } + + public VDEnemyBuilder withFullArmor(ArmorType armorType, int waveMin, int priority) { + return withFullArmor(armorType, waveMin, priority, 100); + } + + public VDEnemyBuilder withFullArmor(ArmorType armorType, int waveMin, int priority, double chance) { + switch (armorType) { + case LEATHER -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_HELMET)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_CHESTPLATE)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_LEGGINGS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_BOOTS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case CHAINMAIL -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_HELMET)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_CHESTPLATE)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_LEGGINGS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_BOOTS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case GOLD -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_HELMET)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_CHESTPLATE)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_LEGGINGS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_BOOTS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case IRON -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_HELMET)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_CHESTPLATE)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_LEGGINGS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_BOOTS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case DIAMOND -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_HELMET)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_CHESTPLATE)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_LEGGINGS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_BOOTS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case NETHERITE -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_HELMET)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_CHESTPLATE)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_LEGGINGS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_BOOTS)).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + } + return this; + } + + public VDEnemyBuilder withFullArmor(ArmorType armorType, int waveMin, int priority, ArmorPiece.Enchant... enchants) { + return withFullArmor(armorType, waveMin, priority, 100, enchants); + } + + public VDEnemyBuilder withFullArmor(ArmorType armorType, int waveMin, int priority, double chance, ArmorPiece.Enchant... enchants) { + switch (armorType) { + case LEATHER -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_HELMET)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_CHESTPLATE)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_LEGGINGS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.LEATHER_BOOTS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case CHAINMAIL -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_HELMET)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_CHESTPLATE)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_LEGGINGS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.CHAINMAIL_BOOTS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case GOLD -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_HELMET)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_CHESTPLATE)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_LEGGINGS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.GOLDEN_BOOTS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case IRON -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_HELMET)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_CHESTPLATE)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_LEGGINGS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.IRON_BOOTS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case DIAMOND -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_HELMET)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_CHESTPLATE)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_LEGGINGS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.DIAMOND_BOOTS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + case NETHERITE -> { + withArmorPiece(ArmorPiece.PiecePart.HELMET, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_HELMET)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.CHESTPLATE, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_CHESTPLATE)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.LEGGINGS, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_LEGGINGS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + withArmorPiece(ArmorPiece.PiecePart.BOOTS, new ArmorPiece().setItemStack(new ItemStack(Material.NETHERITE_BOOTS)).withEnchants(enchants).setWaveMinimum(waveMin).setPriority(priority).setChance(chance)); + } + } + return this; + } + + public VDEnemyBuilder withArmorPiece(ArmorPiece.PiecePart part, ArmorPiece piece) { + vdEnemy.getWaveArmorPieces().computeIfAbsent(part, v -> new ArrayList<>()).add(piece); + return this; + } + + public VDEnemyBuilder withWeaponPiece(VDEnemy.WeaponPiece piece) { + vdEnemy.getWeaponParts().add(piece); + return this; + } + + /** + * Head of the entity will be one of playing players instead of armor part + */ + public VDEnemyBuilder setImpostorHead() { + vdEnemy.setImpostorHead(true); + return this; + } + + public VDEnemyBuilder setBaby() { + vdEnemy.setBaby(true); + return this; + } + + public VDEnemyBuilder canSpawn(Function canSpawn) { + vdEnemy.setCanSpawn(canSpawn); + return this; + } + + public VDEnemyBuilder withScalingHealth(Function scalingHealth) { + vdEnemy.setHealthFunction(scalingHealth); + return this; + } + + public VDEnemyBuilder onSpawn(Consumer onSpawn) { + vdEnemy.setOnSpawn(onSpawn); + return this; + } + + public VDEnemyBuilder onDeath(VDEnemy.OnDeathFunction onDeath) { + vdEnemy.setOnDeath(onDeath); + return this; + } + + public VDEnemyBuilder onDamageByEntity(VDEnemy.OnDamageByFunction onDamageByEntity) { + vdEnemy.setOnDamageBy(onDamageByEntity); + return this; + } + + public VDEnemyBuilder onDamagingEntity(VDEnemy.OnDamagingEntityFunction onDamaging) { + vdEnemy.setOnDamaging(onDamaging); + return this; + } + + public VDEnemyBuilder onAbilityTick(VDEnemy.OnAbilityTickFunction onAbilityTick) { + vdEnemy.setOnAbilityTick(onAbilityTick); + return this; + } + + public VDEnemy build() { + return vdEnemy; + } + + public enum ArmorType { + LEATHER, CHAINMAIL, GOLD, IRON, DIAMOND, NETHERITE + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VdEnemyAbilityHandler.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VdEnemyAbilityHandler.java new file mode 100644 index 000000000..7495a8a92 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/VdEnemyAbilityHandler.java @@ -0,0 +1,46 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy; + +import org.bukkit.entity.Entity; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import plugily.projects.villagedefense.Main; + +public class VdEnemyAbilityHandler { + + public static boolean canCastAbility(Entity entity) { + return entity.getMetadata("VD_ENEMY_ABILITY_COOLDOWN").isEmpty(); + } + + public static int increaseVariable(Entity entity, String key) { + if (entity.getMetadata(key).isEmpty()) { + entity.setMetadata(key, new FixedMetadataValue(JavaPlugin.getProvidingPlugin(Main.class), 1)); + return 1; + } + int value = entity.getMetadata(key).get(0).asInt() + 1; + entity.setMetadata(key, new FixedMetadataValue(JavaPlugin.getProvidingPlugin(Main.class), value)); + return value; + } + + public static void resetVariable(Entity entity, String key) { + entity.removeMetadata(key, JavaPlugin.getProvidingPlugin(Main.class)); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/BlinkerZombie.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/BlinkerZombie.java new file mode 100644 index 000000000..e96c1d189 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/BlinkerZombie.java @@ -0,0 +1,160 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.utils.version.xseries.ParticleDisplay; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemyBuilder; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VdEnemyAbilityHandler; +import plugily.projects.villagedefense.arena.villager.VillagerAiAnimations; + +import java.util.concurrent.ThreadLocalRandom; + +public class BlinkerZombie implements RegistrableZombie { + + private final Main plugin = JavaPlugin.getPlugin(Main.class); + + @Override + public VDEnemy getEnemy() { + return new VDEnemyBuilder("VD_BLINKER_ZOMBIE") + .withName("Blinker Zombie") + .withWaveMinimum(0) + .withWaveMaximum(50) + .withFullArmor(VDEnemyBuilder.ArmorType.LEATHER, 0, 1) + .withScalingHealth(wave -> 25.0) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }) + .onDamageByEntity((event, arena) -> { + Player player; + if (!(event.getDamager() instanceof Player damager)) { + if (event.getDamager() instanceof Arrow arrow) { + player = (Player) arrow.getShooter(); + } else { + return; + } + } else { + player = damager; + } + Entity entity = event.getEntity(); + int value = VdEnemyAbilityHandler.increaseVariable(entity, "VD_ENEMY_ABILITY_RAGE"); + if (value >= 6) { + if (value % 3 == 0) { + doPrepareBlink((Creature) entity, player, player.getLocation().distanceSquared(entity.getLocation()) > 8); + } + } else { + if (value % 2 == 0) { + doPrepareBlink((Creature) entity, player, player.getLocation().distanceSquared(entity.getLocation()) > 8); + } + } + }).build(); + } + + private void doPrepareBlink(Creature creature, Player player, boolean fast) { + if (creature.isDead() || creature.getHealth() <= 0) { + return; + } + if (creature.hasMetadata("VD_ENEMY_ABILITY_CASTING")) { + return; + } + //save location before blink for a chance to dodge + Location loc = findNearestAirBehind(player); + if (loc == null) { + loc = player.getLocation(); + } + final Location finalLoc = loc; + NewCreatureUtils.doSetCustomNameTemporarily(creature, ChatColor.translateAlternateColorCodes('&', "&9&lBLINKING"), (fast ? 7 : 15), () -> { + if (creature.isDead()) { + return; + } + creature.setAI(true); + creature.removeMetadata("VD_ENEMY_ABILITY_CASTING", plugin); + creature.teleport(finalLoc); + creature.setTarget(player); + creature.getWorld().playSound(creature.getLocation(), XSound.ENTITY_ENDERMAN_TELEPORT.parseSound(), 1.0F, 1.0F); + }); + creature.setMetadata("VD_ENEMY_ABILITY_CASTING", new FixedMetadataValue(plugin, true)); + creature.setAI(false); + creature.getWorld().playSound(creature.getLocation(), XSound.ENTITY_EVOKER_PREPARE_SUMMON.parseSound(), 1.0F, 1.6F); + new BukkitRunnable() { + final Location location = creature.getLocation(); + int ticks = 0; + + @Override + public void run() { + if (ticks >= (fast ? 7 : 15) || creature.isDead()) { + cancel(); + return; + } + if (ticks % (fast ? 2 : 5) == 0) { + creature.swingMainHand(); + VillagerAiAnimations.makeEntityLookAt(creature, location + .clone() + .add( + location.getDirection().getX() * 0.5, + -0.15, + location.getDirection().getZ() * 0.5 + )); + } + XParticle.circle(1.4, 13, ParticleDisplay.simple(location, Particle.ENCHANTMENT_TABLE)); + location.setY(location.getY() + (fast ? 0.3 : 0.15)); + ticks += 1; + } + }.runTaskTimer(plugin, 0, 1); + } + + private Location findNearestAirBehind(Player player) { + Location loc = player.getLocation(); + Vector direction = loc.getDirection().setY(0).normalize().multiply(-1); + + int offset = ThreadLocalRandom.current().nextInt(0, 1); + for (int i = 2 + offset; i <= 5 + offset; i++) { + Location checkLoc = loc.clone().add(direction.clone().multiply(i)); + if (isSafeLocation(checkLoc)) { + return checkLoc; + } + } + + return null; + } + + private boolean isSafeLocation(Location loc) { + return loc.getBlock().getType() == Material.AIR && + loc.clone().add(0, 1, 0).getBlock().getType() == Material.AIR && + loc.clone().add(0, -1, 0).getBlock().getType().isSolid(); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/GravityZombie.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/GravityZombie.java new file mode 100644 index 000000000..839b04e16 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/GravityZombie.java @@ -0,0 +1,136 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type; + +import fr.skytasul.guardianbeam.Laser; +import lombok.SneakyThrows; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemyBuilder; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VdEnemyAbilityHandler; +import plugily.projects.villagedefense.arena.villager.VillagerAiAnimations; + +public class GravityZombie implements RegistrableZombie { + + private final Main plugin = JavaPlugin.getPlugin(Main.class); + + @Override + public VDEnemy getEnemy() { + return new VDEnemyBuilder("VD_GRAVITY_ZOMBIE") + .withName("Gravity Zombie") + .withWaveMinimum(0) + .withWaveMaximum(50) + .withFullArmor(VDEnemyBuilder.ArmorType.LEATHER, 0, 1) + .withScalingHealth(wave -> 25.0) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.14); + }) + .onDamageByEntity((event, arena) -> { + //long distance player marking + Player player; + if (!(event.getDamager() instanceof Player damager)) { + if (event.getDamager() instanceof Arrow arrow) { + player = (Player) arrow.getShooter(); + } else { + return; + } + } else { + player = damager; + } + Entity entity = event.getEntity(); + int value = VdEnemyAbilityHandler.increaseVariable(entity, "VD_ENEMY_ABILITY_RAGE"); + if (value >= 2) { + VdEnemyAbilityHandler.resetVariable(entity, "VD_ENEMY_ABILITY_RAGE"); + doPrepareSkill((Creature) entity, player); + } + }).build(); + } + + @SneakyThrows + private void doPrepareSkill(Creature creature, Player player) { + if (creature.isDead() || creature.getHealth() <= 0) { + return; + } + if (creature.hasMetadata("VD_ENEMY_ABILITY_CASTING")) { + return; + } + creature.setAI(false); + creature.setMetadata("VD_ENEMY_ABILITY_CASTING", new FixedMetadataValue(plugin, true)); + Laser laser = new Laser.GuardianLaser(creature.getEyeLocation(), player, 4, 100); + NewCreatureUtils.doSetCustomNameTemporarily(creature, ChatColor.translateAlternateColorCodes('&', "&b&lCHANNELING"), 20 * 4, () -> { + if (creature.isDead()) { + return; + } + creature.removeMetadata("VD_ENEMY_ABILITY_CASTING", plugin); + creature.setAI(true); + }); + laser.start(plugin); + new BukkitRunnable() { + int ticks = 0; + + @Override + public void run() { + if (creature.isDead() || ticks >= 20 * 4) { + if (laser.isStarted()) { + laser.stop(); + } + this.cancel(); + return; + } + double distance = player.getLocation().distance(creature.getLocation()); + if (distance < 4.5) { + throwPlayerFromLocation(player, creature.getLocation()); + } else if (distance > 7) { + throwPlayerToLocation(player, creature.getLocation()); + } + + creature.swingMainHand(); + VillagerAiAnimations.makeEntityLookAt(creature, player.getLocation()); + ticks += 5; + } + }.runTaskTimer(plugin, 5, 5); + } + + private void throwPlayerFromLocation(Player player, Location targetLocation) { + Location playerLocation = player.getLocation(); + Vector direction = playerLocation.toVector().subtract(targetLocation.toVector()).normalize(); + Vector velocity = direction.multiply(0.5); + player.setVelocity(velocity); + } + + private void throwPlayerToLocation(Player player, Location targetLocation) { + Location playerLocation = player.getLocation(); + Vector direction = targetLocation.toVector().subtract(playerLocation.toVector()).normalize(); + Vector velocity = direction.multiply(0.5); + player.setVelocity(velocity); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/PopZombie.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/PopZombie.java new file mode 100644 index 000000000..ad93b4d74 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/PopZombie.java @@ -0,0 +1,74 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type; + +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Creature; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewEnemySpawnerManager; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemyBuilder; + +import java.util.concurrent.ThreadLocalRandom; + +public class PopZombie implements RegistrableZombie { + + private final Main plugin = JavaPlugin.getPlugin(Main.class); + + @Override + public VDEnemy getEnemy() { + return new VDEnemyBuilder("VD_POP_ZOMBIE") + .withName("Pop Zombie") + .withWaveMinimum(0) + .withWaveMaximum(50) + .withScalingHealth(wave -> 25.0) + .onSpawn(creature -> { + creature.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.2); + }) + .onDeath((event, arena) -> { + VersionUtils.sendParticles("LAVA", arena.getPlayers(), event.getEntity().getLocation(), 20); + NewEnemySpawnerManager spawnerManager = arena.getNewEnemySpawnerManager(); + VDEnemy baby = plugin.getNewEnemiesRegistry().getEnemyById("VD_BABY_ZOMBIE"); + pushEntity(spawnerManager.doSpawnEnemyOutsideManagement(baby, event.getEntity().getLocation())); + pushEntity(spawnerManager.doSpawnEnemyOutsideManagement(baby, event.getEntity().getLocation())); + }).build(); + } + + private void pushEntity(Creature creature) { + double upwardForce = 0.5; + double sideForce = 0.3; + + int direction = ThreadLocalRandom.current().nextInt(4); + double x = 0, z = 0; + + switch (direction) { + case 0 -> x = sideForce; + case 1 -> x = -sideForce; + case 2 -> z = sideForce; + case 3 -> z = -sideForce; + } + + Vector velocity = new Vector(x, upwardForce, z); + creature.setVelocity(velocity); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/RegistrableZombie.java b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/RegistrableZombie.java new file mode 100644 index 000000000..72e9781ba --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/managers/spawner/gold/enemy/type/RegistrableZombie.java @@ -0,0 +1,27 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.type; + +import plugily.projects.villagedefense.arena.managers.spawner.gold.enemy.VDEnemy; + +public interface RegistrableZombie { + + VDEnemy getEnemy(); + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/midwave/MidWaveEvent.java b/src/main/java/plugily/projects/villagedefense/arena/midwave/MidWaveEvent.java new file mode 100644 index 000000000..7c9d6ba44 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/midwave/MidWaveEvent.java @@ -0,0 +1,31 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.midwave; + +import plugily.projects.villagedefense.arena.Arena; + +public interface MidWaveEvent { + + boolean canTrigger(Arena arena); + + void initiate(Arena arena); + + void cleanup(Arena arena); + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/midwave/PinataZombieEvent.java b/src/main/java/plugily/projects/villagedefense/arena/midwave/PinataZombieEvent.java new file mode 100644 index 000000000..6da7771d0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/midwave/PinataZombieEvent.java @@ -0,0 +1,211 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.midwave; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.ZombieVillager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityTargetLivingEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.utils.hologram.ArmorStandHologram; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; + +import java.util.concurrent.ThreadLocalRandom; + +public class PinataZombieEvent implements MidWaveEvent, Listener { + + public static final String PINATA_METADATA = "VD_PINATA_EVENT"; + private final Main plugin; + + public PinataZombieEvent(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public boolean canTrigger(Arena arena) { + return arena.getWave() % 11 == 0; + } + + @Override + public void initiate(Arena arena) { + LivingEntity target = (LivingEntity) arena.getStartLocation().getWorld().spawnEntity(arena.getStartLocation(), EntityType.ZOMBIE_VILLAGER); + target.setGlowing(true); + target.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(0.1); + target.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(100.0); + ((Ageable) target).setAdult(); + target.setMetadata(PINATA_METADATA, new FixedMetadataValue(plugin, true)); + + ArmorStandHologram hologram = new ArmorStandHologram(target.getLocation().add(0, 0.25, 0), + ChatColor.translateAlternateColorCodes('&', "&e&lPUNCH ME")); + new BukkitRunnable() { + boolean toggle = false; + int ticks = 0; + int color = 0; + + @Override + public void run() { + if (!target.hasMetadata(PINATA_METADATA) || target.isDead()) { + hologram.delete(); + target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().clone().add(0, 0.5, 0), 1); + target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ZOMBIE_INFECT, 1, 0.5f); + for (int i = 0; i < 8; i++) { + dropNaturalItem(hologram.getLocation(), XMaterial.ROTTEN_FLESH.parseItem()); + } + target.remove(); + cancel(); + return; + } + ArmorStand stand = hologram.getArmorStands().get(0); + stand.teleport(target.getLocation().add(0, 0.25, 0)); + if (ticks % 5 == 0) { + for (Player player : arena.getPlayers()) { + try { + plugin.getGlowingEntities().setGlowing(target, player, getNextColor(color)); + } catch (Exception ignored) { + } + color = (color + 1) % 7; + } + } + if (ticks % 10 == 0) { + String message; + if (toggle) { + message = ChatColor.translateAlternateColorCodes('&', "&c&lPUNCH ME"); + } else { + message = ChatColor.translateAlternateColorCodes('&', "&e&lPUNCH ME"); + } + toggle = !toggle; + stand.setCustomName(message); + } + ticks++; + } + }.runTaskTimer(plugin, 0, 1); + arena.getSpecialEntities().add(target); + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_PINATA_EVENT") + .asKey() + .arena(arena) + .sendArena(); + for (Player player : arena.getPlayers()) { + player.playSound(player, Sound.ENTITY_ZOMBIE_VILLAGER_CURE, 0.5f, 2f); + } + } + + @Override + public void cleanup(Arena arena) { + for (LivingEntity livingEntity : arena.getSpecialEntities()) { + if (livingEntity.hasMetadata(PINATA_METADATA)) { + livingEntity.removeMetadata(PINATA_METADATA, plugin); + } + } + } + + @EventHandler + public void onPinataFocus(EntityTargetLivingEntityEvent event) { + if (!(event.getTarget() instanceof ZombieVillager)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getSpecialEntities().contains(event.getTarget())) { + continue; + } + if (!event.getTarget().hasMetadata(PINATA_METADATA)) { + continue; + } + event.setCancelled(true); + } + } + + @EventHandler + public void onPinataDamage(EntityDamageByEntityEvent event) { + //cancel all pinata damages + if (event.getDamager().hasMetadata(PINATA_METADATA)) { + event.setCancelled(true); + } + //drop rewards on pinata punch + if (event.getDamager() instanceof Player player && event.getEntity().hasMetadata(PINATA_METADATA)) { + if (!plugin.getArenaRegistry().isInArena(player)) { + return; + } + Vector velocity = event.getEntity().getLocation().getDirection().multiply(-1).normalize().multiply(2.0); + event.getEntity().setVelocity(velocity); + //60% chance of drop + if (ThreadLocalRandom.current().nextInt(0, 100) >= 40) { + doCustomDrop(player, event.getDamager().getLocation()); + } + event.setDamage(1.0); + } + } + + private void dropNaturalItem(Location location, ItemStack itemStack) { + Item item = location.getWorld().dropItemNaturally(location.clone().add(0, 0.5, 0), itemStack); + item.setInvulnerable(true); + item.setPickupDelay(Integer.MAX_VALUE); + item.setGravity(true); + item.setCustomNameVisible(false); + Bukkit.getScheduler().runTaskLater(plugin, () -> item.remove(), 15); + } + + private ChatColor getNextColor(int color) { + return switch (color) { + case 0 -> ChatColor.WHITE; + case 1 -> ChatColor.RED; + case 2 -> ChatColor.GOLD; + case 3 -> ChatColor.DARK_RED; + case 4 -> ChatColor.BLUE; + case 5 -> ChatColor.GREEN; + case 6 -> ChatColor.DARK_PURPLE; + default -> ChatColor.BLACK; + }; + } + + private void doCustomDrop(Player player, Location location) { + if (ThreadLocalRandom.current().nextBoolean()) { + int rand = ThreadLocalRandom.current().nextInt(4, 12); + plugin.getUserManager().getUser(player).adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), rand); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a+" + rand + " &7orbs")); + } else { + int amount = ThreadLocalRandom.current().nextInt(1, 3); + for (int i = 0; i < amount; i++) { + dropNaturalItem(location, XMaterial.ROTTEN_FLESH.parseItem()); + } + player.getInventory().addItem(new ItemStack(Material.ROTTEN_FLESH, amount)); + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/midwave/RottenOfferEvent.java b/src/main/java/plugily/projects/villagedefense/arena/midwave/RottenOfferEvent.java new file mode 100644 index 000000000..adfde8a54 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/midwave/RottenOfferEvent.java @@ -0,0 +1,159 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.midwave; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.utils.hologram.ArmorStandHologram; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewEnemySpawnerManager; + +import java.util.Map; + +public class RottenOfferEvent implements MidWaveEvent, Listener { + + public static final String ROTTEN_SALE_METADATA = "VD_TRADER_ROTTEN_SALE"; + private final Main plugin; + + public RottenOfferEvent(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @Override + public boolean canTrigger(Arena arena) { + return arena.getWave() % 7 == 0; + } + + @Override + public void initiate(Arena arena) { + LivingEntity target = (LivingEntity) arena.getStartLocation().getWorld().spawnEntity(arena.getStartLocation(), EntityType.WANDERING_TRADER); + String name = NewCreatureUtils.getRandomVillagerName(); + target.setCustomName(name); + target.setCustomNameVisible(true); + target.setMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA, new FixedMetadataValue(plugin, name)); + target.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).setBaseValue(1.0); + for (Player player : arena.getPlayers()) { + try { + plugin.getGlowingEntities().setGlowing(target, player, ChatColor.BLUE); + } catch (ReflectiveOperationException ignored) { + } + } + + String offerMessage = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_ROTTEN_OFFER").asKey().build(); + ArmorStandHologram hologram = new ArmorStandHologram(target.getLocation().add(0, 0.25, 0), offerMessage); + new BukkitRunnable() { + @Override + public void run() { + if (!target.hasMetadata(ROTTEN_SALE_METADATA)) { + hologram.delete(); + target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().clone().add(0, 0.5, 0), 1); + target.getWorld().playSound(target.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, .5f); + target.remove(); + cancel(); + return; + } + ArmorStand stand = hologram.getArmorStands().get(0); + stand.teleport(target.getLocation().add(0, 0.25, 0)); + } + }.runTaskTimer(plugin, 0, 1); + target.setMetadata(ROTTEN_SALE_METADATA, new FixedMetadataValue(plugin, true)); + arena.addSpecialEntity(target); + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_ROTTEN_SALE") + .asKey() + .value(ChatColor.translateAlternateColorCodes('&', "&c&lROTTEN FLESH")) + .arena(arena) + .sendArena(); + for (Player player : arena.getPlayers()) { + player.playSound(player, Sound.ENTITY_WANDERING_TRADER_TRADE, 1, 1.15f); + } + } + + @Override + public void cleanup(Arena arena) { + for (LivingEntity livingEntity : arena.getSpecialEntities()) { + if (livingEntity.hasMetadata(ROTTEN_SALE_METADATA)) { + livingEntity.removeMetadata(ROTTEN_SALE_METADATA, plugin); + } + } + } + + @EventHandler + public void onTraderDamage(EntityDamageByEntityEvent event) { + if (!event.getEntity().hasMetadata(ROTTEN_SALE_METADATA)) { + return; + } + //cancel no matter what + event.setCancelled(true); + } + + @EventHandler + public void onInteract(PlayerInteractEntityEvent event) { + if (!event.getRightClicked().hasMetadata(ROTTEN_SALE_METADATA)) { + return; + } + Player player = event.getPlayer(); + if (!plugin.getArenaRegistry().isInArena(player)) { + return; + } + event.setCancelled(true); + if (!player.getInventory().contains(Material.ROTTEN_FLESH)) { + player.playSound(player, Sound.ENTITY_WANDERING_TRADER_NO, 1, 1); + return; + } + int count = 0; + for (Map.Entry entry : player.getInventory().all(Material.ROTTEN_FLESH).entrySet()) { + count += entry.getValue().getAmount(); + } + player.getInventory().remove(Material.ROTTEN_FLESH); + Arena arena = plugin.getArenaRegistry().getArena(player); + arena.changeArenaOptionBy("ROTTEN_FLESH_AMOUNT", count); + int orbs = (int) (count * 1.45); + plugin.getUserManager().getUser(player).adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), orbs); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a+" + orbs + " &7orbs")); + player.playSound(player, Sound.ENTITY_WANDERING_TRADER_TRADE, 1, 1); + if (!arena.checkLevelUpRottenFlesh() || arena.getArenaOption("ROTTEN_FLESH_LEVEL") >= 30) { + return; + } + for (Player arenaPlayer : arena.getPlayers()) { + arenaPlayer.setHealth(VersionUtils.getMaxHealth(player)); + VersionUtils.setMaxHealth(player, VersionUtils.getMaxHealth(player) + 2.0); + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_ROTTEN_FLESH_LEVEL_UP").asKey().player(arenaPlayer).sendPlayer(); + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/midwave/ShopOfferEvent.java b/src/main/java/plugily/projects/villagedefense/arena/midwave/ShopOfferEvent.java new file mode 100644 index 000000000..fb3fde346 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/midwave/ShopOfferEvent.java @@ -0,0 +1,94 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.midwave; + +import org.bukkit.Sound; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.utils.hologram.ArmorStandHologram; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.shop.ShopManager; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewEnemySpawnerManager; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +public class ShopOfferEvent implements MidWaveEvent { + + private final Main plugin; + + public ShopOfferEvent(Main plugin) { + this.plugin = plugin; + } + + @Override + public boolean canTrigger(Arena arena) { + return arena.getWave() % 5 == 0; + } + + @Override + public void initiate(Arena arena) { + List list = arena.getVillagers() + .stream() + .filter(v -> !v.isDead()) + .collect(Collectors.toList()); + Villager target = list.get(ThreadLocalRandom.current().nextInt(list.size())); + target.setGlowing(true); + + String offerMessage = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_SPECIAL_OFFER").asKey().build(); + ArmorStandHologram hologram = new ArmorStandHologram(target.getLocation().add(0, 0.25, 0), offerMessage); + new BukkitRunnable() { + @Override + public void run() { + if (!target.hasMetadata(ShopManager.SHOP_OFFER_METADATA)) { + hologram.delete(); + cancel(); + return; + } + ArmorStand stand = hologram.getArmorStands().get(0); + stand.teleport(target.getLocation().add(0, 0.25, 0)); + } + }.runTaskTimer(plugin, 0, 1); + target.setMetadata(ShopManager.SHOP_OFFER_METADATA, new FixedMetadataValue(plugin, true)); + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_OFFERING_SALE") + .asKey() + .value(target.getMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA).get(0).asString()) + .arena(arena) + .sendArena(); + for (Player player : arena.getPlayers()) { + player.playSound(player, Sound.ENTITY_VILLAGER_TRADE, 1, 1.15f); + } + } + + @Override + public void cleanup(Arena arena) { + for (Villager villager : arena.getVillagers()) { + if (villager.hasMetadata(ShopManager.SHOP_OFFER_METADATA)) { + villager.setGlowing(false); + villager.removeMetadata(ShopManager.SHOP_OFFER_METADATA, plugin); + } + } + } +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/midwave/TipEvent.java b/src/main/java/plugily/projects/villagedefense/arena/midwave/TipEvent.java new file mode 100644 index 000000000..c1facb403 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/midwave/TipEvent.java @@ -0,0 +1,78 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.midwave; + +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.utils.LimitedQueue; + +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ThreadLocalRandom; + +public class TipEvent implements MidWaveEvent { + + private final List registeredTips = new ArrayList<>(); + private final Queue tipCache = new LimitedQueue<>(6); + + public TipEvent() { + registeredTips.add(new Tip(new MessageBuilder("Remember to upgrade your armor and weapons in &e&lVillager Shop").build(), 1)); + registeredTips.add(new Tip(new MessageBuilder("You, your pets and villagers %value% passively every wave").value("&a&lHEAL").build(), 1)); + registeredTips.add(new Tip(new MessageBuilder("You can upgrade your %value% with Shift + Right Click").value("&b&lPETS").build(), 5)); + registeredTips.add(new Tip(new MessageBuilder("Enemies do occasionally drop %value% such as Money Pouch, Iron Delivery and more").value("&b&lPOWERUPS").build(), 5)); + registeredTips.add(new Tip(new MessageBuilder("Baby zombies are pretty annoying").build(), 5)); + registeredTips.add(new Tip(new MessageBuilder("You can use %value% to ride villagers and move them").value("&a&lSADDLE").build(), 8)); + registeredTips.add(new Tip(new MessageBuilder("%value% pop when you damage them, avoid their explosion").value("&e&lPlayer Busters").build(), 10)); + registeredTips.add(new Tip(new MessageBuilder("Enemies start scaling health starting from &e&lWave 15").build(), 12)); + registeredTips.add(new Tip(new MessageBuilder("Do not let enemies crowd yourself or you'll die pretty fast").build(), 15)); + registeredTips.add(new Tip(new MessageBuilder("%value% spawn TNT upon hitting you, avoid their TNT explosion").value("&c&lKamikaze Zombies").build(), 25)); + registeredTips.add(new Tip(new MessageBuilder("%value% units cannot be stunned nor slowed by any abilities").value("&7&lUnstunnable (✶)").build(), 36)); + registeredTips.add(new Tip(new MessageBuilder("%value% units will not die on one-shot but receive 15% max health damage instead").value("&4&lUnpoppable (☄)").build(), 36)); + registeredTips.add(new Tip(new MessageBuilder("%value% ignore your presence completely and target only villagers").value("&a&lVillager Slayers").build(), 45)); + } + + + @Override + public boolean canTrigger(Arena arena) { + return arena.getWave() % 4 == 0; + } + + @Override + public void initiate(Arena arena) { + while (true) { + Tip tip = registeredTips.get(ThreadLocalRandom.current().nextInt(registeredTips.size())); + if (arena.getWave() < tip.minWave()) { + continue; + } + if (!tipCache.contains(tip)) { + new MessageBuilder(tip.message()).prefix().arena(arena).sendArena(); + break; + } + } + } + + @Override + public void cleanup(Arena arena) { + } + + private record Tip(String message, int minWave) { + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/powerup/IronDeliveryPowerup.java b/src/main/java/plugily/projects/villagedefense/arena/powerup/IronDeliveryPowerup.java new file mode 100644 index 000000000..60c8c7ce9 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/powerup/IronDeliveryPowerup.java @@ -0,0 +1,199 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.powerup; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Creature; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.Item; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.handlers.hologram.ArmorStandHologram; +import plugily.projects.villagedefense.handlers.upgrade.NewEntityUpgradeManager; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +public class IronDeliveryPowerup implements Powerup { + + private final Main plugin; + + public IronDeliveryPowerup(Main plugin) { + this.plugin = plugin; + } + + @Override + public boolean canSpawn(Arena arena) { + return arena.getWave() >= 5; + } + + @Override + public void spawn(Arena arena, Location location) { + ArmorStandHologram hologram = new ArmorStandHologram(location.clone().add(0, -1.35, 0)) + .appendItem(XMaterial.IRON_BLOCK.parseItem()) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&e&lIRON DELIVERY")); + + hologram.setPickupHandler(player -> { + if (!plugin.getArenaRegistry().getArena(player).equals(arena)) { + return; + } + XSound.ENTITY_PLAYER_LEVELUP.play(player, 1, 0); + XSound.ENTITY_IRON_GOLEM_DEATH.play(arena.getStartLocation(), 1, 0); + int count; + KitSpecifications.GameTimeState state = KitSpecifications.getTimeState(arena); + if (state == KitSpecifications.GameTimeState.EARLY) { + count = 1; + } else if (state == KitSpecifications.GameTimeState.MID) { + count = 2; + } else { + count = 3; + } + for (int i = 0; i < count; i++) { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + XSound.ENTITY_IRON_GOLEM_REPAIR.play(arena.getStartLocation(), 1, 1.25f); + Creature golem = arena.spawnGolemForce(arena.getStartLocation(), player); + if (golem == null) { + return; + } + golem.setMetadata(NewEntityUpgradeManager.UPGRADES_DISABLED_METADATA, new FixedMetadataValue(plugin, true)); + NewEntityUpgradeManager upgradeManager = plugin.getEntityUpgradeManager(); + upgradeManager.getRegisteredUpgrades() + .stream() + .filter(u -> u.getApplicableEntity() == EntityType.IRON_GOLEM) + .forEach(upgrade -> upgradeManager.applyUpgradeSilent(golem, player, upgrade)); + ArmorStandHologram golemHologram = new ArmorStandHologram(golem.getLocation()) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&e&lIRON DELIVERY")); + golem.getWorld().playSound(golem.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 0.5f); + + new BukkitRunnable() { + int tick = 0; + boolean toggle = false; + + @Override + public void run() { + if (tick == 400 || golemHologram.isDeleted() || golemHologram.getArmorStands().isEmpty()) { + World world = golem.getLocation().getWorld(); + world.spawnParticle(Particle.EXPLOSION_LARGE, golem.getLocation().clone().add(0, 0.5, 0), 1); + world.playSound(golem.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 0.5f); + arena.removeIronGolem((IronGolem) golem); + golemHologram.delete(); + cancel(); + return; + } + ArmorStand stand = golemHologram.getArmorStands().get(0); + stand.teleport(golem.getLocation().clone().add(0, 1.1, 0)); + //postpone countdown until wave starts but still teleport moving holograms + if (!arena.isFighting()) { + return; + } + int modulo = tick < 100 ? 10 : tick > 350 ? 3 : 5; + if (tick % modulo == 0) { + String message; + if (toggle) { + message = ChatColor.translateAlternateColorCodes('&', "&c&lIRON DELIVERY (" + ((400 - tick) / 20) + "s)"); + } else { + message = ChatColor.translateAlternateColorCodes('&', "&e&lIRON DELIVERY (" + ((400 - tick) / 20) + "s)"); + } + toggle = !toggle; + stand.setCustomName(message); + } + tick++; + } + }.runTaskTimer(plugin, 1, 1); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!golemHologram.isDeleted()) { + golemHologram.delete(); + } + }, /* remove after 40 seconds to prevent staying even if arena is finished */ 20 * 40); + }, 15 * (i + 1)); + } + hologram.delete(); + }); + + new BukkitRunnable() { + boolean toggle = true; + boolean grounded = false; + boolean flyReverse = false; + int tick = 0; + + @Override + public void run() { + if (tick == 200 || hologram.isDeleted() || hologram.getArmorStands().isEmpty()) { + hologram.getLocation().getWorld().spawnParticle(XParticle.getParticle("EXPLOSION_HUGE"), hologram.getLocation(), 1); + hologram.delete(); + cancel(); + return; + } + if (hologram.getEntityItem().isOnGround() && !grounded) { + grounded = true; + hologram.getEntityItem().setGravity(false); + hologram.getEntityItem().teleport(hologram.getEntityItem().getLocation().add(0, 0.75, 0)); + } + if (grounded) { + hologram.getEntityItem().setGravity(true); + Location newLocation = hologram.getEntityItem().getLocation().clone().add(0, 0.015 * (flyReverse ? -1 : 1), 0); + hologram.getEntityItem().teleport(newLocation); + hologram.getEntityItem().setGravity(false); + if (tick % 60 == 0) { + flyReverse = !flyReverse; + } + } + ArmorStand stand = hologram.getArmorStands().get(0); + int modulo = tick < 100 ? 10 : tick > 150 ? 3 : 5; + if (tick % modulo == 0) { + String message; + if (toggle) { + message = ChatColor.translateAlternateColorCodes('&', "&c&lIRON DELIVERY (" + ((200 - tick) / 20) + "s)"); + } else { + message = ChatColor.translateAlternateColorCodes('&', "&e&lIRON DELIVERY (" + ((200 - tick) / 20) + "s)"); + } + toggle = !toggle; + stand.setCustomName(message); + } + if (tick % 10 == 0) { + for (int i = 0; i < 2; i++) { + Item item = hologram.getLocation().getWorld().dropItemNaturally(stand.getLocation().clone().add(0, 0.5, 0), XMaterial.IRON_INGOT.parseItem()); + item.setInvulnerable(true); + item.setPickupDelay(Integer.MAX_VALUE); + item.setGravity(true); + item.setCustomNameVisible(false); + Bukkit.getScheduler().runTaskLater(plugin, () -> item.remove(), 15); + } + } + stand.teleport(hologram.getEntityItem().getLocation().clone().add(0, -1.25, 0)); + tick++; + } + }.runTaskTimer(plugin, 1, 1); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!hologram.isDeleted()) { + hologram.delete(); + } + }, /* remove after 40 seconds to prevent staying even if arena is finished */ 20 * 40); + } +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/powerup/MoneyPouchPowerup.java b/src/main/java/plugily/projects/villagedefense/arena/powerup/MoneyPouchPowerup.java new file mode 100644 index 000000000..2ab91eef8 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/powerup/MoneyPouchPowerup.java @@ -0,0 +1,163 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.powerup; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.handlers.hologram.ArmorStandHologram; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; + +public class MoneyPouchPowerup implements Powerup { + + private final List goldBlocks = Arrays.asList(XMaterial.GOLD_NUGGET.parseItem(), XMaterial.GOLD_INGOT.parseItem()); + private final Random random = new Random(); + private final Main plugin; + + public MoneyPouchPowerup(Main plugin) { + this.plugin = plugin; + } + + @Override + public boolean canSpawn(Arena arena) { + return true; + } + + @Override + public void spawn(Arena arena, Location location) { + ArmorStandHologram hologram = new ArmorStandHologram(location.clone().add(0, -1.35, 0)) + .appendItem(XMaterial.GOLD_BLOCK.parseItem()) + .appendLines(ChatColor.translateAlternateColorCodes('&', "&e&lMONEY POUCH")) + .appendLines(ChatColor.translateAlternateColorCodes('&', "&7Click me!")); + + AtomicInteger pouchHits = new AtomicInteger(10); + hologram.setTouchHandler(player -> { + if (!plugin.getArenaRegistry().getArena(player).equals(arena)) { + return; + } + XSound.BLOCK_LAVA_POP.play(player); + Item item = hologram.getLocation().getWorld().dropItemNaturally(hologram.getLocation(), goldBlocks.get(random.nextInt(goldBlocks.size()))); + item.setInvulnerable(true); + item.setPickupDelay(Integer.MAX_VALUE); + item.setGravity(true); + item.setCustomNameVisible(false); + Bukkit.getScheduler().runTaskLater(plugin, () -> item.remove(), 15); + int rand = random.nextInt(3, 15); + plugin.getUserManager().getUser(player).adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), rand); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a+" + rand + " &7orbs")); + int hits = pouchHits.decrementAndGet(); + if (hits <= 0) { + hologram.delete(); + } + }); + + new BukkitRunnable() { + boolean toggle = true; + boolean grounded = false; + boolean flyReverse = false; + boolean soundPlayed = false; + int tick = 0; + + @Override + public void run() { + Item entityItem = hologram.getEntityItem(); + if (tick == 190) { + XSound.BLOCK_ANVIL_DESTROY.play(hologram.getLocation(), 1, 1.25f); + soundPlayed = true; + } + if (tick == 200 || hologram.isDeleted() || hologram.getArmorStands().isEmpty()) { + if (!soundPlayed) { + XSound.BLOCK_ANVIL_DESTROY.play(hologram.getLocation(), 1, 1.25f); + } + for (int i = 0; i < 12; i++) { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + Item item = hologram.getLocation().getWorld().dropItemNaturally(entityItem.getLocation(), goldBlocks.get(random.nextInt(goldBlocks.size()))); + item.setVelocity(item.getVelocity().multiply(random.nextDouble(1.0, 1.5))); + item.setInvulnerable(true); + item.setPickupDelay(Integer.MAX_VALUE); + item.setGravity(true); + item.setCustomNameVisible(false); + Bukkit.getScheduler().runTaskLater(plugin, () -> item.remove(), 15); + }, random.nextInt(1, 10)); + } + hologram.delete(); + cancel(); + return; + } + if (hologram.getEntityItem().isOnGround() && !grounded) { + grounded = true; + entityItem.setGravity(false); + entityItem.teleport(hologram.getEntityItem().getLocation().add(0, 0.75, 0)); + } + if (grounded) { + entityItem.setGravity(true); + Location newLocation = hologram.getEntityItem().getLocation().clone().add(0, 0.015 * (flyReverse ? -1 : 1), 0); + entityItem.teleport(newLocation); + entityItem.setGravity(false); + if (tick % 60 == 0) { + flyReverse = !flyReverse; + } + } + ArmorStand stand = hologram.getArmorStands().get(0); + int modulo = tick < 100 ? 10 : tick > 150 ? 3 : 5; + if (tick % modulo == 0) { + String message; + if (toggle) { + message = ChatColor.translateAlternateColorCodes('&', "&c&lMONEY POUCH (" + ((200 - tick) / 20) + "s)"); + } else { + message = ChatColor.translateAlternateColorCodes('&', "&e&lMONEY POUCH (" + ((200 - tick) / 20) + "s)"); + } + toggle = !toggle; + stand.setCustomName(message); + } + if (tick % 10 == 0) { + for (int i = 0; i < 2; i++) { + Item item = hologram.getLocation().getWorld().dropItemNaturally(stand.getLocation().clone().add(0, 0.5, 0), goldBlocks.get(random.nextInt(goldBlocks.size()))); + item.setInvulnerable(true); + item.setPickupDelay(Integer.MAX_VALUE); + item.setGravity(true); + item.setCustomNameVisible(false); + Bukkit.getScheduler().runTaskLater(plugin, () -> item.remove(), 15); + } + } + stand.teleport(entityItem.getLocation().clone().add(0, -1.25 + 0.27, 0)); + hologram.getArmorStands().get(1).teleport(entityItem.getLocation().clone().add(0, -1.25, 0)); + tick++; + } + }.runTaskTimer(plugin, 1, 1); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!hologram.isDeleted()) { + hologram.delete(); + } + }, /* remove after 40 seconds to prevent staying even if arena is finished */ 20 * 40); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/powerup/Powerup.java b/src/main/java/plugily/projects/villagedefense/arena/powerup/Powerup.java new file mode 100644 index 000000000..3c4fba50a --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/powerup/Powerup.java @@ -0,0 +1,30 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.powerup; + +import org.bukkit.Location; +import plugily.projects.villagedefense.arena.Arena; + +public interface Powerup { + + boolean canSpawn(Arena arena); + + void spawn(Arena arena, Location location); + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/powerup/PowerupEvents.java b/src/main/java/plugily/projects/villagedefense/arena/powerup/PowerupEvents.java new file mode 100644 index 000000000..65eeb28d9 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/powerup/PowerupEvents.java @@ -0,0 +1,82 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.powerup; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDeathEvent; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.ArenaMetadata; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +/** + * @author Plajer + *

+ * Created at 06.10.2023 + */ +public class PowerupEvents implements Listener { + + private final List powerups = new ArrayList<>(); + private final Random random = new Random(); + private Main plugin; + + public PowerupEvents(Main plugin) { + this.plugin = plugin; + powerups.add(new IronDeliveryPowerup(plugin)); + powerups.add(new MoneyPouchPowerup(plugin)); + powerups.add(new RandomPowerup(plugin)); + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onPowerupDrop(EntityDeathEvent event) { + if (!NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getEnemies().contains(event.getEntity())) { + continue; + } + if (ThreadLocalRandom.current().nextDouble(0.0, 100.0) <= 1.5) { + int powerupsDropped = arena.getMetadata(ArenaMetadata.POWERUPS_WAVE_COUNT, 0); + if (powerupsDropped >= 4) { + return; + } + arena.setMetadata(ArenaMetadata.POWERUPS_WAVE_COUNT, powerupsDropped + 1); + arena.setMetadata(ArenaMetadata.LAST_POWERUP_DROP_MILLIS, System.currentTimeMillis()); + while (true) { + Powerup powerup = powerups.get(random.nextInt(powerups.size())); + if (!powerup.canSpawn(arena)) { + continue; + } + powerup.spawn(arena, event.getEntity().getLocation().clone().add(0, 0.1, 0)); + return; + } + } + } + } + + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/powerup/RandomPowerup.java b/src/main/java/plugily/projects/villagedefense/arena/powerup/RandomPowerup.java new file mode 100644 index 000000000..4ded5f572 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/powerup/RandomPowerup.java @@ -0,0 +1,241 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.powerup; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Sound; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.handlers.hologram.ArmorStandHologram; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.BiConsumer; + +public class RandomPowerup implements Powerup { + + private final List localPowerups = new ArrayList<>(); + private final Main plugin; + + public RandomPowerup(Main plugin) { + this.plugin = plugin; + registerLocalPowerups(); + } + + private void registerLocalPowerups() { + String powerupMessage = color("&7You received %name%&7 powerup from %player%!"); + localPowerups.add(new LocalRandomPowerup( + color("&e&lREJUVENATION"), + color("&7Heal and absorption for 5s for you and your pets!"), + (arena, player) -> { + for (Player target : arena.getPlayersLeft()) { + target.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 20 * 5, 0)); + target.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, 20 * 5, 0)); + player.playSound(player, Sound.ENTITY_PLAYER_LEVELUP, 1, 1.25f); + player.sendMessage(powerupMessage.replace("%name%", color("&e&lREJUVENATION")).replace("%player%", player.getName())); + } + List pets = new ArrayList<>(); + pets.addAll(arena.getWolves()); + pets.addAll(arena.getIronGolems()); + for (LivingEntity pet : pets) { + pet.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 20 * 5, 0)); + pet.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, 20 * 5, 0)); + } + } + )); + localPowerups.add(new LocalRandomPowerup( + color("&b&lSWIFTNESS"), + color("&7Speed boost for 5s for you and your pets!"), + (arena, player) -> { + for (Player target : arena.getPlayersLeft()) { + target.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 20 * 5, 0)); + player.playSound(player, Sound.ENTITY_PLAYER_LEVELUP, 1, 1.25f); + player.sendMessage(powerupMessage.replace("%name%", color("&b&lSWIFTNESS")).replace("%player%", player.getName())); + } + List pets = new ArrayList<>(); + pets.addAll(arena.getWolves()); + pets.addAll(arena.getIronGolems()); + for (LivingEntity pet : pets) { + pet.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 20 * 5, 0)); + pet.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, 20 * 5, 0)); + } + } + )); + localPowerups.add(new LocalRandomPowerup( + color("&d&lTIME STOP"), + color("&7Alive enemies are frozen in time for 3 seconds!"), + (arena, player) -> { + for (Creature creature : arena.getEnemies()) { + NewCreatureUtils.doStunEnemy(creature, 3); + } + } + )); + localPowerups.add(new LocalRandomPowerup( + color("&6&lJACKPOT"), + color("&7You won jackpot prize of 300 orbs!"), + (arena, player) -> { + int orbs = 300; + player.playSound(player, Sound.ENTITY_PLAYER_LEVELUP, 1, 1.25f); + plugin.getUserManager().getUser(player).adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), orbs); + player.sendMessage(powerupMessage.replace("%name%", color("&6&lJACKPOT")).replace("%player%", player.getName())); + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a+" + orbs + " &7orbs")); + } + )); + //todo test divine barrier + localPowerups.add(new LocalRandomPowerup( + color("&f&lDIVINE BARRIER"), + color("&7Villagers are protected from damage for 10s!"), + (arena, player) -> { + String villagerPowerupMessage = color("&7Villagers received %name%&7 powerup from %player%!"); + for (Villager villager : arena.getVillagers()) { + villager.setNoDamageTicks(20 * 10); + for (Player target : arena.getPlayers()) { + player.playSound(player, Sound.ENTITY_PLAYER_LEVELUP, 1, 1.25f); + player.sendMessage(villagerPowerupMessage.replace("%name%", color("&f&lDIVINE BARRIER")).replace("%player%", player.getName())); + try { + plugin.getGlowingEntities().setGlowing(villager, target, ChatColor.YELLOW); + } catch (ReflectiveOperationException ignored) { + } + Bukkit.getScheduler().runTaskLater(plugin, () -> { + try { + plugin.getGlowingEntities().unsetGlowing(villager, target); + } catch (ReflectiveOperationException ignored) { + } + }, 20 * 10); + } + } + } + )); + } + + private String color(String text) { + return ChatColor.translateAlternateColorCodes('&', text); + } + + @Override + public boolean canSpawn(Arena arena) { + return true; + } + + @Override + public void spawn(Arena arena, Location location) { + ArmorStandHologram hologram = new ArmorStandHologram(location.clone().add(0, -1.5, 0)) + .appendItem(XMaterial.BLAZE_POWDER.parseItem()) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&e&lPOWERUP")); + hologram.setPickupHandler(player -> { + if (!plugin.getArenaRegistry().getArena(player).equals(arena)) { + return; + } + XSound.ENTITY_PLAYER_LEVELUP.play(player, 1, 0); + XSound.ENTITY_VILLAGER_YES.play(player); + hologram.delete(); + onPickup(arena, player); + }); + List materials = Arrays.asList(XMaterial.BLAZE_POWDER.parseItem(), XMaterial.COCOA_BEANS.parseItem(), XMaterial.ANVIL.parseItem(), XMaterial.NETHER_STAR.parseItem()); + + new BukkitRunnable() { + boolean toggle = true; + boolean grounded = false; + boolean flyReverse = false; + int tick = 0; + int index = 0; + + @Override + public void run() { + if (tick == 200 || hologram.isDeleted() || hologram.getArmorStands().isEmpty()) { + hologram.getLocation().getWorld().spawnParticle(XParticle.getParticle("EXPLOSION_HUGE"), hologram.getLocation(), 1); + hologram.delete(); + cancel(); + return; + } + if (hologram.getEntityItem().isOnGround() && !grounded) { + grounded = true; + hologram.getEntityItem().setGravity(false); + hologram.getEntityItem().teleport(hologram.getEntityItem().getLocation().add(0, 0.75, 0)); + } + if (grounded) { + hologram.getEntityItem().setGravity(true); + Location newLocation = hologram.getEntityItem().getLocation().clone().add(0, 0.015 * (flyReverse ? -1 : 1), 0); + hologram.getEntityItem().teleport(newLocation); + hologram.getEntityItem().setGravity(false); + if (tick % 60 == 0) { + flyReverse = !flyReverse; + } + } + ArmorStand stand = hologram.getArmorStands().get(0); + int modulo = tick < 100 ? 10 : tick > 150 ? 3 : 5; + if (tick % modulo == 0) { + String message; + if (toggle) { + message = ChatColor.translateAlternateColorCodes('&', "&c&lRANDOM POWERUP (" + ((200 - tick) / 20) + "s)"); + } else { + message = ChatColor.translateAlternateColorCodes('&', "&e&lRANDOM POWERUP (" + ((200 - tick) / 20) + "s)"); + } + toggle = !toggle; + stand.setCustomName(message); + } + if (tick % 10 == 0) { + hologram.getEntityItem().setItemStack(materials.get(index)); + index++; + if (index >= materials.size()) { + index = 0; + } + + stand.getLocation().getWorld().spawnParticle(XParticle.getParticle("LAVA"), hologram.getEntityItem().getLocation(), 2); + } + stand.teleport(hologram.getEntityItem().getLocation().clone().add(0, -1.25, 0)); + tick++; + } + }.runTaskTimer(plugin, 1, 1); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!hologram.isDeleted()) { + hologram.delete(); + } + }, /* remove after 40 seconds to prevent staying even if arena is finished */ 20 * 40); + } + + private void onPickup(Arena arena, Player player) { + Collections.shuffle(localPowerups); + for (LocalRandomPowerup powerup : localPowerups) { + powerup.onPickup().accept(arena, player); + break; + } + } + + private record LocalRandomPowerup(String name, String description, BiConsumer onPickup) { + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/record/RecordsManager.java b/src/main/java/plugily/projects/villagedefense/arena/record/RecordsManager.java new file mode 100644 index 000000000..71375a480 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/record/RecordsManager.java @@ -0,0 +1,75 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.record; + +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.kits.basekits.Kit; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.user.VDUser; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Handles creation of users records on particular maps + */ +//todo records announce on game end +//todo record per map placeholder (papi) +public class RecordsManager { + + private final Main plugin; + + public RecordsManager(Main plugin) { + this.plugin = plugin; + } + + /** + * Attempts to register survived gameplay wave as a player record if possible. + * If new record is made an announcement is sent to the player. + */ + public void registerAndAnnounceRecord(Player player, Arena arena) { + Kit kit = plugin.getUserManager().getUser(player).getKit(); + VDUser vdUser = plugin.getVdUserManager().getUser(player); + List records = vdUser.getGameplayRecords() + .getOrDefault(arena.getMapName(), new ArrayList<>()) + .stream() + .filter(record -> record.getMapId().equals(arena.getMapName())) + .collect(Collectors.toList()); + VDUser.GameplayRecord newRecord = new VDUser.GameplayRecord(arena.getMapName(), kit.getName(), arena.getWave()); + records.add(newRecord); + List updatedRecords = records + .stream() + .sorted(Comparator.comparing(VDUser.GameplayRecord::getWave).reversed()) + .limit(3) + .collect(Collectors.toList()); + vdUser.getGameplayRecords().put(arena.getMapName(), updatedRecords); + if (!updatedRecords.contains(newRecord)) { + return; + } + player.playSound(player, Sound.ENTITY_VILLAGER_YES, 1, 1); + player.playSound(player, Sound.ENTITY_PLAYER_LEVELUP, 1, 1.25f); + new MessageBuilder("VD_GOLD_NEW_RECORD_REACHED").asKey().player(player).value(kit.getName()).sendPlayer(); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/states/InGameState.java b/src/main/java/plugily/projects/villagedefense/arena/states/InGameState.java index a2d5bb5f3..3395d09f6 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/states/InGameState.java +++ b/src/main/java/plugily/projects/villagedefense/arena/states/InGameState.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena.states; @@ -22,7 +22,8 @@ import plugily.projects.minigamesbox.classic.arena.PluginArena; import plugily.projects.minigamesbox.classic.arena.states.PluginInGameState; import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; +import plugily.projects.minigamesbox.classic.handlers.language.TitleBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.SoundHelper; import plugily.projects.villagedefense.arena.Arena; /** @@ -39,7 +40,7 @@ public void handleCall(PluginArena arena) { if(pluginArena == null) { return; } - pluginArena.getEnemySpawnManager().spawnGlitchCheck(); + pluginArena.getNewEnemySpawnerManager().doGlitchCheck(); if(pluginArena.getVillagers().isEmpty() || arena.getPlayersLeft().isEmpty() && arena.getArenaState() != ArenaState.ENDING) { getPlugin().getArenaManager().stopGame(false, arena); @@ -48,27 +49,23 @@ public void handleCall(PluginArena arena) { int zombiesLeft = pluginArena.getZombiesLeft(); getPlugin().getDebugger().debug("Arena {0} Zombies to spawn {1} Zombies left {2} Fighting {3}", arena.getId(), arena.getArenaOption("ZOMBIES_TO_SPAWN"), zombiesLeft, pluginArena.isFighting()); if(pluginArena.isFighting()) { - if(ServerVersion.Version.isCurrentHigher(ServerVersion.Version.v1_8_R3)) { - pluginArena.getCreatureTargetManager().targetCreatures(); - pluginArena.getCreatureTargetManager().targetRideableCreatures(); - } if(zombiesLeft <= 0) { pluginArena.setFighting(false); pluginArena.getPlugin().getArenaManager().endWave(pluginArena); - } else if(arena.getArenaOption("ZOMBIES_TO_SPAWN") > 0) { - pluginArena.getEnemySpawnManager().spawnEnemies(); - setArenaTimer(500); + } else { + pluginArena.getNewEnemySpawnerManager().doSpawnEnemies(); + if (!pluginArena.getNewEnemySpawnerManager().hasSpawningStarted()) { + setArenaTimer(500); + } } - if(ServerVersion.Version.isCurrentEqualOrHigher(ServerVersion.Version.v1_9_R1)) { - int zombiesLeftFrom = getPlugin().getConfig().getInt("Glowing-Status.Creatures-Left"); - int startingWave; - if(zombiesLeftFrom > 0 && zombiesLeft <= zombiesLeftFrom - && (startingWave = getPlugin().getConfig().getInt("Glowing-Status.Starting-Wave")) > 0 - && pluginArena.getWave() >= startingWave) { - for(org.bukkit.entity.Creature remaining : pluginArena.getEnemies()) { - if(!remaining.isGlowing()) { // To avoid setting glowing property every time - remaining.setGlowing(true); - } + int zombiesLeftFrom = getPlugin().getConfig().getInt("Glowing-Status.Creatures-Left"); + int startingWave; + if (zombiesLeftFrom > 0 && zombiesLeft <= zombiesLeftFrom + && (startingWave = getPlugin().getConfig().getInt("Glowing-Status.Starting-Wave")) > 0 + && pluginArena.getWave() >= startingWave) { + for (org.bukkit.entity.Creature remaining : pluginArena.getEnemies()) { + if (!remaining.isGlowing()) { // To avoid setting glowing property every time + remaining.setGlowing(true); } } } @@ -82,9 +79,17 @@ public void handleCall(PluginArena arena) { if(arena.getArenaOption("ZOMBIES_TO_SPAWN") < 0) { arena.setArenaOption("ZOMBIES_TO_SPAWN", 0); } - } else if(arena.getTimer() <= 0) { - pluginArena.setFighting(true); - pluginArena.getPlugin().getArenaManager().startWave(pluginArena); + if (arena.getTimer() % 4 == 0) { + pluginArena.getVillagerAiManager().doRetreatVillagers(); + } + } else if(arena.getTimer() <= 3) { + SoundHelper.playArenaCountdown(arena); + if(arena.getTimer() <= 0) { + pluginArena.setFighting(true); + pluginArena.getPlugin().getArenaManager().startWave(pluginArena); + } else if(arena.getTimer() >= 1) { + new TitleBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_STARTING_" + arena.getTimer()).asKey().arena(arena).sendArena(); + } } } diff --git a/src/main/java/plugily/projects/villagedefense/arena/states/RestartingState.java b/src/main/java/plugily/projects/villagedefense/arena/states/RestartingState.java index 77fbe0453..31e07ce53 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/states/RestartingState.java +++ b/src/main/java/plugily/projects/villagedefense/arena/states/RestartingState.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena.states; @@ -42,6 +42,7 @@ public void handleCall(PluginArena arena) { if(arena.getTimer() <= 0) { pluginArena.getDroppedFleshes().stream().filter(Objects::nonNull).forEach(Entity::remove); pluginArena.getDroppedFleshes().clear(); + pluginArena.getNewEnemySpawnerManager().doResetSpawnCheck(); } } } diff --git a/src/main/java/plugily/projects/villagedefense/arena/states/StartingState.java b/src/main/java/plugily/projects/villagedefense/arena/states/StartingState.java index 2aa136f6f..4cffa1b82 100644 --- a/src/main/java/plugily/projects/villagedefense/arena/states/StartingState.java +++ b/src/main/java/plugily/projects/villagedefense/arena/states/StartingState.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.arena.states; @@ -50,6 +50,7 @@ public void handleCall(PluginArena arena) { } setArenaTimer(getPlugin().getConfig().getInt("Time-Manager.Cooldown-Before-Next-Wave", 25)); pluginArena.setFighting(false); + pluginArena.getVillagerAiManager().clearCache(); } } diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/CompletionCallback.java b/src/main/java/plugily/projects/villagedefense/arena/villager/CompletionCallback.java new file mode 100644 index 000000000..e4231ecd0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/CompletionCallback.java @@ -0,0 +1,26 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager; + +@FunctionalInterface +public interface CompletionCallback { + + void onComplete(); + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/PathfinderCallback.java b/src/main/java/plugily/projects/villagedefense/arena/villager/PathfinderCallback.java new file mode 100644 index 000000000..93d5e081f --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/PathfinderCallback.java @@ -0,0 +1,29 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager; + +import org.bukkit.Location; +import org.bukkit.entity.Villager; + +@FunctionalInterface +public interface PathfinderCallback { + + void onPathComplete(Villager villager, Location location); + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/VillagerAiAnimations.java b/src/main/java/plugily/projects/villagedefense/arena/villager/VillagerAiAnimations.java new file mode 100644 index 000000000..96f126dde --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/VillagerAiAnimations.java @@ -0,0 +1,92 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager; + +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.villagedefense.Main; + +public class VillagerAiAnimations { + + public static void makeEntityLookAt(Entity entity, Location target) { + Location entityLoc = entity.getLocation(); + + double dx = target.getX() - entityLoc.getX(); + double dy = target.getY() - entityLoc.getY(); + double dz = target.getZ() - entityLoc.getZ(); + + double distanceXZ = Math.sqrt(dx * dx + dz * dz); + + float yaw = (float) Math.toDegrees(Math.atan2(-dx, dz)); + float pitch = (float) Math.toDegrees(-Math.atan2(dy, distanceXZ)); + + entityLoc.setYaw(yaw); + entityLoc.setPitch(pitch); + entity.teleport(entityLoc); + } + + public static Item throwItemTowardsEntity(ItemStack itemStack, Location from, Entity target) { + Item item = target.getWorld().dropItem(from, itemStack); + Vector velocity = calculateVelocity(from, target.getLocation().clone().add(0, 2, 0), 0.3); + item.setVelocity(velocity); + return item; + } + + private static Vector calculateVelocity(Location from, Location to, double power) { + Vector direction = to.toVector().subtract(from.toVector()); + double distance = direction.length(); + + direction.normalize(); + double speed = Math.min(power * (distance / 3), 2.0); + + return direction.multiply(speed); + } + + public static void makeEntityEat(LivingEntity entity, ItemStack food, int eatDuration, CompletionCallback callback) { + entity.getEquipment().setItemInMainHand(food); + + new BukkitRunnable() { + int ticks = 0; + + @Override + public void run() { + if (ticks >= eatDuration) { + this.cancel(); + entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_PLAYER_BURP, 1.0f, 1.0f); + entity.getEquipment().setItemInMainHand(null); + callback.onComplete(); + return; + } + + entity.getWorld().playSound(entity.getLocation(), Sound.ENTITY_GENERIC_EAT, 1.0f, 1.0f); + entity.getWorld().spawnParticle(Particle.ITEM_CRACK, entity.getLocation().add(0, 1, 0), 10, 0.2, 0.2, 0.2, 0, food); + ticks += 5; + } + }.runTaskTimer(JavaPlugin.getProvidingPlugin(Main.class), 0L, 5); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/VillagerAiManager.java b/src/main/java/plugily/projects/villagedefense/arena/villager/VillagerAiManager.java new file mode 100644 index 000000000..582516f40 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/VillagerAiManager.java @@ -0,0 +1,185 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager; + +import com.destroystokyo.paper.entity.Pathfinder; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.type.Door; +import org.bukkit.entity.Villager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.arena.ArenaState; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.villager.trait.AlchemistTrait; +import plugily.projects.villagedefense.arena.villager.trait.BabyTrait; +import plugily.projects.villagedefense.arena.villager.trait.BraveTrait; +import plugily.projects.villagedefense.arena.villager.trait.FishermanTrait; +import plugily.projects.villagedefense.arena.villager.trait.GenericTrait; +import plugily.projects.villagedefense.arena.villager.trait.ScaredTrait; +import plugily.projects.villagedefense.utils.NearbyUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; + +public class VillagerAiManager { + + public static final String VILLAGER_PERSONALITY_METADATA = "VD_VILLAGER_PERSONA"; + public static final String VILLAGER_PERSONALITY_CHOSEN_HOME_ID = "VD_VILLAGER_PERSONA_CHOSEN_HOME"; + + private final @Getter Map> places = new EnumMap<>(Place.class); + private final List personalities = new ArrayList<>(); + private final List registeredTraits = new ArrayList<>(); + private final Arena arena; + + public VillagerAiManager(Arena arena) { + this.arena = arena; + registeredTraits.add(new ScaredTrait(this)); + registeredTraits.add(new FishermanTrait(this)); + registeredTraits.add(new BabyTrait()); + registeredTraits.add(new AlchemistTrait(this)); + registeredTraits.add(new BraveTrait(this)); + } + + public void registerArenaPlace(Place place, Location location) { + if (!places.containsKey(place)) { + places.put(place, new ArrayList<>(Collections.singletonList(location))); + } else { + places.get(place).add(location); + } + } + + public void doApplyVillagerPersonality(Villager villager) { + //based on 10 villagers per arena we will apply personalities + //first set brave villager in the village then others, all else as scared + if (personalities.stream().noneMatch(personality -> personality == Personality.BRAVE)) { + villager.getEquipment().setItemInMainHand(new ItemStack(Material.IRON_SWORD)); + villager.setMetadata(VILLAGER_PERSONALITY_METADATA, new FixedMetadataValue(arena.getPlugin(), Personality.BRAVE.name())); + personalities.add(Personality.BRAVE); + } else if (personalities.stream().noneMatch(personality -> personality == Personality.ALCHEMIST)) { + villager.getEquipment().setItemInMainHand(new ItemStack(Material.SPLASH_POTION)); + villager.setMetadata(VILLAGER_PERSONALITY_METADATA, new FixedMetadataValue(arena.getPlugin(), Personality.ALCHEMIST.name())); + personalities.add(Personality.ALCHEMIST); + } else if (personalities.stream().noneMatch(personality -> personality == Personality.FISHERMAN)) { + villager.getEquipment().setItemInMainHand(new ItemStack(Material.FISHING_ROD)); + villager.setMetadata(VILLAGER_PERSONALITY_METADATA, new FixedMetadataValue(arena.getPlugin(), Personality.FISHERMAN.name())); + personalities.add(Personality.FISHERMAN); + } else if (personalities.stream().filter(personality -> personality == Personality.BABY).count() < 2) { + villager.setMetadata(VILLAGER_PERSONALITY_METADATA, new FixedMetadataValue(arena.getPlugin(), Personality.BABY.name())); + villager.setBaby(); + personalities.add(Personality.BABY); + } else { + villager.setMetadata(VILLAGER_PERSONALITY_METADATA, new FixedMetadataValue(arena.getPlugin(), Personality.SCARED.name())); + personalities.add(Personality.SCARED); + } + List homes = places.get(Place.VILLAGER_HOME_ZONE); + villager.setMetadata(VILLAGER_PERSONALITY_CHOSEN_HOME_ID, new FixedMetadataValue(arena.getPlugin(), ThreadLocalRandom.current().nextInt(homes.size()))); + } + + public void clearCache() { + personalities.clear(); + } + + public void doRetreatVillagers() { + for (Villager villager : arena.getVillagers()) { + Personality personality = Personality.valueOf(villager.getMetadata(VILLAGER_PERSONALITY_METADATA).get(0).asString()); + for (GenericTrait trait : registeredTraits) { + if (trait.getPersonality() == personality) { + trait.onRetreat(arena, villager); + break; + } + } + } + } + + public void doStartPathfinder(Villager villager, Location location, PathfinderCallback callback) { + Pathfinder pathfinder = villager.getPathfinder(); + double speed = ThreadLocalRandom.current().nextDouble(0.05, 0.25); + new BukkitRunnable() { + @Override + public void run() { + if (!villager.isValid() || arena.getArenaState() != ArenaState.IN_GAME) { + this.cancel(); + return; + } + pathfinder.moveTo(location, 1.35 + speed); + for (Block block : NearbyUtils.getNearbyBlocks(villager.getLocation(), 2)) { + if (block.getBlockData() instanceof Door door) { + if (door.getHalf() == Bisected.Half.BOTTOM || block.hasMetadata("VD_DOOR_LOCK")) { + continue; + } + door.setOpen(true); + block.setBlockData(door, true); + block.setMetadata("VD_DOOR_LOCK", new FixedMetadataValue(arena.getPlugin(), true)); + Bukkit.getScheduler().runTaskLater(arena.getPlugin(), () -> { + block.removeMetadata("VD_DOOR_LOCK", arena.getPlugin()); + Door doorBlock = (Door) block.getBlockData(); + if (block.getType() == Material.AIR || !doorBlock.isOpen()) { + return; + } + doorBlock.setOpen(false); + block.setBlockData(doorBlock); + }, 40); + } + } + if (villager.getLocation().distanceSquared(location) <= 2) { + callback.onPathComplete(villager, location); + this.cancel(); + } + } + }.runTaskTimer(arena.getPlugin(), 0, 5); + } + + public void doSocializeVillagers() { + for (Villager villager : arena.getVillagers()) { + Personality personality = Personality.valueOf(villager.getMetadata(VILLAGER_PERSONALITY_METADATA).get(0).asString()); + for (GenericTrait trait : registeredTraits) { + if (trait.getPersonality() == personality) { + trait.onSocialize(arena, villager); + break; + } + } + } + } + + public enum Place { + VILLAGER_SOCIAL_ZONE, + VILLAGER_HOME_ZONE, + VILLAGER_ESCAPE_ZONE, + VILLAGER_FISHING_ZONE + } + + public enum Personality { + BABY, + SCARED, + BRAVE, + ALCHEMIST, + FISHERMAN + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/trait/AlchemistTrait.java b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/AlchemistTrait.java new file mode 100644 index 000000000..d0207c756 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/AlchemistTrait.java @@ -0,0 +1,127 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager.trait; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.ThrownPotion; +import org.bukkit.entity.Villager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.villager.VillagerAiAnimations; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; +import plugily.projects.villagedefense.utils.NearbyUtils; + +import java.util.concurrent.ThreadLocalRandom; + +public class AlchemistTrait implements GenericTrait { + + private final Main plugin = JavaPlugin.getPlugin(Main.class); + private final VillagerAiManager aiManager; + + public AlchemistTrait(VillagerAiManager aiManager) { + this.aiManager = aiManager; + } + + @Override + public VillagerAiManager.Personality getPersonality() { + return VillagerAiManager.Personality.ALCHEMIST; + } + + @Override + public void onSocialize(Arena arena, Villager villager) { + int roll = ThreadLocalRandom.current().nextInt(0, 3); + if (roll == 2) { + doPotionTricks(villager); + } + } + + private void doPotionTricks(Villager villager) { + ItemStack cachedItem = villager.getEquipment().getItemInMainHand(); + int eatTime = ThreadLocalRandom.current().nextInt(40, 65); + VillagerAiAnimations.makeEntityEat(villager, new ItemStack(Material.POTION), eatTime, () -> { + if (ThreadLocalRandom.current().nextBoolean()) { + villager.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 70, 0)); + villager.getWorld().playSound(villager.getLocation(), XSound.ENTITY_VILLAGER_CELEBRATE.parseSound(), 1.0f, 0.75f); + } else { + villager.addPotionEffect(new PotionEffect(PotionEffectType.GLOWING, 20 * 7, 0)); + villager.getWorld().playSound(villager.getLocation(), XSound.ENTITY_VILLAGER_YES.parseSound(), 1.0f, 1.0f); + } + villager.getEquipment().setItemInMainHand(cachedItem); + }); + } + + @Override + public void onRetreat(Arena arena, Villager villager) { + new BukkitRunnable() { + @Override + public void run() { + if (!arena.isFighting() || villager.isDead() || villager.hasMetadata("VD_ALCHEMIST_RETREAT")) { + this.cancel(); + return; + } + ItemStack cachedItem = villager.getEquipment().getItemInMainHand(); + for (Entity entity : villager.getNearbyEntities(5, 5, 5)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + VillagerAiAnimations.makeEntityLookAt(villager, ((LivingEntity) entity).getEyeLocation()); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + villager.setMetadata("VD_ALCHEMIST_RETREAT", new FixedMetadataValue(plugin, true)); + ItemStack potion = new ItemStack(Material.SPLASH_POTION); + PotionMeta meta = (PotionMeta) potion.getItemMeta(); + meta.addCustomEffect(new PotionEffect(PotionEffectType.HEAL, 5, 1), true); + potion.setItemMeta(meta); + ThrownPotion thrownPotion = villager.getWorld().spawn(villager.getEyeLocation(), ThrownPotion.class); + thrownPotion.setItem(potion); + thrownPotion.setPotionMeta(meta); + Vector direction = entity.getLocation().toVector().subtract(villager.getEyeLocation().toVector()).normalize(); + thrownPotion.setVelocity(direction.multiply(1.5)); + villager.getEquipment().setItemInMainHand(null); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + int homeIndex = villager.getMetadata(VillagerAiManager.VILLAGER_PERSONALITY_CHOSEN_HOME_ID).get(0).asInt(); + Location home = NearbyUtils.getRandomNearbyLocation(aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_HOME_ZONE).get(homeIndex), 2); + aiManager.doStartPathfinder(villager, home, (v, l) -> { + }); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + villager.getEquipment().setItemInMainHand(cachedItem); + villager.removeMetadata("VD_ALCHEMIST_RETREAT", plugin); + }, 20 * 10); + }, 20); + }, 20); + this.cancel(); + return; + } + } + }.runTaskTimer(plugin, 0, 30); + } +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/trait/BabyTrait.java b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/BabyTrait.java new file mode 100644 index 000000000..ab74971c6 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/BabyTrait.java @@ -0,0 +1,42 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager.trait; + +import org.bukkit.entity.Villager; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; + +public class BabyTrait implements GenericTrait { + + @Override + public VillagerAiManager.Personality getPersonality() { + return VillagerAiManager.Personality.BABY; + } + + @Override + public void onSocialize(Arena arena, Villager villager) { + //baby doesn't socialize + } + + @Override + public void onRetreat(Arena arena, Villager villager) { + //baby doesn't retreat + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/trait/BraveTrait.java b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/BraveTrait.java new file mode 100644 index 000000000..4e95f069b --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/BraveTrait.java @@ -0,0 +1,85 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager.trait; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Villager; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.villager.VillagerAiAnimations; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; +import plugily.projects.villagedefense.utils.NearbyUtils; + +public class BraveTrait implements GenericTrait { + + private final Main plugin = JavaPlugin.getPlugin(Main.class); + private final VillagerAiManager aiManager; + + public BraveTrait(VillagerAiManager aiManager) { + this.aiManager = aiManager; + } + + @Override + public VillagerAiManager.Personality getPersonality() { + return VillagerAiManager.Personality.BRAVE; + } + + @Override + public void onSocialize(Arena arena, Villager villager) { + } + + @Override + public void onRetreat(Arena arena, Villager villager) { + double healthPercent = villager.getHealth() / villager.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue(); + if (healthPercent <= 0.5) { + int homeIndex = villager.getMetadata(VillagerAiManager.VILLAGER_PERSONALITY_CHOSEN_HOME_ID).get(0).asInt(); + Location home = NearbyUtils.getRandomNearbyLocation(aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_HOME_ZONE).get(homeIndex), 2); + aiManager.doStartPathfinder(villager, home, (v, l) -> { + }); + return; + } + new BukkitRunnable() { + @Override + public void run() { + if (!arena.isFighting() || villager.isDead() || villager.hasMetadata("VD_BRAVE_RETREAT")) { + this.cancel(); + return; + } + for (Entity entity : villager.getNearbyEntities(3, 3, 3)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + VillagerAiAnimations.makeEntityLookAt(villager, ((LivingEntity) entity).getEyeLocation()); + villager.setJumping(true); + ((LivingEntity) entity).damage(2, villager); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + villager.setJumping(false); + }, 20); + return; + } + } + }.runTaskTimer(plugin, 0, 40); + } +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/trait/FishermanTrait.java b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/FishermanTrait.java new file mode 100644 index 000000000..82a2ff321 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/FishermanTrait.java @@ -0,0 +1,202 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager.trait; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Bat; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Item; +import org.bukkit.entity.Villager; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.villager.VillagerAiAnimations; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; +import plugily.projects.villagedefense.utils.NearbyUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class FishermanTrait implements GenericTrait { + + private final VillagerAiManager aiManager; + private final List fishedItems = Arrays.asList( + new ItemStack(Material.COD), + new ItemStack(Material.SALMON), + new ItemStack(Material.TROPICAL_FISH), + new ItemStack(Material.ROTTEN_FLESH) + ); + + public FishermanTrait(VillagerAiManager aiManager) { + this.aiManager = aiManager; + } + + @Override + public VillagerAiManager.Personality getPersonality() { + return VillagerAiManager.Personality.FISHERMAN; + } + + @Override + public void onSocialize(Arena arena, Villager villager) { + //50% chance to socialize or go fishing + if (ThreadLocalRandom.current().nextBoolean()) { + List socialZones = aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_SOCIAL_ZONE); + Location target = NearbyUtils.getRandomNearbyLocation(socialZones.get(ThreadLocalRandom.current().nextInt(socialZones.size())), 3); + aiManager.doStartPathfinder(villager, target, (v, l) -> { + }); + return; + } + doGoFishing(arena, villager); + } + + private void doGoFishing(Arena arena, Villager villager) { + List fishingZones = aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_FISHING_ZONE); + Location moveLocation = fishingZones.get(ThreadLocalRandom.current().nextInt(fishingZones.size())); + aiManager.doStartPathfinder(villager, moveLocation, (v, l) -> { + villager.setAI(false); + launchRope(arena, villager); + }); + } + + private void launchRope(Arena arena, Villager villager) { + for (Block block : NearbyUtils.getNearbyBlocks(villager.getLocation(), 5)) { + if (block.getType() == Material.WATER) { + if (block.getRelative(BlockFace.UP).getType() != Material.AIR) { + continue; + } else if (block.getRelative(BlockFace.NORTH).getType() != Material.WATER && !isNearbyWater(block.getRelative(BlockFace.NORTH))) { + continue; + } else if (block.getRelative(BlockFace.EAST).getType() != Material.WATER && !isNearbyWater(block.getRelative(BlockFace.EAST))) { + continue; + } else if (block.getRelative(BlockFace.SOUTH).getType() != Material.WATER && !isNearbyWater(block.getRelative(BlockFace.SOUTH))) { + continue; + } else if (block.getRelative(BlockFace.WEST).getType() != Material.WATER && !isNearbyWater(block.getRelative(BlockFace.WEST))) { + continue; + } + Location initialLocation = block.getLocation().add(0, 0.25, 0); + Bat inWater = (Bat) villager.getWorld().spawnEntity(initialLocation, EntityType.BAT, CreatureSpawnEvent.SpawnReason.CUSTOM, e -> { + e.setInvisible(true); + e.setInvulnerable(true); + e.setSilent(true); + }); + Bat atLand = (Bat) villager.getWorld().spawnEntity(villager.getEyeLocation().add(0, -0.25, 0), EntityType.BAT, CreatureSpawnEvent.SpawnReason.CUSTOM, e -> { + e.setInvisible(true); + e.setInvulnerable(true); + e.setSilent(true); + }); + inWater.setAI(false); + atLand.setAI(false); + inWater.setLeashHolder(atLand); + VillagerAiAnimations.makeEntityLookAt(villager, initialLocation); + new BukkitRunnable() { + int ticks = 0; + + @Override + public void run() { + if (ticks % 20 == 0) { + inWater.teleport(initialLocation.add(ThreadLocalRandom.current().nextDouble(0, 0.15), 0, ThreadLocalRandom.current().nextDouble(0, 0.15))); + } + if (ticks == 20 * 10) { + Item item = VillagerAiAnimations.throwItemTowardsEntity(new ItemStack(Material.COD), inWater.getLocation(), villager); + item.setCanPlayerPickup(false); + item.setCanMobPickup(false); + ItemStack fishedItem = rollFishedItem(); + Bukkit.getScheduler().runTaskLater(arena.getPlugin(), () -> { + item.remove(); + villager.getEquipment().setItemInMainHand(fishedItem); + }, 30); + inWater.remove(); + atLand.remove(); + Bukkit.getScheduler().runTaskLater(arena.getPlugin(), () -> { + Location location = villager.getLocation(); + VillagerAiAnimations.makeEntityLookAt(villager, location.clone() + .add( + location.getDirection().getX() * 0.5, + -0.35, + location.getDirection().getZ() * 0.5 + )); + double healthPercent = villager.getHealth() / villager.getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue(); + if (healthPercent <= 0.75) { + VillagerAiAnimations.makeEntityEat(villager, fishedItem, 50, () -> { + if (fishedItem.getType() == Material.ROTTEN_FLESH) { + villager.damage(1.0); + villager.getWorld().playSound(villager.getLocation(), XSound.ENTITY_VILLAGER_NO.parseSound(), 1.0f, 1.0f); + } else { + villager.setHealth(Math.min(villager.getHealth() + 2.0, VersionUtils.getMaxHealth(villager))); + } + villager.setCustomName(NewCreatureUtils.getHealthNameTag(villager)); + Bukkit.getScheduler().runTaskLater(arena.getPlugin(), () -> { + villager.setAI(true); + villager.getEquipment().setItemInMainHand(new ItemStack(Material.FISHING_ROD)); + }, 15); + }); + } else { + Bukkit.getScheduler().runTaskLater(arena.getPlugin(), () -> { + villager.setAI(true); + villager.getEquipment().setItemInMainHand(new ItemStack(Material.FISHING_ROD)); + }, 15); + } + }, 20 * 2); + this.cancel(); + return; + } + ticks += 2; + } + }.runTaskTimer(arena.getPlugin(), 0, 2); + return; + } + } + } + + private ItemStack rollFishedItem() { + return fishedItems.get(ThreadLocalRandom.current().nextInt(fishedItems.size())); + } + + private boolean isNearbyWater(Block block) { + if (block.getRelative(BlockFace.NORTH).getType() != Material.WATER) { + return false; + } else if (block.getRelative(BlockFace.EAST).getType() != Material.WATER) { + return false; + } else if (block.getRelative(BlockFace.SOUTH).getType() != Material.WATER) { + return false; + } else { + return block.getRelative(BlockFace.WEST).getType() == Material.WATER; + } + } + + @Override + public void onRetreat(Arena arena, Villager villager) { + int homeIndex = villager.getMetadata(VillagerAiManager.VILLAGER_PERSONALITY_CHOSEN_HOME_ID).get(0).asInt(); + Location home = NearbyUtils.getRandomNearbyLocation(aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_HOME_ZONE).get(homeIndex), 2); + + if (home.distanceSquared(villager.getLocation()) >= 6) { + aiManager.doStartPathfinder(villager, home, (v, l) -> { + }); + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/trait/GenericTrait.java b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/GenericTrait.java new file mode 100644 index 000000000..139e4345e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/GenericTrait.java @@ -0,0 +1,33 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager.trait; + +import org.bukkit.entity.Villager; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; + +public interface GenericTrait { + + VillagerAiManager.Personality getPersonality(); + + void onSocialize(Arena arena, Villager villager); + + void onRetreat(Arena arena, Villager villager); + +} diff --git a/src/main/java/plugily/projects/villagedefense/arena/villager/trait/ScaredTrait.java b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/ScaredTrait.java new file mode 100644 index 000000000..daec81fac --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/arena/villager/trait/ScaredTrait.java @@ -0,0 +1,192 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.arena.villager.trait; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.villager.CompletionCallback; +import plugily.projects.villagedefense.arena.villager.VillagerAiAnimations; +import plugily.projects.villagedefense.arena.villager.VillagerAiManager; +import plugily.projects.villagedefense.utils.NearbyUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class ScaredTrait implements GenericTrait { + + private final Main plugin = JavaPlugin.getPlugin(Main.class); + private final List randomFoods = Arrays.asList( + new ItemStack(Material.BREAD), + new ItemStack(Material.COOKED_CHICKEN), + new ItemStack(Material.COOKIE), + new ItemStack(Material.CARROT), + new ItemStack(Material.BEETROOT_SOUP), + new ItemStack(Material.POTION) + ); + private final VillagerAiManager aiManager; + + public ScaredTrait(VillagerAiManager aiManager) { + this.aiManager = aiManager; + } + + @Override + public VillagerAiManager.Personality getPersonality() { + return VillagerAiManager.Personality.SCARED; + } + + @Override + public void onSocialize(Arena arena, Villager villager) { + List socialZones = aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_SOCIAL_ZONE); + Location target = NearbyUtils.getRandomNearbyLocation(socialZones.get(ThreadLocalRandom.current().nextInt(socialZones.size())), 3); + collectNearbyBabyAndMoveTo(villager, target, () -> { + int roll = ThreadLocalRandom.current().nextInt(0, 3); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (roll == 1) { + doReadingSession(villager); + } else if (roll == 2) { + doEatingSession(villager); + } else { + int generousRoll = ThreadLocalRandom.current().nextInt(0, 4); + if (generousRoll == 3) { + doGenerousDonation(villager); + } + } + }, 20L * ThreadLocalRandom.current().nextInt(2, 4)); + }); + } + + private void doReadingSession(Villager villager) { + villager.getEquipment().setItemInMainHand(new ItemStack(Material.BOOK)); + new BukkitRunnable() { + int ticks = 0; + + @Override + public void run() { + if (ticks >= 20 * 8) { + villager.getEquipment().setItemInMainHand(null); + this.cancel(); + return; + } + Location location = villager.getLocation(); + VillagerAiAnimations.makeEntityLookAt(villager, location.clone() + .add( + location.getDirection().getX() * 0.5, + -0.35, + location.getDirection().getZ() * 0.5 + )); + if (ticks % 15 == 0) { + villager.getWorld().spawnParticle(Particle.VILLAGER_HAPPY, villager.getEyeLocation().add(0, 0.25, 0), 4, 0.2, 0.1, 0.2, 0); + } + ticks += 5; + } + }.runTaskTimer(plugin, 0, 5); + } + + private void doEatingSession(Villager villager) { + ItemStack rolledFood = randomFoods.get(ThreadLocalRandom.current().nextInt(randomFoods.size())); + villager.getEquipment().setItemInMainHand(rolledFood); + int eatTime = ThreadLocalRandom.current().nextInt(40, 65); + VillagerAiAnimations.makeEntityEat(villager, rolledFood, eatTime, () -> { + villager.setHealth(Math.min(villager.getHealth() + 1.0, VersionUtils.getMaxHealth(villager))); + villager.setCustomName(NewCreatureUtils.getHealthNameTag(villager)); + if (ThreadLocalRandom.current().nextBoolean()) { + villager.getWorld().playSound(villager.getLocation(), XSound.ENTITY_VILLAGER_YES.parseSound(), 1.0f, 1.0f); + } else { + villager.getWorld().playSound(villager.getLocation(), XSound.ENTITY_VILLAGER_AMBIENT.parseSound(), 1.0f, 1.0f); + } + }); + } + + private void doGenerousDonation(Villager villager) { + for (Entity entity : villager.getNearbyEntities(12, 5, 12)) { + if (!(entity instanceof Player player)) { + continue; + } + if (player.getFoodLevel() < 20) { + aiManager.doStartPathfinder(villager, player.getLocation(), (v, l) -> { + villager.getWorld().playSound(villager.getLocation(), XSound.ENTITY_VILLAGER_TRADE.parseSound(), 1.0f, 1.0f); + VillagerAiAnimations.makeEntityLookAt(villager, player.getEyeLocation()); + villager.getEquipment().setItemInMainHand(new ItemStack(Material.APPLE)); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + //generous donation towards player + VillagerAiAnimations.throwItemTowardsEntity(new ItemStack(Material.APPLE), villager.getEyeLocation(), player); + villager.getEquipment().setItemInMainHand(null); + }, 20 * 2); + }); + return; + } + } + } + + @Override + public void onRetreat(Arena arena, Villager villager) { + int homeIndex = villager.getMetadata(VillagerAiManager.VILLAGER_PERSONALITY_CHOSEN_HOME_ID).get(0).asInt(); + Location home = NearbyUtils.getRandomNearbyLocation(aiManager.getPlaces().get(VillagerAiManager.Place.VILLAGER_HOME_ZONE).get(homeIndex), 2); + collectNearbyBabyAndMoveTo(villager, home, () -> { + }); + } + + private void collectNearbyBabyAndMoveTo(Villager villager, Location moveLocation, CompletionCallback callback) { + if (villager.getPassengers().isEmpty()) { + for (Entity nearby : villager.getNearbyEntities(7, 7, 7)) { + if (!(nearby instanceof Villager nearbyVillager)) { + continue; + } + if (nearbyVillager.isAdult() || nearbyVillager.hasMetadata("VD_BABY_ESCORTED")) { + continue; + } + nearbyVillager.setMetadata("VD_BABY_ESCORTED", new FixedMetadataValue(plugin, true)); + aiManager.doStartPathfinder(villager, nearbyVillager.getLocation(), (v, l) -> { + nearbyVillager.setInvulnerable(true); + villager.addPassenger(nearbyVillager); + aiManager.doStartPathfinder(villager, moveLocation, (v2, l2) -> { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (villager.getPassengers().isEmpty()) { + return; + } + villager.removePassenger(nearbyVillager); + nearbyVillager.setInvulnerable(false); + nearbyVillager.removeMetadata("VD_BABY_ESCORTED", plugin); + }, 20 * 2); + }); + }); + return; + } + } + aiManager.doStartPathfinder(villager, moveLocation, (v, l) -> { + callback.onComplete(); + }); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/boot/AdditionalValueInitializer.java b/src/main/java/plugily/projects/villagedefense/boot/AdditionalValueInitializer.java index 4b2075c34..8246f304a 100644 --- a/src/main/java/plugily/projects/villagedefense/boot/AdditionalValueInitializer.java +++ b/src/main/java/plugily/projects/villagedefense/boot/AdditionalValueInitializer.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.boot; @@ -57,10 +57,6 @@ private void registerConfigOptions() { getConfigPreferences().registerOption("RESPAWN_IN_GAME_JOIN", new ConfigOption("Respawn.In-Game-Join", true)); getConfigPreferences().registerOption("LIMIT_WAVE_UNLIMITED", new ConfigOption("Limit.Wave.Unlimited", true)); getConfigPreferences().registerOption("LIMIT_ENTITY_BUY_AFTER_DEATH", new ConfigOption("Limit.Wave.Entity-Buy-After-Death", true)); - getConfigPreferences().registerOption("ZOMBIE_HEALTHBAR", new ConfigOption("Creatures.Health-Bar", true)); - getConfigPreferences().registerOption("NAME_VISIBILITY_GOLEM", new ConfigOption("Name-Visibility.Golem", true)); - getConfigPreferences().registerOption("NAME_VISIBILITY_WOLF", new ConfigOption("Name-Visibility.Wolf", true)); - getConfigPreferences().registerOption("NAME_VISIBILITY_VILLAGER", new ConfigOption("Name-Visibility.Villager", true)); } private void registerStatistics() { @@ -72,8 +68,6 @@ private void registerStatistics() { private void registerPermission() { getPermissionsManager().registerPermissionCategory("ORBS_BOOSTER", new PermissionCategory("Orbs-Boost", null)); - getPermissionsManager().registerPermissionCategory("PLAYER_SPAWN_LIMIT_WOLVES", new PermissionCategory("Spawn-Limit.Wolves", null)); - getPermissionsManager().registerPermissionCategory("PLAYER_SPAWN_LIMIT_GOLEMS", new PermissionCategory("Spawn-Limit.Golems", null)); getPermissionsManager().registerPermission("KIT_PREMIUM_UNLOCK", new Permission("Basic.Premium-Kits", "villagedefense.kits.premium")); } @@ -131,28 +125,10 @@ private void registerArenaOptions() { * It's counting up to 20 and resets to 0. * If value is equal 5 or 15 and wave is enough high special * zombie units will be spawned in addition to standard ones. + * + * @deprecated subject to removal */ getArenaOptionManager().registerArenaOption("ZOMBIE_SPAWN_COUNTER", new ArenaOption("null", 0)); - /** - * Value describes how many seconds zombie spawn system should hold and not spawn any entity. - * This value reduces server load and lag preventing spawning hordes at once. - * Example when wave is 30 counter will set value to 2 holding zombies spawn for 2 seconds - * Algorithm: floor(wave / 15) - */ - getArenaOptionManager().registerArenaOption("ZOMBIE_IDLE_PROCESS", new ArenaOption("null", 0)); - /** - * Value that describes the multiplier of extra health zombies will receive. - * Current health + multiplier. - *

- * Since 4.0.0 there is maximum amount of 750 to spawn in wave. - * The more value will be above 750 the stronger zombies will be. - *

- * Zombies amount is based on algorithm: ceil((players * 0.5) * (wave * wave) / 2) - * Difficulty multiplier is based on: ceil((ceil((players * 0.5) * (wave * wave) / 2) - 750) / 15) - * Example: 12 players in wave 20 will receive 30 difficulty multiplier. - * So each zombie will get 30 HP more, harder! - */ - getArenaOptionManager().registerArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER", new ArenaOption("null", 1)); } private ConfigPreferences getConfigPreferences() { diff --git a/src/main/java/plugily/projects/villagedefense/boot/MessageInitializer.java b/src/main/java/plugily/projects/villagedefense/boot/MessageInitializer.java index e8f39b320..09dfe0ffd 100644 --- a/src/main/java/plugily/projects/villagedefense/boot/MessageInitializer.java +++ b/src/main/java/plugily/projects/villagedefense/boot/MessageInitializer.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.boot; @@ -40,6 +40,7 @@ public MessageInitializer(Main plugin) { } public void registerMessages() { + registerGoldMessages(); getMessageManager().registerMessage("COMMANDS_ADMIN_ADDED_ORBS", new Message("Commands.Admin.Added-Orbs", "")); getMessageManager().registerMessage("COMMANDS_ADMIN_RECEIVED_ORBS", new Message("Commands.Admin.Received-Orbs", "")); @@ -53,12 +54,19 @@ public void registerMessages() { getMessageManager().registerMessage("IN_GAME_MESSAGES_ADMIN_REMOVED_ZOMBIES", new Message("In-Game.Messages.Admin.Removed.Zombies", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_ADMIN_REMOVED_WOLVES", new Message("In-Game.Messages.Admin.Removed.Wolves", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_ADMIN_CHANGED_WAVE", new Message("In-Game.Messages.Admin.Changed.Wave", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_ADMIN_NOTHING_T0_CLEAN", new Message("In-Game.Messages.Admin.Nothing-To-Clean", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_ROTTEN_FLESH_LEVEL_UP", new Message("In-Game.Messages.Village.Rotten-Flesh-Level-Up", "")); - getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_FEEL_REFRESHED", new Message("In-Game.Messages.Village.You-Feel-Refreshed", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_DIED", new Message("In-Game.Messages.Village.Villager.Died", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_NAMES", new Message("In-Game.Messages.Village.Villager.Names", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_SPECIAL_OFFER", new Message("In-Game.Messages.Village.Villager.Special-Offer", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_OFFERING_SALE", new Message("In-Game.Messages.Village.Villager.Offering-Sale", "")); + + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_ROTTEN_OFFER", new Message("In-Game.Messages.Village.Villager.Rotten-Offer", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_ROTTEN_SALE", new Message("In-Game.Messages.Village.Villager.Rotten-Sale", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_VILLAGER_PINATA_EVENT", new Message("In-Game.Messages.Village.Villager.Pinata-Event", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_STUCK_ZOMBIES", new Message("In-Game.Messages.Village.Wave.Stuck-Zombies", "")); /*unused*/ getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_SPECTATOR_WARNING", new Message("In-Game.Messages.Village.Wave.Spectator-Warning", "")); @@ -68,13 +76,18 @@ public void registerMessages() { getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_STARTED", new Message("In-Game.Messages.Village.Wave.Started", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_START", new Message("In-Game.Messages.Village.Wave.Title.Start", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_END", new Message("In-Game.Messages.Village.Wave.Title.End", "")); - getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ORBS_PICKUP", new Message("In-Game.Messages.Village.Orbs.Pickup", "")); - getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_SPAWN", new Message("In-Game.Messages.Village.Entities.Wolf.Spawn", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_STARTING_3", new Message("In-Game.Messages.Village.Wave.Title.Start-3", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_STARTING_2", new Message("In-Game.Messages.Village.Wave.Title.Start-2", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_TITLE_STARTING_1", new Message("In-Game.Messages.Village.Wave.Title.Start-1", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_RIDE_OTHER", new Message("In-Game.Messages.Village.Entities.Cant-Ride-Other", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_UPGRADE_THIS", new Message("In-Game.Messages.Village.Entities.Cant-Upgrade-This", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_UPGRADE_BABY", new Message("In-Game.Messages.Village.Entities.Cant-Upgrade-Baby", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_UPGRADE_OTHER", new Message("In-Game.Messages.Village.Entities.Cant-Upgrade-Other", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_NAME", new Message("In-Game.Messages.Village.Entities.Wolf.Name", "")); - getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_DEATH", new Message("In-Game.Messages.Village.Entities.Wolf.Death", "")); - getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_SPAWN", new Message("In-Game.Messages.Village.Entities.Golem.Spawn", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_WOLF_BABY_NAME", new Message("In-Game.Messages.Village.Entities.Wolf.Baby-Name", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_NAME", new Message("In-Game.Messages.Village.Entities.Golem.Name", "")); - getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_CANT_RIDE_OTHER", new Message("In-Game.Messages.Village.Entities.Golem.Cant-Ride-Other", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_ZOMBIE_STUNNED_NAME", new Message("In-Game.Messages.Village.Entities.Zombie.Stunned-Name", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_ZOMBIE_FRENZY_NAME", new Message("In-Game.Messages.Village.Entities.Zombie.Frenzy-Name", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_GUI", new Message("In-Game.Messages.Village.Shop.GUI", "")); @@ -83,7 +96,13 @@ public void registerMessages() { getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_MOB_LIMIT_REACHED", new Message("In-Game.Messages.Village.Shop.Mob-Limit-Reached", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_NOT_ENOUGH_CURRENCY", new Message("In-Game.Messages.Village.Shop.Not-Enough-Currency", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_CURRENCY", new Message("In-Game.Messages.Village.Shop.Currency", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_WAVE_LOCK", new Message("In-Game.Messages.Village.Shop.Wave-Lock", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_ITEM_LOCKED", new Message("In-Game.Messages.Village.Shop.Item-Locked-Name", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_WAVE_STILL_LOCKED", new Message("In-Game.Messages.Village.Shop.Wave-Still-Locked", "")); getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_NOT_DEFINED", new Message("In-Game.Messages.Village.Shop.Not-Defined", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_NEW_OFFERS_AVAILABLE", new Message("In-Game.Messages.Village.Shop.New-Shop-Offers", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_SPECIAL_OFFER", new Message("In-Game.Messages.Village.Shop.Special-Offer", "")); + getMessageManager().registerMessage("IN_GAME_MESSAGES_VILLAGE_SHOP_AUTO_ARMOR_EQUIPPED", new Message("In-Game.Messages.Village.Shop.Auto-Armor-Equipped", "")); getMessageManager().registerMessage("LEADERBOARD_STATISTICS_ORBS", new Message("Leaderboard.Statistics.Orbs", "")); @@ -109,174 +128,39 @@ public void registerMessages() { getMessageManager().registerMessage("UPGRADE_MENU_UPGRADES_DEFENSE_NAME", new Message("Upgrade-Menu.Upgrades.Final-Defense.Name", "")); getMessageManager().registerMessage("UPGRADE_MENU_UPGRADES_DEFENSE_DESCRIPTION", new Message("Upgrade-Menu.Upgrades.Final-Defense.Description", "")); - - //CLEANER KIT - - getMessageManager().registerMessage("KIT_CONTENT_CLEANER_NAME", new Message("Kit.Content.Cleaner.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_CLEANER_DESCRIPTION", new Message("Kit.Content.Cleaner.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_CLEANER_GAME_ITEM_NAME", new Message("Kit.Content.Cleaner.Game-Item.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_CLEANER_GAME_ITEM_DESCRIPTION", new Message("Kit.Content.Cleaner.Game-Item.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_CLEANER_CLEANED_MAP", new Message("Kit.Content.Cleaner.Cleaned.Map", "")); - getMessageManager().registerMessage("KIT_CONTENT_CLEANER_CLEANED_NOTHING", new Message("Kit.Content.Cleaner.Cleaned.Nothing", "")); - -//ZOMBIE_TELEPORTER KIT - - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_NAME", new Message("Kit.Content.Zombie-Teleporter.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_DESCRIPTION", new Message("Kit.Content.Zombie-Teleporter.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_GAME_ITEM_NAME", new Message("Kit.Content.Zombie-Teleporter.Game-Item.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_GAME_ITEM_DESCRIPTION", new Message("Kit.Content.Zombie-Teleporter.Game-Item.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_GAME_ITEM_GUI", new Message("Kit.Content.Zombie-Teleporter.Game-Item.GUI", "")); - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_TELEPORT_ZOMBIE", new Message("Kit.Content.Zombie-Teleporter.Teleport.Zombie", "")); - getMessageManager().registerMessage("KIT_CONTENT_ZOMBIE_TELEPORTER_TELEPORT_NOT_FOUND", new Message("Kit.Content.Zombie-Teleporter.Teleport.Not-Found", "")); - -//KNIGHT + //KNIGHT getMessageManager().registerMessage("KIT_CONTENT_KNIGHT_NAME", new Message("Kit.Content.Knight.Name", "")); getMessageManager().registerMessage("KIT_CONTENT_KNIGHT_DESCRIPTION", new Message("Kit.Content.Knight.Description", "")); -//LIGHT_TANK - - getMessageManager().registerMessage("KIT_CONTENT_LIGHT_TANK_NAME", new Message("Kit.Content.Light-Tank.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_LIGHT_TANK_DESCRIPTION", new Message("Kit.Content.Light-Tank.Description", "")); - -//ARCHER - - getMessageManager().registerMessage("KIT_CONTENT_ARCHER_NAME", new Message("Kit.Content.Archer.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_ARCHER_DESCRIPTION", new Message("Kit.Content.Archer.Description", "")); - -//PUNCHER - - getMessageManager().registerMessage("KIT_CONTENT_PUNCHER_NAME", new Message("Kit.Content.Puncher.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_PUNCHER_DESCRIPTION", new Message("Kit.Content.Puncher.Description", "")); - -//HEALER - - getMessageManager().registerMessage("KIT_CONTENT_HEALER_NAME", new Message("Kit.Content.Healer.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_HEALER_DESCRIPTION", new Message("Kit.Content.Healer.Description", "")); - -//LOOTER - - getMessageManager().registerMessage("KIT_CONTENT_LOOTER_NAME", new Message("Kit.Content.Looter.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_LOOTER_DESCRIPTION", new Message("Kit.Content.Looter.Description", "")); - -//RUNNER - - getMessageManager().registerMessage("KIT_CONTENT_RUNNER_NAME", new Message("Kit.Content.Runner.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_RUNNER_DESCRIPTION", new Message("Kit.Content.Runner.Description", "")); - -//MEDIUM_TANK - - getMessageManager().registerMessage("KIT_CONTENT_MEDIUM_TANK_NAME", new Message("Kit.Content.Medium-Tank.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_MEDIUM_TANK_DESCRIPTION", new Message("Kit.Content.Medium-Tank.Description", "")); - -//WORKER - - getMessageManager().registerMessage("KIT_CONTENT_WORKER_NAME", new Message("Kit.Content.Worker.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_WORKER_DESCRIPTION", new Message("Kit.Content.Worker.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_WORKER_GAME_ITEM_CHAT", new Message("Kit.Content.Worker.Game-Item.Chat", "")); - -//DOG_FRIEND - - getMessageManager().registerMessage("KIT_CONTENT_DOG_FRIEND_NAME", new Message("Kit.Content.Dog-Friend.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_DOG_FRIEND_DESCRIPTION", new Message("Kit.Content.Dog-Friend.Description", "")); - -//HARDCORE - - getMessageManager().registerMessage("KIT_CONTENT_HARDCORE_NAME", new Message("Kit.Content.Hardcore.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_HARDCORE_DESCRIPTION", new Message("Kit.Content.Hardcore.Description", "")); - -//GOLEM_FRIEND - - getMessageManager().registerMessage("KIT_CONTENT_GOLEM_FRIEND_NAME", new Message("Kit.Content.Golem-Friend.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_GOLEM_FRIEND_DESCRIPTION", new Message("Kit.Content.Golem-Friend.Description", "")); - -//TORNADO - - getMessageManager().registerMessage("KIT_CONTENT_TORNADO_NAME", new Message("Kit.Content.Tornado.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_TORNADO_DESCRIPTION", new Message("Kit.Content.Tornado.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_TORNADO_GAME_ITEM_NAME", new Message("Kit.Content.Tornado.Game-Item.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_TORNADO_GAME_ITEM_DESCRIPTION", new Message("Kit.Content.Tornado.Game-Item.Description", "")); - -//TERMINATOR - - getMessageManager().registerMessage("KIT_CONTENT_TERMINATOR_NAME", new Message("Kit.Content.Terminator.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_TERMINATOR_DESCRIPTION", new Message("Kit.Content.Terminator.Description", "")); - -//TELEPORTER - - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_NAME", new Message("Kit.Content.Teleporter.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_DESCRIPTION", new Message("Kit.Content.Teleporter.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_GAME_ITEM_NAME", new Message("Kit.Content.Teleporter.Game-Item.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_GAME_ITEM_DESCRIPTION", new Message("Kit.Content.Teleporter.Game-Item.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_GAME_ITEM_GUI", new Message("Kit.Content.Teleport.Game-Item.GUI", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_TELEPORT_VILLAGER", new Message("Kit.Content.Teleporter.Teleport.Villager", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_TELEPORT_WARNING", new Message("Kit.Content.Teleporter.Teleport.Warning", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_TELEPORT_PLAYER", new Message("Kit.Content.Teleporter.Teleport.Player", "")); - getMessageManager().registerMessage("KIT_CONTENT_TELEPORTER_TELEPORT_NOT_FOUND", new Message("Kit.Content.Teleporter.Teleport.Not-Found", "")); - -//HEAVY_TANK - - getMessageManager().registerMessage("KIT_CONTENT_HEAVY_TANK_NAME", new Message("Kit.Content.Heavy-Tank.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_HEAVY_TANK_DESCRIPTION", new Message("Kit.Content.Heavy-Tank.Description", "")); - -//SHOT_BOW - - getMessageManager().registerMessage("KIT_CONTENT_SHOT_BOW_NAME", new Message("Kit.Content.Shot-Bow.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_SHOT_BOW_DESCRIPTION", new Message("Kit.Content.Shot-Bow.Description", "")); - -//BLOCKER - - getMessageManager().registerMessage("KIT_CONTENT_BLOCKER_NAME", new Message("Kit.Content.Blocker.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_BLOCKER_DESCRIPTION", new Message("Kit.Content.Blocker.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_BLOCKER_GAME_ITEM_NAME", new Message("Kit.Content.Blocker.Game-Item.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_BLOCKER_GAME_ITEM_DESCRIPTION", new Message("Kit.Content.Blocker.Game-Item.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_BLOCKER_PLACE_SUCCESS", new Message("Kit.Content.Blocker.Place.Success", "")); - getMessageManager().registerMessage("KIT_CONTENT_BLOCKER_PLACE_FAIL", new Message("Kit.Content.Blocker.Place.Fail", "")); - -//PREMIUM_HARDCORE - - getMessageManager().registerMessage("KIT_CONTENT_PREMIUM_HARDCORE_NAME", new Message("Kit.Content.Premium-Hardcore.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_PREMIUM_HARDCORE_DESCRIPTION", new Message("Kit.Content.Premium-Hardcore.Description", "")); - -//MEDIC - - getMessageManager().registerMessage("KIT_CONTENT_MEDIC_NAME", new Message("Kit.Content.Medic.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_MEDIC_DESCRIPTION", new Message("Kit.Content.Medic.Description", "")); - -//WILD_NAKED - - getMessageManager().registerMessage("KIT_CONTENT_WILD_NAKED_NAME", new Message("Kit.Content.Wild-Naked.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_WILD_NAKED_DESCRIPTION", new Message("Kit.Content.Wild-Naked.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_WILD_NAKED_CANNOT_WEAR_ARMOR", new Message("Kit.Content.Wild-Naked.Cannot-Wear-Armor", "")); - -//WIZARD - - getMessageManager().registerMessage("KIT_CONTENT_WIZARD_NAME", new Message("Kit.Content.Wizard.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_WIZARD_DESCRIPTION", new Message("Kit.Content.Wizard.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_NAME", new Message("Kit.Content.Wizard.Game-Item.Essence.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_DESCRIPTION", new Message("Kit.Content.Wizard.Game-Item.Essence.Description", "")); - getMessageManager().registerMessage("KIT_CONTENT_WIZARD_GAME_ITEM_WAND_NAME", new Message("Kit.Content.Wizard.Game-Item.Wand.Name", "")); - getMessageManager().registerMessage("KIT_CONTENT_WIZARD_GAME_ITEM_WAND_DESCRIPTION", new Message("Kit.Content.Wizard.Game-Item.Wand.Description", "")); + //GENERAL FOR KITS + getMessageManager().registerMessage("KIT_LOCKED_TILL", new Message("Kit.Locked-Till", "")); + getMessageManager().registerMessage("KIT_ABILITY_UNLOCKED", new Message("Kit.Ability-Unlocked", "")); + getMessageManager().registerMessage("KIT_ABILITY_POWER_INCREASED", new Message("Kit.Ability-Power-Increased", "")); + getMessageManager().registerMessage("KIT_PASSIVE_POWER_INCREASED", new Message("Kit.Passive-Power-Increased", "")); + } + private void registerGoldMessages() { + getMessageManager().registerMessage("VD_GOLD_NEW_RECORD_REACHED", new Message("Gold-Messages.New-Record-Reached", "")); } private void registerLocales() { Arrays.asList(new Locale("Chinese (Traditional)", "简体中文", "zh_HK", "POEditor contributors", Arrays.asList("中文(傳統)", "中國傳統", "chinese_traditional", "zh")), - new Locale("Chinese (Simplified)", "简体中文", "zh_CN", "POEditor contributors", Arrays.asList("简体中文", "中文", "chinese", "chinese_simplified", "cn")), - new Locale("Czech", "Český", "cs_CZ", "POEditor contributors", Arrays.asList("czech", "cesky", "český", "cs")), - new Locale("Dutch", "Nederlands", "nl_NL", "POEditor contributors", Arrays.asList("dutch", "nederlands", "nl")), - new Locale("English", "English", "en_GB", "Tigerpanzer_02", Arrays.asList("default", "english", "en")), - new Locale("French", "Français", "fr_FR", "POEditor contributors", Arrays.asList("french", "francais", "français", "fr")), - new Locale("German", "Deutsch", "de_DE", "Tigerkatze and POEditor contributors", Arrays.asList("deutsch", "german", "de")), - new Locale("Italian", "Italiano", "it_IT", "POEditor contributors", Arrays.asList("italian", "italiano", "it")), - new Locale("Polish", "Polski", "pl_PL", "Plajer", Arrays.asList("polish", "polski", "pl")), - new Locale("Portuguese", "Português", "pt_PT", "POEditor contributors", Arrays.asList("portuguese", "pt-pt", "pt_pt")), - new Locale("Portuguese (BR)", "Português Brasileiro", "pt_BR", "POEditor contributors", Arrays.asList("brazilian", "brasil", "brasileiro", "pt-br", "pt_br")), - new Locale("Russian", "Pусский", "ru_RU", "POEditor contributors", Arrays.asList("russian", "pусский", "pyccknn", "russkiy", "ru")), - new Locale("Spanish", "Español", "es_ES", "POEditor contributors", Arrays.asList("spanish", "espanol", "español", "es")), - new Locale("Turkish", "Türk", "tr_TR", "POEditor contributors", Arrays.asList("turkish", "turk", "türk", "tr")), - new Locale("Vietnamese", "Việt", "vn_VN", "POEditor contributors", Arrays.asList("vietnamese", "viet", "việt", "vn"))) - .forEach(LocaleRegistry::registerLocale); + new Locale("Chinese (Simplified)", "简体中文", "zh_CN", "POEditor contributors", Arrays.asList("简体中文", "中文", "chinese", "chinese_simplified", "cn")), + new Locale("Czech", "Český", "cs_CZ", "POEditor contributors", Arrays.asList("czech", "cesky", "český", "cs")), + new Locale("Dutch", "Nederlands", "nl_NL", "POEditor contributors", Arrays.asList("dutch", "nederlands", "nl")), + new Locale("English", "English", "en_GB", "Tigerpanzer_02", Arrays.asList("default", "english", "en")), + new Locale("French", "Français", "fr_FR", "POEditor contributors", Arrays.asList("french", "francais", "français", "fr")), + new Locale("German", "Deutsch", "de_DE", "Tigerkatze and POEditor contributors", Arrays.asList("deutsch", "german", "de")), + new Locale("Italian", "Italiano", "it_IT", "POEditor contributors", Arrays.asList("italian", "italiano", "it")), + new Locale("Polish", "Polski", "pl_PL", "Plajer", Arrays.asList("polish", "polski", "pl")), + new Locale("Portuguese", "Português", "pt_PT", "POEditor contributors", Arrays.asList("portuguese", "pt-pt", "pt_pt")), + new Locale("Portuguese (BR)", "Português Brasileiro", "pt_BR", "POEditor contributors", Arrays.asList("brazilian", "brasil", "brasileiro", "pt-br", "pt_br")), + new Locale("Russian", "Pусский", "ru_RU", "POEditor contributors", Arrays.asList("russian", "pусский", "pyccknn", "russkiy", "ru")), + new Locale("Spanish", "Español", "es_ES", "POEditor contributors", Arrays.asList("spanish", "espanol", "español", "es")), + new Locale("Turkish", "Türk", "tr_TR", "POEditor contributors", Arrays.asList("turkish", "turk", "türk", "tr")), + new Locale("Vietnamese", "Việt", "vn_VN", "POEditor contributors", Arrays.asList("vietnamese", "viet", "việt", "vn"))) + .forEach(LocaleRegistry::registerLocale); } private MessageManager getMessageManager() { diff --git a/src/main/java/plugily/projects/villagedefense/boot/PlaceholderInitializer.java b/src/main/java/plugily/projects/villagedefense/boot/PlaceholderInitializer.java index e7b54f132..f3e608b15 100644 --- a/src/main/java/plugily/projects/villagedefense/boot/PlaceholderInitializer.java +++ b/src/main/java/plugily/projects/villagedefense/boot/PlaceholderInitializer.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.boot; @@ -24,6 +24,7 @@ import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; import plugily.projects.minigamesbox.classic.handlers.placeholder.Placeholder; import plugily.projects.minigamesbox.classic.handlers.placeholder.PlaceholderManager; +import plugily.projects.minigamesbox.classic.user.User; import plugily.projects.villagedefense.Main; import plugily.projects.villagedefense.arena.Arena; import plugily.projects.villagedefense.arena.ArenaRegistry; @@ -167,6 +168,21 @@ public String getValue(PluginArena arena) { return Integer.toString(arena.getArenaOption("ROTTEN_FLESH_AMOUNT")); } }); + getPlaceholderManager().registerPlaceholder(new Placeholder("orbs_amount", Placeholder.PlaceholderType.ARENA, Placeholder.PlaceholderExecutor.ALL) { + @Override + public String getValue(Player player, PluginArena arena) { + User user = plugin.getUserManager().getUser(player); + if(user.getArena() == null) { + return "0"; + } + return Integer.toString(user.getStatistic("ORBS")); + } + + @Override + public String getValue(PluginArena arena) { + return "undefined"; + } + }); } private PlaceholderManager getPlaceholderManager() { diff --git a/src/main/java/plugily/projects/villagedefense/commands/arguments/ArgumentsRegistry.java b/src/main/java/plugily/projects/villagedefense/commands/arguments/ArgumentsRegistry.java index adb5e8f19..615114973 100644 --- a/src/main/java/plugily/projects/villagedefense/commands/arguments/ArgumentsRegistry.java +++ b/src/main/java/plugily/projects/villagedefense/commands/arguments/ArgumentsRegistry.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.commands.arguments; @@ -23,7 +23,9 @@ import plugily.projects.villagedefense.commands.arguments.admin.AddOrbsArgument; import plugily.projects.villagedefense.commands.arguments.admin.ClearEntitiesArgument; import plugily.projects.villagedefense.commands.arguments.admin.RespawnArgument; +import plugily.projects.villagedefense.commands.arguments.admin.ScriptEngineDebugArgument; import plugily.projects.villagedefense.commands.arguments.admin.SetPriceArgument; +import plugily.projects.villagedefense.commands.arguments.admin.SetWaveUnlockArgument; import plugily.projects.villagedefense.commands.arguments.admin.arena.SetWaveArgument; /** @@ -46,5 +48,7 @@ public ArgumentsRegistry(Main plugin) { new ClearEntitiesArgument(this); new RespawnArgument(this); new SetPriceArgument(this); + new SetWaveUnlockArgument(this); + new ScriptEngineDebugArgument(this); } } diff --git a/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ClearEntitiesArgument.java b/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ClearEntitiesArgument.java index 25c6e7cfd..2ae68b4bb 100644 --- a/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ClearEntitiesArgument.java +++ b/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ClearEntitiesArgument.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.commands.arguments.admin; @@ -63,7 +63,7 @@ public void execute(CommandSender sender, String[] args) { switch(args[1].toLowerCase()) { case "villager": if(arena.getVillagers().isEmpty()) { - new MessageBuilder("KIT_CONTENT_CLEANER_CLEANED_NOTHING").asKey().send(sender); + new MessageBuilder("IN_GAME_MESSAGES_ADMIN_NOTHING_T0_CLEAN").asKey().send(sender); return; } for(Villager villager : arena.getVillagers()) { @@ -76,7 +76,7 @@ public void execute(CommandSender sender, String[] args) { break; case "zombie": if(arena.getEnemies().isEmpty()) { - new MessageBuilder("KIT_CONTENT_CLEANER_CLEANED_NOTHING").asKey().send(sender); + new MessageBuilder("IN_GAME_MESSAGES_ADMIN_NOTHING_T0_CLEAN").asKey().send(sender); return; } ArenaUtils.removeSpawnedEnemies(arena); @@ -86,7 +86,7 @@ public void execute(CommandSender sender, String[] args) { break; case "golem": if(arena.getIronGolems().isEmpty()) { - new MessageBuilder("KIT_CONTENT_CLEANER_CLEANED_NOTHING").asKey().send(sender); + new MessageBuilder("IN_GAME_MESSAGES_ADMIN_NOTHING_T0_CLEAN").asKey().send(sender); return; } for(IronGolem golem : arena.getIronGolems()) { @@ -99,7 +99,7 @@ public void execute(CommandSender sender, String[] args) { break; case "wolf": if(arena.getWolves().isEmpty()) { - new MessageBuilder("KIT_CONTENT_CLEANER_CLEANED_NOTHING").asKey().send(sender); + new MessageBuilder("IN_GAME_MESSAGES_ADMIN_NOTHING_T0_CLEAN").asKey().send(sender); return; } for(Wolf wolf : arena.getWolves()) { diff --git a/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ScriptEngineDebugArgument.java b/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ScriptEngineDebugArgument.java new file mode 100644 index 000000000..6fe41cb56 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/ScriptEngineDebugArgument.java @@ -0,0 +1,70 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.commands.arguments.admin; + +import plugily.projects.villagedefense.commands.arguments.ArgumentsRegistry; + +/** + * @author Plajer + *

+ * Created at 03.09.2023 + */ +public class ScriptEngineDebugArgument { + + public ScriptEngineDebugArgument(ArgumentsRegistry registry) { + /*registry.mapArgument("villagedefenseadmin", new LabeledCommandArgument("scripttest", Arrays.asList("villagedefense.admin.scripttest"), + CommandArgument.ExecutorType.PLAYER, new LabelData("/vda scripttest &c[text]", "/vda scripttest", + "&7Perform a rewards script engine test\n&6Permission: &7villagedefense.admin.scripttest")) { + @Override + public void execute(CommandSender sender, String[] args) { + Player player = (Player) sender; + if(!registry.getPlugin().getBukkitHelper().checkIsInGameInstance(player)) { + return; + } + Arena arena = (Arena) registry.getPlugin().getArenaRegistry().getArena(player); + StringBuilder combined = new StringBuilder(); + for(String argument : args) { + if(argument.equals("scripttest")) { + continue; + } + combined = combined.append(argument); + } + javax.script.ScriptEngine engine; + try { + engine = new NashornScriptEngineFactory().getScriptEngine(); + } catch(Exception ex) { + player.sendMessage("Engine failed to initialize"); + player.sendMessage(ex.getMessage()); + return; + } + engine.put("player", player); + engine.put("server", Bukkit.getServer()); + engine.put("arena", arena); + engine.put("plugin", registry.getPlugin()); + try { + engine.eval(combined.toString()); + } catch(ScriptException ex) { + player.sendMessage("Evaluation failed at " + ex.getColumnNumber() + ":" + ex.getLineNumber() + ", details:"); + player.sendMessage(ex.getMessage()); + } + } + });*/ + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/SetWaveUnlockArgument.java b/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/SetWaveUnlockArgument.java new file mode 100644 index 000000000..1feee65c0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/commands/arguments/admin/SetWaveUnlockArgument.java @@ -0,0 +1,88 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.commands.arguments.admin; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import plugily.projects.minigamesbox.classic.commands.arguments.data.CommandArgument; +import plugily.projects.minigamesbox.classic.commands.arguments.data.LabelData; +import plugily.projects.minigamesbox.classic.commands.arguments.data.LabeledCommandArgument; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.number.NumberUtils; +import plugily.projects.villagedefense.commands.arguments.ArgumentsRegistry; + +import java.util.List; + +/** + * @author Plajer + *

+ * Created at 24.11.2018 + */ +public class SetWaveUnlockArgument { + + public SetWaveUnlockArgument(ArgumentsRegistry registry) { + registry.mapArgument("villagedefenseadmin", new LabeledCommandArgument("setwaveunlock", "villagedefense.admin.setwaveunlock", CommandArgument.ExecutorType.PLAYER, + new LabelData("/vda setwaveunlock &6", "/vda setwaveunlock ", + "&7Set wave at which item is purchasable in the shop\n&6Permission: &7villagedefense.admin.setwaveunlock")) { + @Override + public void execute(CommandSender sender, String[] args) { + if(args.length == 1 || !NumberUtils.isInteger(args[1])) { + new MessageBuilder(ChatColor.RED + "Please type wave number!").prefix().send(sender); + return; + } + + Player player = (Player) sender; + ItemStack item = VersionUtils.getItemInHand(player); + if(item == null || item.getType() == Material.AIR) { + new MessageBuilder("COMMANDS_HOLD_ANY_ITEM").asKey().player(player).sendPlayer(); + return; + } + + ItemMeta meta = item.getItemMeta(); + if(meta == null || !meta.hasLore()) { + VersionUtils.setItemInHand(player, new ItemBuilder(item) + .lore(Integer.parseInt(args[1]) + " wave_lock").build()); + new MessageBuilder("COMMANDS_COMMAND_EXECUTED").asKey().player(player).sendPlayer(); + return; + } + + //check any price from lore + List lore = ComplementAccessor.getComplement().getLore(meta); + for(String search : lore) { + if (search.endsWith("wave_lock")) { + lore.remove(search); + break; + } + } + lore.add(0, Integer.parseInt(args[1]) + " wave_lock"); + ComplementAccessor.getComplement().setLore(meta, lore); + item.setItemMeta(meta); + new MessageBuilder("COMMANDS_COMMAND_EXECUTED").asKey().player(player).sendPlayer(); + } + }); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/BaseCreatureInitializer.java b/src/main/java/plugily/projects/villagedefense/creatures/BaseCreatureInitializer.java deleted file mode 100644 index 2b4cf55fd..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/BaseCreatureInitializer.java +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures; - -import org.bukkit.Location; -import org.bukkit.attribute.Attribute; -import org.bukkit.entity.Creature; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Wolf; -import plugily.projects.minigamesbox.classic.utils.misc.MiscUtils; - -public interface BaseCreatureInitializer { - Villager spawnVillager(Location location); - - Wolf spawnWolf(Location location); - - IronGolem spawnGolem(Location location); - - Creature spawnFastZombie(Location location); - - Creature spawnBabyZombie(Location location); - - Creature spawnHardZombie(Location location); - - Creature spawnPlayerBuster(Location location); - - Creature spawnGolemBuster(Location location); - - Creature spawnVillagerBuster(Location location); - - Creature spawnKnockbackResistantZombies(Location location); - - Creature spawnVillagerSlayer(Location location); - - default void applyFollowRange(Creature zombie) { - MiscUtils.getEntityAttribute(zombie, Attribute.GENERIC_FOLLOW_RANGE).ifPresent(ai -> ai.setBaseValue(200.0D)); - } - - default void applyDamageModifier(LivingEntity entity, double value) { - MiscUtils.getEntityAttribute(entity, Attribute.GENERIC_ATTACK_DAMAGE).ifPresent(ai -> ai.setBaseValue(value)); - } - - default void applySpeedModifier(LivingEntity entity, double value) { - MiscUtils.getEntityAttribute(entity, Attribute.GENERIC_MOVEMENT_SPEED).ifPresent(ai -> ai.setBaseValue(value)); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/CachedObject.java b/src/main/java/plugily/projects/villagedefense/creatures/CachedObject.java deleted file mode 100644 index 4b54cae71..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/CachedObject.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures; - -/** - * @author Plajer - *

- * Created at 06.01.2019 - */ -public class CachedObject { - - private final String fieldName; - private final Class clazz; - private final Object object; - - public CachedObject(String fieldName, Class clazz, Object object) { - this.fieldName = fieldName; - this.clazz = clazz; - this.object = object; - } - - public String getFieldName() { - return fieldName; - } - - public Class getClazz() { - return clazz; - } - - public Object getObject() { - return object; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/CreatureUtils.java b/src/main/java/plugily/projects/villagedefense/creatures/CreatureUtils.java deleted file mode 100644 index 5fbe41331..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/CreatureUtils.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures; - -import org.bukkit.ChatColor; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.Player; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Wolf; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.string.StringFormatUtils; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; - -import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.logging.Level; - -/** - * @author Plajer - *

- * Created at 2017 - */ -public class CreatureUtils { - - private static String[] villagerNames = ("Jagger,Kelsey,Kelton,Haylie,Harlow,Howard,Wulffric,Winfred,Ashley,Bailey,Beckett,Alfredo,Alfred,Adair,Edgar,ED,Eadwig,Edgaras,Buckley,Stanley,Nuffley," - + "Mary,Jeffry,Rosaly,Elliot,Harry,Sam,Rosaline,Tom,Ivan,Kevin,Adam,Emma,Mira,Jeff,Isac,Nico").split(","); - private static Main plugin; - private static BaseCreatureInitializer creatureInitializer; - private static final List cachedObjects = new ArrayList<>(); - - private CreatureUtils() { - } - - public static void init(Main plugin) { - CreatureUtils.plugin = plugin; - villagerNames = new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_VILLAGER_NAMES").asKey().build().split(","); - creatureInitializer = initCreatureInitializer(); - } - - public static BaseCreatureInitializer initCreatureInitializer() { - switch(ServerVersion.Version.getCurrent()) { - case v1_8_R3: - return new plugily.projects.villagedefense.creatures.v1_8_R3.CreatureInitializer(); - default: - return new plugily.projects.villagedefense.creatures.v1_9_UP.CreatureInitializer(); - } - } - - public static Object getPrivateField(String fieldName, Class clazz, Object object) { - for(CachedObject cachedObject : cachedObjects) { - if(cachedObject.getClazz().equals(clazz) && cachedObject.getFieldName().equals(fieldName)) { - return cachedObject.getObject(); - } - } - try { - Field field = clazz.getDeclaredField(fieldName); - - AccessController.doPrivileged((PrivilegedAction) () -> { - field.setAccessible(true); - return null; - }); - - Object o = field.get(object); - cachedObjects.add(new CachedObject(fieldName, clazz, o)); - return o; - } catch(NoSuchFieldException | IllegalAccessException e) { - plugin.getLogger().log(Level.WARNING, "Failed to retrieve private field of object " + object.getClass() + "!"); - plugin.getLogger().log(Level.WARNING, e.getMessage() + " (fieldName " + fieldName + ", class " + clazz.getName() + ")"); - } - return null; - } - - /** - * Check if the given entity is a arena's enemy. - * We define the enemy as it's not the player, the villager, the wolf and the iron golem - * - * @param entity the entity - * @return true if it is - */ - public static boolean isEnemy(Entity entity) { - return entity instanceof Creature && !(entity instanceof Player || entity instanceof Villager || entity instanceof Wolf || entity instanceof IronGolem); - } - - /** - * Applies attributes (i.e. health bar (if enabled), - * health multiplier and follow range) to target zombie. - * - * @param zombie zombie to apply attributes for - * @param arena arena to get health multiplier from - */ - public static void applyAttributes(Creature zombie, Arena arena) { - creatureInitializer.applyFollowRange(zombie); - VersionUtils.setMaxHealth(zombie, VersionUtils.getMaxHealth(zombie) + arena.getArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER")); - zombie.setHealth(VersionUtils.getMaxHealth(zombie)); - if(plugin.getConfigPreferences().getOption("ZOMBIE_HEALTHBAR")) { - zombie.setCustomNameVisible(true); - zombie.setCustomName(StringFormatUtils.getProgressBar((int) zombie.getHealth(), (int) VersionUtils.getMaxHealth(zombie), 50, "|", - ChatColor.YELLOW + "", ChatColor.GRAY + "")); - } - } - - public static float getZombieSpeed() { - return 1.3f; - } - - public static float getBabyZombieSpeed() { - return 2.0f; - } - - public static String[] getVillagerNames() { - return villagerNames.clone(); - } - - public static String getRandomVillagerName() { - return getVillagerNames()[villagerNames.length == 1 ? 0 : ThreadLocalRandom.current().nextInt(villagerNames.length)]; - } - - public static Main getPlugin() { - return plugin; - } - - public static BaseCreatureInitializer getCreatureInitializer() { - return creatureInitializer; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/DoorBreakListener.java b/src/main/java/plugily/projects/villagedefense/creatures/DoorBreakListener.java deleted file mode 100644 index ca240463f..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/DoorBreakListener.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures; - -import java.util.concurrent.ThreadLocalRandom; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.scheduler.BukkitRunnable; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.ArenaRegistry; -import plugily.projects.villagedefense.utils.Utils; - -/** - * Created by Tom on 14/08/2014. - */ -public class DoorBreakListener extends BukkitRunnable { - - private final Main plugin; - - public DoorBreakListener(Main plugin) { - this.plugin = plugin; - runTaskTimer(plugin, 1, 20); - } - - @Override - public void run() { - for(World world : plugin.getArenaRegistry().getArenaIngameWorlds()) { - for(LivingEntity entity : world.getLivingEntities()) { - if(entity.getType() != EntityType.ZOMBIE) { - continue; - } - - for(Block block : plugin.getBukkitHelper().getNearbyBlocks(entity, 1)) { - Material door = Utils.getCachedDoor(block); - - if(block.getType() != door) { - continue; - } - - org.bukkit.Location blockLoc = block.getLocation(); - - VersionUtils.sendParticles("SMOKE_LARGE", null, blockLoc, 5, 0.1,0.1,0.1); - VersionUtils.playSound(blockLoc, "ENTITY_ZOMBIE_ATTACK_WOODEN_DOOR"); - - if(ThreadLocalRandom.current().nextInt(20) == 5) { - VersionUtils.sendParticles("SMOKE_LARGE", null, blockLoc, 15, 0.1,0.1,0.1); - VersionUtils.sendParticles("EXPLOSION_HUGE", null, blockLoc, 1, 0.1,0.1,0.1); - - Block b = block.getRelative(BlockFace.UP); - - if(b.getType() == door) { - b.setType(Material.AIR); - } else if((b = block.getRelative(BlockFace.DOWN)).getType() == door) { - b.setType(Material.AIR); - } - - block.setType(Material.AIR); - VersionUtils.playSound(blockLoc, "ENTITY_ZOMBIE_BREAK_WOODEN_DOOR"); - } - } - } - } - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/BabyZombie.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/BabyZombie.java deleted file mode 100644 index ac1150950..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/BabyZombie.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 14/08/2014. - */ -public class BabyZombie extends EntityZombie { - - public BabyZombie(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public BabyZombie(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getBabyZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getBabyZombieSpeed())); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); // this one to look at human - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); // this one to target human - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)); - setBaby(true); - setHealth(2); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(100.0D); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/CreatureInitializer.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/CreatureInitializer.java deleted file mode 100644 index eb0aaaf34..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/CreatureInitializer.java +++ /dev/null @@ -1,231 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import net.minecraft.server.v1_8_R3.AttributeInstance; -import net.minecraft.server.v1_8_R3.AttributeModifier; -import net.minecraft.server.v1_8_R3.EntityInsentient; -import net.minecraft.server.v1_8_R3.EntityTypes; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftLivingEntity; -import org.bukkit.entity.Creature; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Wolf; -import org.bukkit.entity.Zombie; -import org.bukkit.event.entity.CreatureSpawnEvent; -import plugily.projects.minigamesbox.classic.utils.misc.MessageUtils; -import plugily.projects.villagedefense.creatures.BaseCreatureInitializer; - -public class CreatureInitializer implements BaseCreatureInitializer { - - private static final UUID uId = UUID.fromString("206a89dc-ae78-4c4d-b42c-3b31db3f5a7e"); - private static final UUID movementSpeedUuId = UUID.fromString("206a89dc-ae78-4c4d-b42c-3b31db3f5a7c"); - private static final UUID attackDamageUuId = UUID.fromString("206a89dc-ae78-4c4d-b42c-3b31db3f5a7d"); - - public CreatureInitializer() { - registerEntity("VillageZombie", 54, FastZombie.class); - registerEntity("VillageZombie", 54, BabyZombie.class); - registerEntity("VillageZombie", 54, PlayerBuster.class); - registerEntity("VillageZombie", 54, GolemBuster.class); - registerEntity("VillageZombie", 54, HardZombie.class); - registerEntity("VillageZombie", 54, TankerZombie.class); - registerEntity("VillageZombie", 54, VillagerSlayer.class); - registerEntity("VillageVillager", 120, RidableVillager.class); - registerEntity("VillageVillagerGolem", 99, RidableIronGolem.class); - registerEntity("VillageWolf", 95, WorkingWolf.class); - registerEntity("VillageZombie", 54, VillagerBuster.class); - } - - private void registerEntity(String name, int id, Class customClass) { - try { - List> dataMaps = new ArrayList<>(); - for (Field f : EntityTypes.class.getDeclaredFields()) { - if (f.getType().isAssignableFrom(Map.class)) { - f.setAccessible(true); - dataMaps.add((Map) f.get(null)); - } - } - ((Map, String>) dataMaps.get(1)).put(customClass, name); - ((Map, Integer>) dataMaps.get(3)).put(customClass, id); - } catch (Exception e) { - e.printStackTrace(); - Bukkit.getConsoleSender().sendMessage("[Village Defense] Entities has failed to register!"); - Bukkit.getConsoleSender().sendMessage("[Village Defense] Restart server or change your server version!"); - } - } - - private World getWorld(Location location) { - return ((CraftWorld) location.getWorld()).getHandle(); - } - - @Override - public Villager spawnVillager(Location location) { - RidableVillager ridableVillager = new RidableVillager(location.getWorld()); - ridableVillager.setPosition(location.getX(), location.getY(), location.getZ()); - getWorld(location).addEntity(ridableVillager, CreatureSpawnEvent.SpawnReason.CUSTOM); - Villager villager = (Villager) ridableVillager.getBukkitEntity(); - villager.setRemoveWhenFarAway(false); - return villager; - } - - @Override - public Wolf spawnWolf(Location location) { - WorkingWolf wolf = new WorkingWolf(location.getWorld()); - wolf.setPosition(location.getX(), location.getY(), location.getZ()); - getWorld(location).addEntity(wolf, CreatureSpawnEvent.SpawnReason.CUSTOM); - wolf.setInvisible(false); - return (Wolf) wolf.getBukkitEntity(); - } - - @Override - public IronGolem spawnGolem(Location location) { - RidableIronGolem ironGolem = new RidableIronGolem(location.getWorld()); - ironGolem.setPosition(location.getX(), location.getY(), location.getZ()); - getWorld(location).addEntity(ironGolem, CreatureSpawnEvent.SpawnReason.CUSTOM); - return (IronGolem) ironGolem.getBukkitEntity(); - } - - @Override - public Zombie spawnFastZombie(Location location) { - World world = getWorld(location); - FastZombie fastZombie = new FastZombie(world); - fastZombie.setPosition(location.getX(), location.getY(), location.getZ()); - world.addEntity(fastZombie, CreatureSpawnEvent.SpawnReason.CUSTOM); - Zombie zombie = (Zombie) fastZombie.getBukkitEntity(); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnBabyZombie(Location location) { - World world = getWorld(location); - BabyZombie babyZombie = new BabyZombie(world); - babyZombie.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) babyZombie.getBukkitEntity(); - world.addEntity(babyZombie, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnHardZombie(Location location) { - World world = getWorld(location); - HardZombie hardZombie = new HardZombie(world); - hardZombie.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) hardZombie.getBukkitEntity(); - world.addEntity(hardZombie, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnPlayerBuster(Location location) { - World world = getWorld(location); - PlayerBuster playerBuster = new PlayerBuster(world); - playerBuster.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) playerBuster.getBukkitEntity(); - world.addEntity(playerBuster, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnGolemBuster(Location location) { - World world = getWorld(location); - GolemBuster golemBuster = new GolemBuster(world); - golemBuster.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) golemBuster.getBukkitEntity(); - world.addEntity(golemBuster, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnVillagerBuster(Location location) { - World world = getWorld(location); - VillagerBuster villagerBuster = new VillagerBuster(world); - villagerBuster.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) villagerBuster.getBukkitEntity(); - world.addEntity(villagerBuster, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnKnockbackResistantZombies(Location location) { - World world = getWorld(location); - TankerZombie tankerZombie = new TankerZombie(world); - tankerZombie.getAttributeInstance(GenericAttributes.c).setValue(Double.MAX_VALUE); - tankerZombie.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) tankerZombie.getBukkitEntity(); - world.addEntity(tankerZombie, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public Zombie spawnVillagerSlayer(Location location) { - World world = getWorld(location); - VillagerSlayer villagerSlayer = new VillagerSlayer(world); - villagerSlayer.setPosition(location.getX(), location.getY(), location.getZ()); - Zombie zombie = (Zombie) villagerSlayer.getBukkitEntity(); - world.addEntity(villagerSlayer, CreatureSpawnEvent.SpawnReason.CUSTOM); - zombie.setRemoveWhenFarAway(false); - return zombie; - } - - @Override - public void applyFollowRange(Creature zombie) { - EntityInsentient nmsEntity = (EntityInsentient) ((CraftLivingEntity) zombie).getHandle(); - AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.FOLLOW_RANGE); - if (attributes.a(uId) == null) { // Check if the attribute is not set - attributes.b(new AttributeModifier(uId, "follow range multiplier", 200.0D, 1)); - } - } - - @Override - public void applyDamageModifier(LivingEntity entity, double value) { - EntityInsentient nmsEntity = (EntityInsentient) ((CraftLivingEntity) entity).getHandle(); - AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.ATTACK_DAMAGE); - if (attributes.a(attackDamageUuId) == null) { - attributes.b(new AttributeModifier(attackDamageUuId, "attack damage multiplier", value, 1)); - } - } - - @Override - public void applySpeedModifier(LivingEntity entity, double value) { - EntityInsentient nmsEntity = (EntityInsentient) ((CraftLivingEntity) entity).getHandle(); - AttributeInstance attributes = nmsEntity.getAttributeInstance(GenericAttributes.MOVEMENT_SPEED); - if (attributes.a(movementSpeedUuId) == null) { - attributes.b(new AttributeModifier(movementSpeedUuId, "movement speed multiplier", value, 1)); - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/FastZombie.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/FastZombie.java deleted file mode 100644 index d9a335e83..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/FastZombie.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 14/08/2014. - */ -public class FastZombie extends EntityZombie { - - public FastZombie(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public FastZombie(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getZombieSpeed())); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); // this one to look at human - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); // this one to target human - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(100.0D); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/GoalSelectorCleaner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/GoalSelectorCleaner.java deleted file mode 100644 index 3361f67a2..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/GoalSelectorCleaner.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityCreature; -import net.minecraft.server.v1_8_R3.PathfinderGoalSelector; -import org.bukkit.craftbukkit.v1_8_R3.util.UnsafeList; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Internal helper class - */ -class GoalSelectorCleaner { - - private GoalSelectorCleaner() { - } - - static void clearSelectors(EntityCreature creature) { - UnsafeList goalB = (UnsafeList) CreatureUtils.getPrivateField("b", PathfinderGoalSelector.class, creature.goalSelector); - goalB.clear(); - UnsafeList goalC = (UnsafeList) CreatureUtils.getPrivateField("c", PathfinderGoalSelector.class, creature.goalSelector); - goalC.clear(); - UnsafeList targetB = (UnsafeList) CreatureUtils.getPrivateField("b", PathfinderGoalSelector.class, creature.targetSelector); - targetB.clear(); - UnsafeList targetC = (UnsafeList) CreatureUtils.getPrivateField("c", PathfinderGoalSelector.class, creature.targetSelector); - targetC.clear(); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/GolemBuster.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/GolemBuster.java deleted file mode 100644 index 26ac46ecb..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/GolemBuster.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import java.util.ArrayList; -import java.util.Arrays; -import net.minecraft.server.v1_8_R3.DamageSource; -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityPlayer; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.Bukkit; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.LivingEntity; -import org.bukkit.event.entity.EntityDeathEvent; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 14/08/2014. - */ -public class GolemBuster extends EntityZombie { - - public GolemBuster(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public GolemBuster(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getZombieSpeed())); - goalSelector.a(5, new PathfinderGoalBreakDoorFaster(this)); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityIronGolem.class, 8.0F)); // this one to look at IronGolem - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - //this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityPlayer.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, true)); // this one to target - setHealth(5); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(200.0D); - } - - @Override - public boolean damageEntity(DamageSource damagesource, float f) { - if(damagesource != null && damagesource.getEntity() != null && damagesource.getEntity().getBukkitEntity().getType() == EntityType.IRON_GOLEM) { - this.die(); - org.bukkit.inventory.ItemStack[] itemStack = new org.bukkit.inventory.ItemStack[]{new org.bukkit.inventory.ItemStack(org.bukkit.Material.ROTTEN_FLESH)}; - Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent((LivingEntity) getBukkitEntity(), new ArrayList<>(Arrays.asList(itemStack)), expToDrop)); - IronGolem golem = (IronGolem) damagesource.getEntity().getBukkitEntity(); - golem.getWorld().spawnEntity(golem.getLocation(), EntityType.PRIMED_TNT); - return true; - } - super.damageEntity(damagesource, f); - return false; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/HardZombie.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/HardZombie.java deleted file mode 100644 index aa3dc76d9..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/HardZombie.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 14/08/2014. - */ -public class HardZombie extends EntityZombie { - - public HardZombie(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public HardZombie(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getZombieSpeed())); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); // this one to look at human - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); // this one to target human - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)); - setHealth(35); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(100.0D); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/PathfinderGoalBreakDoorFaster.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/PathfinderGoalBreakDoorFaster.java deleted file mode 100644 index 91dae3d81..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/PathfinderGoalBreakDoorFaster.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.Block; -import net.minecraft.server.v1_8_R3.EntityInsentient; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; - - -public class PathfinderGoalBreakDoorFaster extends PathfinderGoalBreakDoor { - - private int i = 0; - private int j = -1; - - public PathfinderGoalBreakDoorFaster(EntityInsentient entityinsentient) { - super(entityinsentient); - } - - @Override - public void e() { - super.e(); - a.world.triggerEffect(1010, b, 0); - - ++i; - int i = (int) (this.i / 240.0F * 10.0F); - - if(i != j) { - a.world.c(a.getId(), b, i); - j = i; - } - - if(this.i == 70) { - a.world.setAir(b); - a.world.triggerEffect(1012, b, 0); - a.world.triggerEffect(2001, b, Block.getId(c)); - } - } - -} - diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/PlayerBuster.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/PlayerBuster.java deleted file mode 100644 index 600736fb0..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/PlayerBuster.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import java.util.ArrayList; -import java.util.Arrays; -import net.minecraft.server.v1_8_R3.DamageSource; -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityPlayer; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 15/08/2014. - */ -public class PlayerBuster extends EntityZombie { - - public PlayerBuster(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public PlayerBuster(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getZombieSpeed())); - goalSelector.a(5, new PathfinderGoalBreakDoorFaster(this)); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityPlayer.class, 8.0F)); // this one to look at human - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityPlayer.class, true));// this one to target - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)); - setHealth(1); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(200.0D); - } - - @Override - public boolean damageEntity(DamageSource damagesource, float f) { - if(damagesource != null && damagesource.getEntity() != null && damagesource.getEntity().getBukkitEntity().getType() == EntityType.PLAYER) { - if(CreatureUtils.getPlugin().getUserManager().getUser((Player) damagesource.getEntity().getBukkitEntity()).isSpectator()) { - return true; - } - ItemStack[] itemStack = new ItemStack[]{new ItemStack(Material.ROTTEN_FLESH)}; - Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent((LivingEntity) getBukkitEntity(), new ArrayList<>(Arrays.asList(itemStack)), expToDrop)); - getBukkitEntity().getWorld().spawnEntity(getBukkitEntity().getLocation(), EntityType.PRIMED_TNT); - this.die(); - return true; - } - super.damageEntity(damagesource, f); - return false; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/RidableIronGolem.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/RidableIronGolem.java deleted file mode 100644 index 959cb54b1..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/RidableIronGolem.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.IMonster; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalDefendVillage; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveThroughVillage; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomStroll; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; - -/** - * Created by Tom on 17/08/2014. - */ -public class RidableIronGolem extends EntityIronGolem { - - public RidableIronGolem(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public RidableIronGolem(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - - this.a(1.4F, 2.9F); - ((Navigation) getNavigation()).b(true); - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalMeleeAttack(this, 1.0D, true)); - goalSelector.a(2, new PathfinderGoalMoveTowardsTarget(this, 0.9D, 32.0F)); - goalSelector.a(3, new PathfinderGoalMoveThroughVillage(this, 0.6D, true)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, 1.0D)); - goalSelector.a(5, new PathfinderGoalRandomStroll(this, 0.6D)); - goalSelector.a(6, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(1, new PathfinderGoalDefendVillage(this)); - targetSelector.a(2, new PathfinderGoalHurtByTarget(this, false)); - targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, 0, false, true, IMonster.e)); - setHealth(500); - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(150D); - } - - @Override - protected void dropDeathLoot(boolean flag, int i) { - //do not drop death loot - } - - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/RidableVillager.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/RidableVillager.java deleted file mode 100644 index 914e22a42..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/RidableVillager.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityAgeable; -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityInsentient; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalAvoidTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalInteract; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtTradingPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMakeLove; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveIndoors; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalOpenDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalPlay; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomStroll; -import net.minecraft.server.v1_8_R3.PathfinderGoalRestrictOpenDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalTradeWithPlayer; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; - -/** - * Created by Tom on 15/08/2014. - */ -public class RidableVillager extends EntityVillager { - - public RidableVillager(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public RidableVillager(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - - setSize(0.6F, 1.8F); - ((Navigation) getNavigation()).b(true); - ((Navigation) getNavigation()).a(true); - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalAvoidTarget<>(this, EntityZombie.class, 8.0F, 0.6D, 0.6D)); - goalSelector.a(1, new PathfinderGoalTradeWithPlayer(this)); - goalSelector.a(1, new PathfinderGoalLookAtTradingPlayer(this)); - goalSelector.a(2, new PathfinderGoalMoveIndoors(this)); - goalSelector.a(3, new PathfinderGoalRestrictOpenDoor(this)); - goalSelector.a(4, new PathfinderGoalOpenDoor(this, true)); - goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 0.6D)); - goalSelector.a(6, new PathfinderGoalMakeLove(this)); - goalSelector.a(8, new PathfinderGoalPlay(this, 0.32D)); - goalSelector.a(9, new PathfinderGoalInteract(this, EntityHuman.class, 3.0F, 1.0F)); - goalSelector.a(9, new PathfinderGoalInteract(this, EntityVillager.class, 5.0F, 0.02F)); - goalSelector.a(9, new PathfinderGoalRandomStroll(this, 0.6D)); - goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F)); - } - - @Override - public EntityAgeable createChild(EntityAgeable entityAgeable) { - return this.b(entityAgeable); - } - - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/TankerZombie.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/TankerZombie.java deleted file mode 100644 index b122e9399..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/TankerZombie.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 17/12/2015. - */ -public class TankerZombie extends EntityZombie { - - public TankerZombie(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public TankerZombie(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getZombieSpeed())); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F)); // this one to look at human - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(1, new PathfinderGoalHurtByTarget(this, false)); - targetSelector.a(4, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)); // this one to target human - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, false)); - targetSelector.a(3, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)); - setHealth(35); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(100.0D); - getAttributeInstance(GenericAttributes.c).setValue(0D); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/VillagerBuster.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/VillagerBuster.java deleted file mode 100644 index c39370357..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/VillagerBuster.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import java.util.ArrayList; -import java.util.Collections; -import net.minecraft.server.v1_8_R3.Entity; -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityIronGolem; -import net.minecraft.server.v1_8_R3.EntityPlayer; -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -/** - * Created by Tom on 15/08/2014. - */ -public class VillagerBuster extends EntityZombie { - - public VillagerBuster(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public VillagerBuster(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, CreatureUtils.getZombieSpeed(), false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, CreatureUtils.getZombieSpeed())); - goalSelector.a(5, new PathfinderGoalBreakDoorFaster(this)); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityVillager.class, 8.0F)); // this one to look at human - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - //this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityPlayer.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, false)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, true));// this one to target - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)); - - - setHealth(10); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(200.0D); - } - - @Override - public boolean r(Entity entity) { - if(entity.getBukkitEntity().getType() == EntityType.VILLAGER) { - this.die(); - Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent((LivingEntity) getBukkitEntity(), new ArrayList<>(Collections.singletonList(new ItemStack(Material.ROTTEN_FLESH))), 6)); - org.bukkit.entity.Entity bukkitEntity = entity.getBukkitEntity(); - bukkitEntity.getWorld().spawnEntity(bukkitEntity.getLocation(), EntityType.PRIMED_TNT); - return false; - } - return super.r(entity); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/VillagerSlayer.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/VillagerSlayer.java deleted file mode 100644 index a5a2f71dc..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/VillagerSlayer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityVillager; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalBreakDoor; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; - -/** - * @author Plajer - *

- * Created at 02.05.2018 - */ -public class VillagerSlayer extends EntityZombie { - - public VillagerSlayer(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public VillagerSlayer(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - ((Navigation) getNavigation()).b(true); - - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(1, new PathfinderGoalBreakDoor(this)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0f, false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, 1.0f)); - goalSelector.a(7, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityVillager.class, true)); - setHealth(70); - - } - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(100.0D); - getAttributeInstance(GenericAttributes.c).setValue(0D); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/WorkingWolf.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/WorkingWolf.java deleted file mode 100644 index 08addc79f..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/WorkingWolf.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3; - -import net.minecraft.server.v1_8_R3.EntityHuman; -import net.minecraft.server.v1_8_R3.EntityWolf; -import net.minecraft.server.v1_8_R3.EntityZombie; -import net.minecraft.server.v1_8_R3.GenericAttributes; -import net.minecraft.server.v1_8_R3.Navigation; -import net.minecraft.server.v1_8_R3.PathfinderGoalFloat; -import net.minecraft.server.v1_8_R3.PathfinderGoalFollowOwner; -import net.minecraft.server.v1_8_R3.PathfinderGoalHurtByTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLeapAtTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalLookAtPlayer; -import net.minecraft.server.v1_8_R3.PathfinderGoalMeleeAttack; -import net.minecraft.server.v1_8_R3.PathfinderGoalMoveTowardsRestriction; -import net.minecraft.server.v1_8_R3.PathfinderGoalNearestAttackableTarget; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomLookaround; -import net.minecraft.server.v1_8_R3.PathfinderGoalRandomStroll; -import net.minecraft.server.v1_8_R3.World; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; - -/** - * Created by Tom on 17/08/2014. - */ -public class WorkingWolf extends EntityWolf { - - public WorkingWolf(org.bukkit.World world) { - this(((CraftWorld) world).getHandle()); - } - - public WorkingWolf(World world) { - super(world); - - GoalSelectorCleaner.clearSelectors(this); - - this.a(1.4F, 2.9F); - ((Navigation) getNavigation()).a(true); - goalSelector.a(0, new PathfinderGoalFloat(this)); - goalSelector.a(3, new PathfinderGoalLeapAtTarget(this, 0.4F)); - goalSelector.a(4, new PathfinderGoalMeleeAttack(this, 1.0D, true)); - goalSelector.a(5, new PathfinderGoalFollowOwner(this, 1.0D, 10.0F, 2.0F)); - goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.5F, false)); - goalSelector.a(4, new PathfinderGoalMoveTowardsRestriction(this, 1.0D)); - goalSelector.a(6, new PathfinderGoalRandomStroll(this, 0.6D)); - goalSelector.a(7, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 6.0F)); - goalSelector.a(8, new PathfinderGoalRandomLookaround(this)); - targetSelector.a(2, new PathfinderGoalNearestAttackableTarget<>(this, EntityZombie.class, true)); - targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true)); - - } - - - @Override - protected void initAttributes() { - super.initAttributes(); - getAttributeInstance(GenericAttributes.FOLLOW_RANGE).setValue(70.0D); - } - - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/BabyZombieSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/BabyZombieSpawner.java deleted file mode 100644 index 110762af5..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/BabyZombieSpawner.java +++ /dev/null @@ -1,64 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class BabyZombieSpawner implements SimpleEnemySpawner { - @Override - public boolean canApplyHolidayEffect() { - return true; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 ? 1D / 3 : 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 ? spawnAmount / 4 : 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5; - } - - @Override - public Creature spawn(Location location) { - return CreatureUtils.getCreatureInitializer().spawnBabyZombie(location); - } - - @Override - public String getName() { - return "BabyZombie"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/FastZombieSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/FastZombieSpawner.java deleted file mode 100644 index 53cec4535..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/FastZombieSpawner.java +++ /dev/null @@ -1,77 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class FastZombieSpawner implements SimpleEnemySpawner { - @Override - public boolean canApplyHolidayEffect() { - return true; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - if(spawnAmount < 5 || arena.getEnemies().isEmpty()) { - return 1; - } - - if(phase == 5 && wave <= 7) { - return 2d / 3; - } - - return 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - return (spawnAmount < 5 || (phase == 5 && wave <= 7) || arena.getEnemies().isEmpty()) ? spawnAmount : 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return arena.getEnemies().isEmpty() || spawnAmount < 5 || (phase == 5 && wave <= 7); - } - - @Override - public Creature spawn(Location location) { - return CreatureUtils.getCreatureInitializer().spawnFastZombie(location); - } - - @Override - public String getName() { - return "FastZombie"; - } - - @Override - public int getPriority() { - return -1; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/GolemBusterSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/GolemBusterSpawner.java deleted file mode 100644 index a941a804d..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/GolemBusterSpawner.java +++ /dev/null @@ -1,81 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class GolemBusterSpawner implements SimpleEnemySpawner { - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5) { - return 1D / 3; - } - if(wave >= 6) { - return 1D / 8; - } - return 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5) { - return spawnAmount / 4; - } - if(wave >= 6) { - return spawnAmount - 4; - } - return 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 || (wave >= 6 && !arena.getIronGolems().isEmpty()); - } - - @Override - public Creature spawn(Location location) { - Creature golemBuster = CreatureUtils.getCreatureInitializer().spawnGolemBuster(location); - golemBuster.getEquipment().setHelmet(new ItemStack(Material.TNT)); - golemBuster.getEquipment().setHelmetDropChance(0.0F); - VersionUtils.setItemInHandDropChance(golemBuster, 0F); - golemBuster.getEquipment().setBoots(XMaterial.IRON_BOOTS.parseItem()); - golemBuster.getEquipment().setLeggings(XMaterial.IRON_LEGGINGS.parseItem()); - golemBuster.getEquipment().setChestplate(XMaterial.IRON_CHESTPLATE.parseItem()); - return golemBuster; - } - - @Override - public String getName() { - return "GolemBuster"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/HalfInvisibleZombieSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/HalfInvisibleZombieSpawner.java deleted file mode 100644 index da08bf84c..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/HalfInvisibleZombieSpawner.java +++ /dev/null @@ -1,79 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class HalfInvisibleZombieSpawner implements SimpleEnemySpawner { - @Override - public int getMinWave() { - return 7; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - return 1D / 8; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - int total = 0; - if(wave > 23) { - total++; - } - if(wave > 15) { - total += spawnAmount - 13; - } else if(wave > 7) { - total += spawnAmount - 5; - } - return total; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return true; - } - - @Override - public Creature spawn(Location location) { - Creature fastZombie = CreatureUtils.getCreatureInitializer().spawnFastZombie(location); - fastZombie.getEquipment().setBoots(new ItemStack(Material.CHAINMAIL_BOOTS)); - fastZombie.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1)); - return fastZombie; - } - - @Override - public String getName() { - return "HalfInvisibleZombie"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/HardZombieSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/HardZombieSpawner.java deleted file mode 100644 index 5209bce0b..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/HardZombieSpawner.java +++ /dev/null @@ -1,82 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class HardZombieSpawner implements SimpleEnemySpawner { - @Override - public int getMinWave() { - return 4; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5 && wave > 14 && wave <= 20) { - return 1D / 3; - } - if(phase == 15 && wave > 8) { - return 1; - } - return 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5 && wave > 14 && wave <= 20) { - return spawnAmount; - } - if(phase == 15 && wave > 8) { - return spawnAmount - 7; - } - return 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 || phase == 15; - } - - @Override - public Creature spawn(Location location) { - Creature hardZombie = CreatureUtils.getCreatureInitializer().spawnHardZombie(location); - hardZombie.getEquipment().setBoots(new ItemStack(Material.DIAMOND_BOOTS)); - hardZombie.getEquipment().setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS)); - hardZombie.getEquipment().setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE)); - hardZombie.getEquipment().setHelmet(new ItemStack(Material.DIAMOND_HELMET)); - return hardZombie; - } - - @Override - public String getName() { - return "HardZombie"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/KnockbackResistantZombieSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/KnockbackResistantZombieSpawner.java deleted file mode 100644 index 5b8a121f5..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/KnockbackResistantZombieSpawner.java +++ /dev/null @@ -1,73 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class KnockbackResistantZombieSpawner implements SimpleEnemySpawner { - @Override - public int getMinWave() { - return 20; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - return 2D / 9; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - return spawnAmount; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5; - } - - @Override - public Creature spawn(Location location) { - Creature tankerZombie = CreatureUtils.getCreatureInitializer().spawnKnockbackResistantZombies(location); - VersionUtils.setItemInHand(tankerZombie, XMaterial.GOLDEN_AXE.parseItem()); - tankerZombie.getEquipment().setBoots(new ItemStack(Material.DIAMOND_BOOTS)); - tankerZombie.getEquipment().setLeggings(new ItemStack(Material.DIAMOND_LEGGINGS)); - tankerZombie.getEquipment().setChestplate(new ItemStack(Material.DIAMOND_CHESTPLATE)); - tankerZombie.getEquipment().setHelmet(new ItemStack(Material.DIAMOND_HELMET)); - return tankerZombie; - } - - @Override - public String getName() { - return "KnockbackResistantZombie"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/PlayerBusterSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/PlayerBusterSpawner.java deleted file mode 100644 index 2537626b2..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/PlayerBusterSpawner.java +++ /dev/null @@ -1,81 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class PlayerBusterSpawner implements SimpleEnemySpawner { - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5) { - return 1D / 3; - } - if(wave > 10) { - return 1D / 8; - } - return 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5) { - return spawnAmount / 4; - } - if(wave > 10) { - return spawnAmount - 8; - } - return 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 || wave > 10; - } - - @Override - public Creature spawn(Location location) { - Creature playerBuster = CreatureUtils.getCreatureInitializer().spawnPlayerBuster(location); - playerBuster.getEquipment().setHelmet(new ItemStack(Material.TNT)); - playerBuster.getEquipment().setHelmetDropChance(0.0F); - VersionUtils.setItemInHandDropChance(playerBuster, 0F); - playerBuster.getEquipment().setBoots(XMaterial.GOLDEN_BOOTS.parseItem()); - playerBuster.getEquipment().setLeggings(XMaterial.GOLDEN_LEGGINGS.parseItem()); - playerBuster.getEquipment().setChestplate(XMaterial.GOLDEN_CHESTPLATE.parseItem()); - return playerBuster; - } - - @Override - public String getName() { - return "PlayerBuster"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/SoftHardZombieSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/SoftHardZombieSpawner.java deleted file mode 100644 index 24c9529c2..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/SoftHardZombieSpawner.java +++ /dev/null @@ -1,82 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class SoftHardZombieSpawner implements SimpleEnemySpawner { - @Override - public int getMinWave() { - return 4; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5 && wave > 7 && wave <= 14) { - return 1D / 3; - } - if(phase == 15 && wave > 4 && wave <= 8) { - return 1; - } - return 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5 && wave > 7 && wave <= 14) { - return spawnAmount; - } - if(phase == 15 && wave > 4 && wave <= 8) { - return spawnAmount - 3; - } - return 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 || phase == 15; - } - - @Override - public Creature spawn(Location location) { - Creature hardBuster = CreatureUtils.getCreatureInitializer().spawnHardZombie(location); - hardBuster.getEquipment().setBoots(new ItemStack(Material.IRON_BOOTS)); - hardBuster.getEquipment().setLeggings(new ItemStack(Material.IRON_LEGGINGS)); - hardBuster.getEquipment().setChestplate(new ItemStack(Material.IRON_CHESTPLATE)); - hardBuster.getEquipment().setHelmet(new ItemStack(Material.IRON_HELMET)); - return hardBuster; - } - - @Override - public String getName() { - return "SoftHardZombie"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/VillagerBusterSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/VillagerBusterSpawner.java deleted file mode 100644 index bd0c71b4d..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/VillagerBusterSpawner.java +++ /dev/null @@ -1,81 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class VillagerBusterSpawner implements SimpleEnemySpawner { - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5) { - return 1D / 3; - } - if(wave >= 15) { - return 1D / 8; - } - return 0; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - if(phase == 5) { - return spawnAmount / 4; - } - if(wave >= 15) { - return spawnAmount - 13; - } - return 0; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5 || (wave >= 15 && !arena.getVillagers().isEmpty()); - } - - @Override - public Creature spawn(Location location) { - Creature villagerBuster = CreatureUtils.getCreatureInitializer().spawnVillagerBuster(location); - villagerBuster.getEquipment().setHelmet(new ItemStack(Material.TNT)); - villagerBuster.getEquipment().setHelmetDropChance(0.0F); - VersionUtils.setItemInHandDropChance(villagerBuster, 0F); - villagerBuster.getEquipment().setBoots(XMaterial.LEATHER_BOOTS.parseItem()); - villagerBuster.getEquipment().setLeggings(XMaterial.LEATHER_LEGGINGS.parseItem()); - villagerBuster.getEquipment().setChestplate(XMaterial.LEATHER_CHESTPLATE.parseItem()); - return villagerBuster; - } - - @Override - public String getName() { - return "VillagerBuster"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/VillagerSlayerSpawner.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/VillagerSlayerSpawner.java deleted file mode 100644 index a73c3353c..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_8_R3/spawner/VillagerSlayerSpawner.java +++ /dev/null @@ -1,74 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_8_R3.spawner; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class VillagerSlayerSpawner implements SimpleEnemySpawner { - @Override - public int getMinWave() { - return 23; - } - - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - return 1D / 6; - } - - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - return spawnAmount; - } - - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - return phase == 5; - } - - @Override - public Creature spawn(Location location) { - Creature villagerSlayer = CreatureUtils.getCreatureInitializer().spawnVillagerSlayer(location); - VersionUtils.setItemInHand(villagerSlayer, XMaterial.EMERALD.parseItem()); - VersionUtils.setItemInHandDropChance(villagerSlayer, 0F); - villagerSlayer.getEquipment().setBoots(new ItemStack(Material.CHAINMAIL_BOOTS)); - villagerSlayer.getEquipment().setLeggings(new ItemStack(Material.CHAINMAIL_LEGGINGS)); - villagerSlayer.getEquipment().setChestplate(new ItemStack(Material.CHAINMAIL_CHESTPLATE)); - villagerSlayer.getEquipment().setHelmet(new ItemStack(Material.CHAINMAIL_HELMET)); - return villagerSlayer; - } - - @Override - public String getName() { - return "VillagerSlayer"; - } - - @Override - public ItemStack getDropItem() { - return null; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CreatureInitializer.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CreatureInitializer.java deleted file mode 100644 index 380f09b01..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CreatureInitializer.java +++ /dev/null @@ -1,99 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_9_UP; - -import org.bukkit.Location; -import org.bukkit.entity.Creature; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Wolf; -import org.bukkit.entity.Zombie; -import plugily.projects.villagedefense.creatures.BaseCreatureInitializer; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -public class CreatureInitializer implements BaseCreatureInitializer { - - @Override - public Villager spawnVillager(Location location) { - Creature creature = CreatureUtils.getPlugin().getEnemySpawnerRegistry().getRideableCreatureByName(CustomRideableCreature.RideableType.VILLAGER).get().spawn(location); - if(creature instanceof Villager) { - return (Villager) creature; - } - throw new ClassCastException("Villager creature isn't a villager"); - } - - @Override - public Wolf spawnWolf(Location location) { - Creature creature = CreatureUtils.getPlugin().getEnemySpawnerRegistry().getRideableCreatureByName(CustomRideableCreature.RideableType.WOLF).get().spawn(location); - if(creature instanceof Wolf) { - return (Wolf) creature; - } - throw new ClassCastException("Wolf creature isn't a wolf"); - } - - @Override - public IronGolem spawnGolem(Location location) { - Creature creature = CreatureUtils.getPlugin().getEnemySpawnerRegistry().getRideableCreatureByName(CustomRideableCreature.RideableType.IRON_GOLEM).get().spawn(location); - if(creature instanceof IronGolem) { - return (IronGolem) creature; - } - throw new ClassCastException("IronGolem creature isn't a iron golem"); - } - - @Override - public Zombie spawnFastZombie(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnBabyZombie(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnHardZombie(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnPlayerBuster(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnGolemBuster(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnVillagerBuster(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnKnockbackResistantZombies(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } - - @Override - public Zombie spawnVillagerSlayer(Location location) { - throw new UnsupportedOperationException("Method isn't used on 1.9 and up"); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomCreature.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomCreature.java deleted file mode 100644 index 2e73b7bac..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomCreature.java +++ /dev/null @@ -1,331 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_9_UP; - -import org.bukkit.Location; -import org.bukkit.attribute.Attribute; -import org.bukkit.entity.Ageable; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.FixedMetadataValue; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.SimpleEnemySpawner; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * @author Tigerpanzer_02 - *

- * Created at 15.01.2022 - */ -public class CustomCreature implements SimpleEnemySpawner { - - private final Main plugin; - private final int waveMin; - private final int waveMax; - private final PriorityTarget priorityTarget; - private final boolean explodeTarget; - private final String key; - private final EntityType entityType; - private final boolean baby; - private final boolean breed; - private final int age; - private final boolean ageLook; - private final int expDrop; - private final boolean holidayEffects; - private final List rates; - private final List spawn = new ArrayList<>(); - private final List amount = new ArrayList<>(); - private final List check = new ArrayList<>(); - private final Map attributes; - private final List equipments; - private final ItemStack dropItem; - - - public CustomCreature(Main plugin, int waveMin, int waveMax, PriorityTarget priorityTarget, boolean explodeTarget, String key, EntityType entityType, boolean baby, boolean breed, int age, boolean ageLook, int expDrop, boolean holidayEffects, List rates, Map attributes, List equipments, ItemStack dropItem) { - this.priorityTarget = priorityTarget; - this.explodeTarget = explodeTarget; - if(ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_8_R3)) { - throw new IllegalStateException("Couldn't create Creature " + key + " as its only for Version 1.9+"); - } - this.plugin = plugin; - this.waveMin = waveMin; - this.waveMax = waveMax; - this.key = key; - this.entityType = entityType; - this.baby = baby; - this.breed = breed; - this.age = age; - this.ageLook = ageLook; - this.expDrop = expDrop; - this.holidayEffects = holidayEffects; - this.rates = rates; - - for(Rate rate : rates) { - switch(rate.getRateType()) { - case AMOUNT: - amount.add(rate); - break; - case SPAWN: - spawn.add(rate); - break; - case CHECK: - check.add(rate); - break; - } - } - - this.attributes = attributes; - this.equipments = equipments; - this.dropItem = dropItem; - } - - @Override - public int getMaxWave() { - return getWaveMax(); - } - - @Override - public int getMinWave() { - return getWaveMin(); - } - - public int getWaveMax() { - return waveMax; - } - - public PriorityTarget getPriorityTarget() { - return priorityTarget; - } - - public boolean isExplodeTarget() { - return explodeTarget; - } - - public int getWaveMin() { - return waveMin; - } - - public String getKey() { - return key; - } - - public EntityType getEntityType() { - return entityType; - } - - public boolean isBaby() { - return baby; - } - - public boolean isBreed() { - return breed; - } - - public int getAge() { - return age; - } - - public boolean isAgeLook() { - return ageLook; - } - - public int getExpDrop() { - return expDrop; - } - - public boolean isHolidayEffects() { - return holidayEffects; - } - - public List getRates() { - return rates; - } - - public Map getAttributes() { - return attributes; - } - - public List getEquipments() { - return equipments; - } - - public ItemStack getDropItem() { - return dropItem; - } - - @Override - public boolean canApplyHolidayEffect() { - return isHolidayEffects(); - } - - /** - * How often the enemies will be spawned? Amount between 0.0 and 1.0 - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return the spawn rate in double - */ - @Override - public double getSpawnRate(Arena arena, int wave, int phase, int spawnAmount) { - for(Rate rate : spawn) { - if(!rate.isPhase(phase)) { - continue; - } - if(!rate.isSpawnLower(spawnAmount)) { - continue; - } - if(rate.isWaveHigher(wave) && rate.isWaveLower(wave)) { - return (rate.getRate() / rate.getDivision()) - rate.getReduce(); - } - } - return 0; - } - - /** - * Get the final amount of enemies to spawn, after some workaround - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return the final amount - */ - @Override - public int getFinalAmount(Arena arena, int wave, int phase, int spawnAmount) { - for(Rate rate : amount) { - if(!rate.isPhase(phase)) { - continue; - } - if(!rate.isSpawnLower(spawnAmount)) { - continue; - } - if(rate.isWaveHigher(wave) && rate.isWaveLower(wave)) { - return (int) ((spawnAmount / (rate.getRate() / rate.getDivision())) - rate.getReduce()); - } - } - return 0; - } - - /** - * Check if the enemies can be spawned on this phase - * - * @param arena the arena - * @param wave the current wave - * @param phase the current phase - * @param spawnAmount the raw amount that the arena suggests - * @return true if they can - */ - @Override - public boolean checkPhase(Arena arena, int wave, int phase, int spawnAmount) { - for(Rate rate : check) { - if(!rate.isPhase(phase)) { - continue; - } - if(!rate.isSpawnLower(spawnAmount)) { - continue; - } - if(rate.isWaveHigher(wave) && rate.isWaveLower(wave)) { - return true; - } - } - return false; - } - - public Creature spawn(Location location) { - Entity entity = VersionUtils.spawnEntity(location, entityType); - if(entity instanceof Ageable) { - Ageable ageable = (Ageable) entity; - ageable.setBreed(isBreed()); - if(isBaby()) { - ageable.setBaby(); - } else { - ageable.setAdult(); - } - if(getAge() > 0) ageable.setAge(getAge()); - ageable.setAgeLock(isAgeLook()); - } - if(entity instanceof Creature) { - Creature creature = (Creature) entity; - for(Equipment equipment : equipments) { - switch(equipment.getEquipmentType()) { - case HELMET: - creature.getEquipment().setHelmet(equipment.getItemStack()); - creature.getEquipment().setHelmetDropChance(equipment.getDropChance()); - break; - case CHESTPLATE: - creature.getEquipment().setChestplate(equipment.getItemStack()); - creature.getEquipment().setChestplateDropChance(equipment.getDropChance()); - break; - case LEGGINGS: - creature.getEquipment().setLeggings(equipment.getItemStack()); - creature.getEquipment().setLeggingsDropChance(equipment.getDropChance()); - break; - case BOOTS: - creature.getEquipment().setBoots(equipment.getItemStack()); - creature.getEquipment().setBootsDropChance(equipment.getDropChance()); - break; - case HAND: - VersionUtils.setItemInHand(creature, equipment.getItemStack()); - creature.getEquipment().setItemInMainHandDropChance(equipment.getDropChance()); - break; - } - } - creature.getAttribute(Attribute.GENERIC_FOLLOW_RANGE).setBaseValue(200D); - for(Map.Entry attribute : attributes.entrySet()) { - creature.getAttribute(attribute.getKey()).setBaseValue(attribute.getValue()); - if(attribute.getKey() == Attribute.GENERIC_MAX_HEALTH) { - VersionUtils.setMaxHealth(creature, attribute.getValue()); - creature.setHealth(attribute.getValue()); - } - } - creature.setRemoveWhenFarAway(false); - creature.setMetadata("PlugilyProjects-VillageDefense-Name", new FixedMetadataValue(plugin, key)); - return creature; - } else { - entity.remove(); - throw new IllegalStateException("Couldn't spawn Creature " + key + " as its not instance of creature"); - } - } - - /** - * Get the name of the spawner - * - * @return the name - */ - @Override - public String getName() { - return key; - } - - - public enum PriorityTarget { - ANY, PLAYER, VILLAGER, IRON_GOLEM, WOLF - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomCreatureEvents.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomCreatureEvents.java deleted file mode 100644 index 897583d18..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomCreatureEvents.java +++ /dev/null @@ -1,143 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_9_UP; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Wolf; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.MetadataValue; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.managers.spawner.EnemySpawner; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -/** - * @author Tigerpanzer_02 - *

- * Created at 15.01.2022 - */ -public class CustomCreatureEvents implements Listener { - - private final Main plugin; - - public CustomCreatureEvents(Main plugin) { - this.plugin = plugin; - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - - @EventHandler - public void onCreatureDeathEvent(EntityDeathEvent event) { - LivingEntity entity = event.getEntity(); - if(!(entity instanceof Creature)) { - return; - } - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(entity instanceof IronGolem || entity instanceof Wolf || entity instanceof Villager) { - if(arena.getIronGolems().contains(entity) || arena.getWolves().contains(entity) || arena.getVillagers().contains(entity)) { - Optional customRideableCreatureOptional = plugin.getEnemySpawnerRegistry().getRideableCreatureByName(CustomRideableCreature.RideableType.valueOf(entity.getType().name().toUpperCase())); - if(!customRideableCreatureOptional.isPresent()) { - continue; - } - ItemStack itemStack = customRideableCreatureOptional.get().getDropItem(); - event.getDrops().add(itemStack); - } - } else if(arena.getEnemies().contains(entity)) { - CustomCreature customCreature = arena.getCreatureTargetManager().getCustomCreatureFromCreature((Creature) entity); - if(customCreature == null) { - continue; - } - ItemStack itemStack = customCreature.getDropItem(); - event.getDrops().add(itemStack); - event.setDroppedExp(customCreature.getExpDrop()); - } - } - } - - - @EventHandler - public void onExplosiveHit(EntityDamageByEntityEvent event) { - if(!(event.getDamager() instanceof Creature)) { - return; - } - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(!arena.isFighting()) { - continue; - } - CustomCreature customCreature = getCustomCreatureFromCreature(arena, (Creature) event.getDamager()); - if(customCreature == null) { - return; - } - if(!customCreature.isExplodeTarget()) { - return; - } - CustomCreature.PriorityTarget priorityTarget = customCreature.getPriorityTarget(); - List entityTypes = new ArrayList<>(); - if(priorityTarget == CustomCreature.PriorityTarget.ANY) { - for(CustomCreature.PriorityTarget priorityTargets : CustomCreature.PriorityTarget.values()) { - if(priorityTargets == CustomCreature.PriorityTarget.ANY) { - continue; - } - entityTypes.add(EntityType.valueOf(priorityTargets.toString())); - } - } else { - entityTypes.add(EntityType.valueOf(priorityTarget.toString())); - } - if(entityTypes.contains(event.getEntity().getType())) { - event.getDamager().getLocation().getWorld().spawnEntity(event.getDamager().getLocation(), EntityType.PRIMED_TNT); - event.getDamager().remove(); - Bukkit.getServer().getPluginManager().callEvent(new EntityDeathEvent((LivingEntity) event.getDamager(), new ArrayList<>(Collections.singletonList(new ItemStack(Material.ROTTEN_FLESH))), 6)); - } - } - } - - public CustomCreature getCustomCreatureFromCreature(Arena arena, Creature creature) { - List metadataValueList = creature.getMetadata("PlugilyProjects-VillageDefense-Name"); - if(metadataValueList.isEmpty()) { - plugin.getDebugger().debug("Arena {0} Couldn't find creature meta data", arena.getId()); - return null; - } - for(MetadataValue metadataValue : metadataValueList) { - if(plugin.getEnemySpawnerRegistry().getSpawnerByName(metadataValue.asString()).isPresent()) { - EnemySpawner enemySpawner = plugin.getEnemySpawnerRegistry().getSpawnerByName(metadataValue.asString()).get(); - if(enemySpawner instanceof CustomCreature) { - return (CustomCreature) enemySpawner; - } - } - } - plugin.getDebugger().debug("Arena {0} Couldn't find creature spawner", arena.getId()); - return null; - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomRideableCreature.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomRideableCreature.java deleted file mode 100644 index c7d0737fc..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/CustomRideableCreature.java +++ /dev/null @@ -1,106 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_9_UP; - -import org.bukkit.Location; -import org.bukkit.attribute.Attribute; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; - -import java.util.Map; - -/** - * @author Tigerpanzer_02 - *

- * Created at 16.01.2022 - */ -public class CustomRideableCreature { - - private final RideableType rideableType; - private final boolean holidayEffects; - private final Map attributes; - private final ItemStack dropItem; - - public CustomRideableCreature(RideableType rideableType, boolean holidayEffects, Map attributes, ItemStack dropItem) { - this.rideableType = rideableType; - this.holidayEffects = holidayEffects; - this.attributes = attributes; - this.dropItem = dropItem; - } - - public Creature spawn(Location location) { - EntityType entityType = EntityType.VILLAGER; - switch(rideableType) { - case VILLAGER: - entityType = EntityType.VILLAGER; - break; - case WOLF: - entityType = EntityType.WOLF; - break; - case IRON_GOLEM: - entityType = EntityType.IRON_GOLEM; - break; - } - Entity entity = VersionUtils.spawnEntity(location, entityType); - if(entity instanceof Creature) { - Creature creature = (Creature) entity; - creature.getAttribute(Attribute.GENERIC_FOLLOW_RANGE).setBaseValue(200D); - for(Map.Entry attribute : attributes.entrySet()) { - creature.getAttribute(attribute.getKey()).setBaseValue(attribute.getValue()); - if(attribute.getKey() == Attribute.GENERIC_MAX_HEALTH) { - VersionUtils.setMaxHealth(creature, attribute.getValue()); - creature.setHealth(attribute.getValue()); - } - } - creature.setRemoveWhenFarAway(false); - if(ServerVersion.Version.isCurrentEqualOrHigher(ServerVersion.Version.v1_16_R3)) { - creature.setInvisible(false); - } - return creature; - } else { - entity.remove(); - throw new IllegalStateException("Couldn't spawn Creature " + entityType + " as its not instance of creature"); - } - } - - public RideableType getRideableType() { - return rideableType; - } - - public boolean isHolidayEffects() { - return holidayEffects; - } - - public Map getAttributes() { - return attributes; - } - - public ItemStack getDropItem() { - return dropItem; - } - - public enum RideableType { - VILLAGER, IRON_GOLEM, WOLF - } -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/Equipment.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/Equipment.java deleted file mode 100644 index b17dc27c7..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/Equipment.java +++ /dev/null @@ -1,57 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_9_UP; - -import org.bukkit.inventory.ItemStack; - -/** - * @author Tigerpanzer_02 - *

- * Created at 15.01.2022 - */ -public class Equipment { - - private final ItemStack itemStack; - private final int dropChance; - private final EquipmentType equipmentType; - - public Equipment(ItemStack itemStack, int dropChance, EquipmentType equipmentType) { - this.itemStack = itemStack; - this.dropChance = dropChance; - this.equipmentType = equipmentType; - } - - public ItemStack getItemStack() { - return itemStack; - } - - public int getDropChance() { - return dropChance; - } - - public EquipmentType getEquipmentType() { - return equipmentType; - } - - public enum EquipmentType { - HELMET, CHESTPLATE, LEGGINGS, BOOTS, HAND - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/Rate.java b/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/Rate.java deleted file mode 100644 index 81531251a..000000000 --- a/src/main/java/plugily/projects/villagedefense/creatures/v1_9_UP/Rate.java +++ /dev/null @@ -1,118 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.creatures.v1_9_UP; - -/** - * @author Tigerpanzer_02 - *

- * Created at 15.01.2022 - */ -public class Rate { - - private final int phase; - private final int waveHigher; - private final int waveLower; - private final int spawnLower; - private final int rate; - private final int division; - private final int reduce; - private final RateType rateType; - - public Rate(int phase, int waveHigher, int waveLower, int spawnLower, int rate, int division, int reduce, RateType rateType) { - this.phase = phase; - this.waveHigher = waveHigher; - this.waveLower = waveLower; - this.spawnLower = spawnLower; - this.rate = rate; - this.division = division; - this.reduce = reduce; - this.rateType = rateType; - } - - public boolean isPhase(int number) { - if(phase == number) { - return true; - } - return phase == 0; - } - - public int getPhase() { - return phase; - } - - public boolean isWaveHigher(int wave) { - if(waveHigher == 0) { - return true; - } - return wave >= waveHigher; - } - - public boolean isWaveLower(int wave) { - if(waveLower == 0) { - return true; - } - return wave <= waveLower; - } - - public boolean isSpawnLower(int number) { - if(spawnLower == 0) { - return true; - } - return number <= spawnLower; - } - - public int getSpawnLower() { - return spawnLower; - } - - public int getWaveHigher() { - return waveHigher; - } - - public int getWaveLower() { - return waveLower; - } - - public double getRate() { - if(rate == 0) { - return 1; - } - return rate; - } - - public int getDivision() { - if(division == 0) { - return 1; - } - return division; - } - - public int getReduce() { - return reduce; - } - - public RateType getRateType() { - return rateType; - } - - public enum RateType { - SPAWN, AMOUNT, CHECK - } -} diff --git a/src/main/java/plugily/projects/villagedefense/events/ChatEvents.java b/src/main/java/plugily/projects/villagedefense/events/ChatEvents.java new file mode 100644 index 000000000..c47372534 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/events/ChatEvents.java @@ -0,0 +1,97 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.events; + +import io.papermc.paper.chat.ChatRenderer; +import io.papermc.paper.event.player.AsyncChatEvent; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextReplacementConfig; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.kits.ChatDisplayable; + +//Village Defense Gold - backported into the main plugin +public class ChatEvents implements Listener, ChatRenderer { + + private final Main plugin; + + public ChatEvents(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + + @EventHandler + public void onChatIngame(AsyncChatEvent event) { + event.renderer(this); + } + + @Override + public @NotNull Component render(@NotNull Player source, @NotNull Component sourceDisplayName, @NotNull Component message, @NotNull Audience viewer) { + Arena arena = plugin.getArenaRegistry().getArena(source); + if (!(viewer instanceof Player viewerPlayer)) { + return ChatRenderer.defaultRenderer().render(source, sourceDisplayName, message, viewer); + } + Arena viewerArena = plugin.getArenaRegistry().getArena(viewerPlayer); + //if target is in arena - ignore messages outside their arena unless spychat is enabled + if (viewerArena != null) { + if (viewerArena.equals(arena) || plugin.getArgumentsRegistry().getSpyChat().isSpyChatEnabled(viewerPlayer)) { + return formatChatPlaceholders(source, arena, sourceDisplayName, message); + } + return Component.empty(); + } + //return non formatted message outside arena + return ChatRenderer.defaultRenderer().render(source, sourceDisplayName, message, viewer); + } + + private Component formatChatPlaceholders(Player player, Arena arena, Component displayName, Component message) { + Component formatted = Component.text(new MessageBuilder("IN_GAME_GAME_CHAT_FORMAT").asKey().arena(arena).build()); + User user = plugin.getUserManager().getUser(player); + if (user.getKit() != null) { + formatted = formatted.replaceText( + TextReplacementConfig + .builder() + .match("%kit%") + .replacement(Component.text(((ChatDisplayable) user.getKit()).getChatPrefix()).font(Key.key("villagedefense"))) + .build() + ); + } else { + formatted = formatted.replaceText( + TextReplacementConfig + .builder() + .match("%kit%") + .replacement(Component.text("-")) + .build() + ); + } + formatted = formatted + .replaceText(TextReplacementConfig.builder().match("%player%").replacement(displayName).build()) + .replaceText(TextReplacementConfig.builder().match("%user_statistic_level%").replacement(Component.text(user.getStatistic(plugin.getStatsStorage().getStatisticType("LEVEL")))).build()) + .replaceText(TextReplacementConfig.builder().match("%message%").replacement(message).build()); + return formatted; + } +} diff --git a/src/main/java/plugily/projects/villagedefense/events/EntityUpgradeListener.java b/src/main/java/plugily/projects/villagedefense/events/EntityUpgradeListener.java index 8ababd92f..d1b287e28 100644 --- a/src/main/java/plugily/projects/villagedefense/events/EntityUpgradeListener.java +++ b/src/main/java/plugily/projects/villagedefense/events/EntityUpgradeListener.java @@ -1,43 +1,36 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.events; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; +import org.bukkit.Sound; +import org.bukkit.entity.Ageable; import org.bukkit.entity.EntityType; -import org.bukkit.entity.IronGolem; import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Wolf; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEntityEvent; import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.creatures.CreatureUtils; -import plugily.projects.villagedefense.handlers.upgrade.EntityUpgradeMenu; +import plugily.projects.villagedefense.handlers.upgrade.NewEntityUpgradeManager; -import java.util.ArrayList; +import java.util.UUID; /** * @author Plajer @@ -46,93 +39,40 @@ */ public class EntityUpgradeListener implements Listener { - private final EntityUpgradeMenu upgradeMenu; private final Main plugin; - - public EntityUpgradeListener(EntityUpgradeMenu upgradeMenu) { - this.upgradeMenu = upgradeMenu; - this.plugin = upgradeMenu.getPlugin(); - upgradeMenu.getPlugin().getServer().getPluginManager().registerEvents(this, upgradeMenu.getPlugin()); + public EntityUpgradeListener(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); } @EventHandler - public void onDamage(EntityDamageByEntityEvent event) { - if(!(event.getDamager() instanceof LivingEntity) || !(event.getDamager() instanceof IronGolem)) { + public void onEntityClick(PlugilyPlayerInteractEntityEvent event) { + if((event.getRightClicked().getType() != EntityType.IRON_GOLEM && event.getRightClicked().getType() != EntityType.WOLF) + || VersionUtils.checkOffHand(event.getHand()) + || !event.getPlayer().isSneaking() + || !event.getRightClicked().hasMetadata("VD_OWNER_UUID") + || plugin.getArenaRegistry().getArena(event.getPlayer()) == null) { return; } - switch(event.getDamager().getType()) { - case IRON_GOLEM: - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(!arena.getIronGolems().contains(event.getDamager())) { - continue; - } - event.setDamage(event.getDamage() + upgradeMenu.getTier(event.getDamager(), upgradeMenu.getUpgrade("Damage")) * 2); - } - break; - case WOLF: - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(!arena.getWolves().contains(event.getDamager())) { - continue; - } - int tier = upgradeMenu.getTier(event.getDamager(), upgradeMenu.getUpgrade("Swarm-Awareness")); - if(tier == 0) { - return; - } - double multiplier = 1; - for(Entity entity : plugin.getBukkitHelper().getNearbyEntities(event.getDamager().getLocation(), 3)) { - if(entity instanceof Wolf) { - multiplier += tier * 0.2; - } - } - event.setDamage(event.getDamage() * multiplier); - } - break; - default: - break; - } - } - - @EventHandler - public void onFinalDefense(EntityDeathEvent event) { - if(event.getEntityType() != EntityType.IRON_GOLEM) { + if(plugin.getUserManager().getUser(event.getPlayer()).isSpectator()) { return; } - - LivingEntity livingEntity = event.getEntity(); - - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(!arena.getIronGolems().contains(livingEntity)) { - continue; - } - int tier = upgradeMenu.getTier(livingEntity, upgradeMenu.getUpgrade("Final-Defense")); - if(tier == 0) { - return; - } - VersionUtils.sendParticles("EXPLOSION_HUGE", arena.getPlayers(), livingEntity.getLocation(), 5); - for(Entity en : plugin.getBukkitHelper().getNearbyEntities(livingEntity.getLocation(), tier * 5)) { - if(CreatureUtils.isEnemy(en)) { - ((Creature) en).damage(10000.0, livingEntity); - } - } - for(Creature zombie : new ArrayList<>(arena.getEnemies())) { - zombie.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 5, 0)); - zombie.damage(0.5, livingEntity); - } + UUID uuid = UUID.fromString(event.getRightClicked().getMetadata("VD_OWNER_UUID").get(0).asString()); + if(!event.getPlayer().getUniqueId().equals(uuid)) { + return; } - } - - @EventHandler - public void onEntityClick(PlugilyPlayerInteractEntityEvent event) { - if((event.getRightClicked().getType() != EntityType.IRON_GOLEM && event.getRightClicked().getType() != EntityType.WOLF) - || VersionUtils.checkOffHand(event.getHand()) || !event.getPlayer().isSneaking() - || event.getRightClicked().getCustomName() == null) { + if (event.getRightClicked().hasMetadata(NewEntityUpgradeManager.UPGRADES_DISABLED_METADATA)) { + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_UPGRADE_THIS").asKey().player(event.getPlayer()).sendPlayer(); + event.getPlayer().playSound(event.getPlayer(), Sound.ENTITY_VILLAGER_NO, 1, 1); return; } - - if(plugin.getArenaRegistry().getArena(event.getPlayer()) != null && !upgradeMenu.getPlugin().getUserManager().getUser(event.getPlayer()).isSpectator()) { - upgradeMenu.openUpgradeMenu((LivingEntity) event.getRightClicked(), event.getPlayer()); + if (event.getRightClicked() instanceof Ageable ageable && !ageable.isAdult()) { + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_UPGRADE_BABY").asKey().player(event.getPlayer()).sendPlayer(); + event.getPlayer().playSound(event.getPlayer(), Sound.ENTITY_VILLAGER_NO, 1, 1); + return; } + plugin.getEntityUpgradeManager().openUpgradeMenu((LivingEntity) event.getRightClicked(), event.getPlayer()); } } diff --git a/src/main/java/plugily/projects/villagedefense/events/PluginEvents.java b/src/main/java/plugily/projects/villagedefense/events/PluginEvents.java index f3e9b1cc4..cc466486b 100644 --- a/src/main/java/plugily/projects/villagedefense/events/PluginEvents.java +++ b/src/main/java/plugily/projects/villagedefense/events/PluginEvents.java @@ -1,33 +1,34 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.events; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.entity.Creature; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.IronGolem; import org.bukkit.entity.Item; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Villager; @@ -49,19 +50,32 @@ import org.bukkit.event.inventory.InventoryPickupItemEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerExpChangeEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; import org.bukkit.inventory.ItemStack; +import plugily.projects.minigamesbox.classic.api.event.player.PlugilyPlayerChooseKitEvent; import plugily.projects.minigamesbox.classic.arena.ArenaState; import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.kits.basekits.Kit; import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEntityEvent; -import plugily.projects.minigamesbox.string.StringFormatUtils; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; import plugily.projects.villagedefense.Main; import plugily.projects.villagedefense.api.event.game.VillageGameSecretWellEvent; import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.BuilderKit; +import plugily.projects.villagedefense.kits.CleanerKit; +import plugily.projects.villagedefense.kits.CrusaderKit; +import plugily.projects.villagedefense.kits.MedicKit; +import plugily.projects.villagedefense.kits.ShotBowKit; +import plugily.projects.villagedefense.kits.TornadoKit; +import plugily.projects.villagedefense.kits.WizardKit; +import plugily.projects.villagedefense.kits.petsfriend.PetsFriendKit; +import plugily.projects.villagedefense.kits.terminator.TerminatorKit; import plugily.projects.villagedefense.utils.Utils; +import java.util.UUID; + /** * Created by Tom on 16/08/2014. */ @@ -74,89 +88,97 @@ public PluginEvents(Main plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } - @EventHandler - public void onItemPickup(PlayerExpChangeEvent event) { - Player player = event.getPlayer(); - Arena arena = plugin.getArenaRegistry().getArena(player); - if(arena == null) { - return; - } - - User user = plugin.getUserManager().getUser(player); - if(user.isSpectator()) { - event.setAmount(0); + public void onConsumeClearBottle(PlayerItemConsumeEvent event) { + if (!plugin.getArenaRegistry().isInArena(event.getPlayer())) { return; } + //Quality of Life - remove empty glass bottles on potion consume + event.getPlayer().getInventory().remove(Material.GLASS_BOTTLE); + } - int amount = (int) Math.ceil(event.getAmount() * 1.6 * arena.getArenaOption("ZOMBIE_DIFFICULTY_MULTIPLIER")); - - event.setAmount(amount); - - int orbsBoost = plugin.getPermissionsManager().getPermissionCategoryValue("ORBS_BOOSTER", player); - - amount += (amount * (orbsBoost / 100)); - - amount += event.getAmount(); - user.adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), event.getAmount()); - - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ORBS_PICKUP").asKey().integer(amount).player(player).sendPlayer(); + @EventHandler + public void onKitSelectSound(PlugilyPlayerChooseKitEvent event) { + XSound.UI_BUTTON_CLICK.play(event.getPlayer()); + playKitSound(event.getKit(), event.getPlayer()); } + private void playKitSound(Kit kit, Player player) { + //knight kit omitted + if (kit instanceof BuilderKit) { + player.playSound(player, Sound.BLOCK_WOODEN_DOOR_OPEN, 1, 0.75f); + } else if (kit instanceof CleanerKit) { + player.playSound(player, Sound.BLOCK_LAVA_EXTINGUISH, 1, 1.5f); + } else if (kit instanceof CrusaderKit) { + player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_0, 1, 1); + } else if (kit instanceof MedicKit) { + player.playSound(player, Sound.ENTITY_VILLAGER_CELEBRATE, 1, 1.25f); + } else if (kit instanceof PetsFriendKit) { + player.playSound(player, Sound.ENTITY_WOLF_WHINE, 1, 1.15f); + } else if (kit instanceof ShotBowKit) { + player.playSound(player, Sound.ENTITY_ARROW_HIT, 1, 0.75f); + } else if (kit instanceof TerminatorKit) { + player.playSound(player, Sound.ENTITY_WITHER_DEATH, 1, 2.0f); + } else if (kit instanceof TornadoKit) { + player.playSound(player, Sound.ENTITY_ENDERMAN_TELEPORT, 1, 0.25f); + } else if (kit instanceof WizardKit) { + player.playSound(player, Sound.AMBIENT_CAVE, 1, 2.0f); + } + } @EventHandler public void onEntityInteractEntity(PlugilyPlayerInteractEntityEvent event) { - if(VersionUtils.checkOffHand(event.getHand())) { + if (VersionUtils.checkOffHand(event.getHand())) { return; } Arena arena = plugin.getArenaRegistry().getArena(event.getPlayer()); - if(arena == null) { + if (arena == null) { return; } - if(plugin.getUserManager().getUser(event.getPlayer()).isSpectator()) { + if (plugin.getUserManager().getUser(event.getPlayer()).isSpectator()) { event.setCancelled(true); return; } - if(VersionUtils.getItemInHand(event.getPlayer()).getType() == Material.SADDLE) { - if(event.getRightClicked().getType() == EntityType.IRON_GOLEM || event.getRightClicked().getType() == EntityType.VILLAGER || event.getRightClicked().getType() == EntityType.WOLF) { + if (VersionUtils.getItemInHand(event.getPlayer()).getType() == Material.SADDLE) { + if (!event.getRightClicked().getPassengers().isEmpty()) { + event.getPlayer().playSound(event.getPlayer(), Sound.ENTITY_VILLAGER_NO, 1, 1); + event.setCancelled(true); + return; + } + if (event.getRightClicked().getType() == EntityType.IRON_GOLEM || event.getRightClicked().getType() == EntityType.VILLAGER || event.getRightClicked().getType() == EntityType.WOLF) { VersionUtils.setPassenger(event.getRightClicked(), event.getPlayer()); event.setCancelled(true); return; } } - if(event.getRightClicked().getType() == EntityType.VILLAGER) { + Entity target = event.getRightClicked(); + if (target.getType() == EntityType.VILLAGER) { event.setCancelled(true); - arena.getShopManager().openShop(event.getPlayer()); - } else if(event.getRightClicked().getType() == EntityType.IRON_GOLEM) { - if(event.getPlayer().isSneaking()) { - return; - } - IronGolem ironGolem = (IronGolem) event.getRightClicked(); - if(ironGolem.getCustomName() != null && ironGolem.getCustomName().contains(event.getPlayer().getName())) { - VersionUtils.setPassenger(event.getRightClicked(), event.getPlayer()); - } else { - new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_GOLEM_CANT_RIDE_OTHER").asKey().player(event.getPlayer()).sendPlayer(); + arena.getShopManager().openShop(event.getPlayer(), (Villager) target); + } else if (target.getType() == EntityType.IRON_GOLEM || target.getType() == EntityType.WOLF) { + if (target.getType() == EntityType.WOLF) { + Wolf wolf = (Wolf) event.getRightClicked(); + Bukkit.getScheduler().runTask(plugin, () -> wolf.setSitting(false)); } - } else if(event.getRightClicked().getType() == EntityType.WOLF) { - Wolf wolf = (Wolf) event.getRightClicked(); - Bukkit.getScheduler().runTask(plugin, () -> wolf.setSitting(false)); - if(event.getPlayer().isSneaking()) { + if (event.getPlayer().isSneaking()) { return; } - //to prevent wolves sitting - if(wolf.getCustomName() != null && wolf.getCustomName().contains(event.getPlayer().getName())) { + if (!target.hasMetadata("VD_OWNER_UUID") + || event.getPlayer().getUniqueId().equals(UUID.fromString(target.getMetadata("VD_OWNER_UUID").get(0).asString()))) { VersionUtils.setPassenger(event.getRightClicked(), event.getPlayer()); + return; } + new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_WAVE_ENTITIES_CANT_RIDE_OTHER").asKey().player(event.getPlayer()).sendPlayer(); } } @EventHandler public void onDoorDrop(ItemSpawnEvent event) { - if(event.getEntity().getItemStack().getType() == Utils.getCachedDoor(event.getLocation().getBlock())) { - for(Entity entity : plugin.getBukkitHelper().getNearbyEntities(event.getLocation(), 20)) { - if(entity instanceof Player && plugin.getArenaRegistry().getArena((Player) entity) != null) { + if (event.getEntity().getItemStack().getType() == Utils.getCachedDoor(event.getLocation().getBlock())) { + for (Entity entity : plugin.getBukkitHelper().getNearbyEntities(event.getLocation(), 20)) { + if (entity instanceof Player && plugin.getArenaRegistry().getArena((Player) entity) != null) { event.getEntity().remove(); } } @@ -165,7 +187,7 @@ public void onDoorDrop(ItemSpawnEvent event) { @EventHandler public void onDrop(PlayerDropItemEvent event) { - if(plugin.getArenaRegistry().isInArena(event.getPlayer()) && event.getItemDrop().getItemStack().getType() == Material.SADDLE) { + if (plugin.getArenaRegistry().isInArena(event.getPlayer()) && event.getItemDrop().getItemStack().getType() == Material.SADDLE) { event.setCancelled(true); } } @@ -173,10 +195,10 @@ public void onDrop(PlayerDropItemEvent event) { @EventHandler public void onItemMove(InventoryClickEvent event) { - if(event.getWhoClicked() instanceof Player && plugin.getArenaRegistry().isInArena((Player) event.getWhoClicked())) { - if(plugin.getArenaRegistry().getArena(((Player) event.getWhoClicked())).getArenaState() != ArenaState.IN_GAME) { - if(event.getClickedInventory() == event.getWhoClicked().getInventory()) { - if(event.getView().getType() == InventoryType.CRAFTING || event.getView().getType() == InventoryType.PLAYER) { + if (event.getWhoClicked() instanceof Player && plugin.getArenaRegistry().isInArena((Player) event.getWhoClicked())) { + if (plugin.getArenaRegistry().getArena(((Player) event.getWhoClicked())).getArenaState() != ArenaState.IN_GAME) { + if (event.getClickedInventory() == event.getWhoClicked().getInventory()) { + if (event.getView().getType() == InventoryType.CRAFTING || event.getView().getType() == InventoryType.PLAYER) { event.setResult(Event.Result.DENY); } } @@ -187,21 +209,21 @@ public void onItemMove(InventoryClickEvent event) { @EventHandler public void onEntityCombust(EntityCombustByEntityEvent event) { - if(!(event.getCombuster() instanceof Projectile)) { + if (!(event.getCombuster() instanceof Projectile)) { return; } Projectile projectile = (Projectile) event.getCombuster(); - if(!(projectile.getShooter() instanceof Player)) { + if (!(projectile.getShooter() instanceof Player)) { return; } - if(event.getEntity() instanceof Player) { + if (event.getEntity() instanceof Player) { Arena arena = plugin.getArenaRegistry().getArena((Player) projectile.getShooter()); - if(arena != null && arena.equals(plugin.getArenaRegistry().getArena((Player) event.getEntity()))) { + if (arena != null && arena.equals(plugin.getArenaRegistry().getArena((Player) event.getEntity()))) { event.setCancelled(true); } - } else if(event.getEntity() instanceof IronGolem || event.getEntity() instanceof Villager || event.getEntity() instanceof Wolf) { - for(Arena a : plugin.getArenaRegistry().getPluginArenas()) { - if(a.getWolves().contains(event.getEntity()) || a.getVillagers().contains(event.getEntity()) || a.getIronGolems().contains(event.getEntity())) { + } else if (event.getEntity() instanceof IronGolem || event.getEntity() instanceof Villager || event.getEntity() instanceof Wolf) { + for (Arena a : plugin.getArenaRegistry().getPluginArenas()) { + if (a.getWolves().contains(event.getEntity()) || a.getVillagers().contains(event.getEntity()) || a.getIronGolems().contains(event.getEntity())) { event.setCancelled(true); return; } @@ -211,45 +233,61 @@ public void onEntityCombust(EntityCombustByEntityEvent event) { @EventHandler(priority = EventPriority.HIGHEST) public void onFriendHurt(EntityDamageByEntityEvent event) { - if(!(event.getDamager() instanceof Player) || plugin.getArenaRegistry().getArena((Player) event.getDamager()) == null) { + if (!(event.getDamager() instanceof Player) || plugin.getArenaRegistry().getArena((Player) event.getDamager()) == null) { return; } - if(plugin.getUserManager().getUser((Player) event.getDamager()).isSpectator()) { + if (plugin.getUserManager().getUser((Player) event.getDamager()).isSpectator()) { event.setCancelled(true); return; } - if(!(event.getEntity() instanceof Player || event.getEntity() instanceof Wolf || event.getEntity() instanceof IronGolem || event.getEntity() instanceof Villager)) { + if (!(event.getEntity() instanceof Player || event.getEntity() instanceof Wolf || event.getEntity() instanceof IronGolem || event.getEntity() instanceof Villager)) { return; } event.setCancelled(true); } - @EventHandler(priority = EventPriority.HIGH) + @EventHandler(priority = EventPriority.HIGHEST) public void onCreatureHurt(EntityDamageEvent event) { - if(!(event.getEntity() instanceof Creature) || !plugin.getConfigPreferences().getOption("ZOMBIE_HEALTHBAR")) { + if (!(event.getEntity() instanceof Creature creature)) { + return; + } + if (event.isCancelled()) { return; } - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(!arena.getEnemies().contains(event.getEntity())) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getEnemies().contains(creature) + && !arena.getWolves().contains(creature)) { continue; } - Creature creature = (Creature) event.getEntity(); - creature.setCustomName(StringFormatUtils.getProgressBar((int) creature.getHealth(), (int) VersionUtils.getMaxHealth(creature), - 50, "|", ChatColor.YELLOW + "", ChatColor.GRAY + "")); + event.setCancelled(false); + creature.setCustomName(NewCreatureUtils.getHealthNameTagPreDamage(creature, event.getFinalDamage())); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onAssistApply(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Creature) || !(event.getDamager() instanceof LivingEntity)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getEnemies().contains(event.getEntity())) { + continue; + } + arena.getAssistHandler().doRegisterDamageOnEnemy((LivingEntity) event.getDamager(), (Creature) event.getEntity(), event.getFinalDamage()); } } @EventHandler(priority = EventPriority.HIGHEST) public void onSecond(EntityDamageByEntityEvent event) { - if(!(event.getDamager() instanceof Projectile)) { + if (!(event.getDamager() instanceof Projectile)) { return; } Projectile projectile = (Projectile) event.getDamager(); - if(!(projectile.getShooter() instanceof Player)) { + if (!(projectile.getShooter() instanceof Player)) { return; } - if(plugin.getArenaRegistry().getArena((Player) projectile.getShooter()) == null || !(event.getEntity() instanceof Player || event.getEntity() instanceof Wolf - || event.getEntity() instanceof IronGolem || event.getEntity() instanceof Villager)) { + if (plugin.getArenaRegistry().getArena((Player) projectile.getShooter()) == null || !(event.getEntity() instanceof Player || event.getEntity() instanceof Wolf + || event.getEntity() instanceof IronGolem || event.getEntity() instanceof Villager)) { return; } event.setCancelled(true); @@ -257,22 +295,21 @@ public void onSecond(EntityDamageByEntityEvent event) { @EventHandler public void onEntityLeash(PlayerLeashEntityEvent event) { - if(event.getEntity() instanceof Villager) { + if (event.getEntity() instanceof Villager) { ((Villager) event.getEntity()).setLeashHolder(event.getPlayer()); } } - @EventHandler(priority = EventPriority.HIGH) public void onBlockBreakEvent(BlockBreakEvent event) { - if(plugin.getArenaRegistry().isInArena(event.getPlayer())) { + if (plugin.getArenaRegistry().isInArena(event.getPlayer())) { event.setCancelled(true); } } @EventHandler(priority = EventPriority.HIGH) public void onBuild(BlockPlaceEvent event) { - if(plugin.getArenaRegistry().isInArena(event.getPlayer()) && event.getBlock().getType() != Utils.getCachedDoor(event.getBlock())) { + if (plugin.getArenaRegistry().isInArena(event.getPlayer()) && event.getBlock().getType() != Utils.getCachedDoor(event.getBlock())) { event.setCancelled(true); } } @@ -280,7 +317,7 @@ public void onBuild(BlockPlaceEvent event) { @EventHandler public void onSecretWellDrop(InventoryPickupItemEvent event) { - if(event.getInventory().getType() != InventoryType.HOPPER) { + if (event.getInventory().getType() != InventoryType.HOPPER) { return; } @@ -288,8 +325,8 @@ public void onSecretWellDrop(InventoryPickupItemEvent event) { Location location = item.getLocation(); Arena currentArena = null; - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(location.getWorld() == arena.getStartLocation().getWorld()) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (location.getWorld() == arena.getStartLocation().getWorld()) { currentArena = arena; item.remove(); event.setCancelled(true); @@ -298,7 +335,7 @@ public void onSecretWellDrop(InventoryPickupItemEvent event) { } } - if(currentArena == null) { + if (currentArena == null) { return; } @@ -306,25 +343,26 @@ public void onSecretWellDrop(InventoryPickupItemEvent event) { VillageGameSecretWellEvent villageGameSecretWellEvent = new VillageGameSecretWellEvent(currentArena, itemStack, location); Bukkit.getPluginManager().callEvent(villageGameSecretWellEvent); - if(villageGameSecretWellEvent.isCancelled()) { + if (villageGameSecretWellEvent.isCancelled()) { return; } - if(itemStack.getType() == Material.ROTTEN_FLESH) { - for(Entity entity : plugin.getBukkitHelper().getNearbyEntities(location, 20)) { - if(!(entity instanceof Player)) { + if (itemStack.getType() == Material.ROTTEN_FLESH) { + for (Entity entity : plugin.getBukkitHelper().getNearbyEntities(location, 20)) { + if (!(entity instanceof Player)) { continue; } Arena arena = plugin.getArenaRegistry().getArena((Player) entity); - if(arena == null) { + if (arena == null) { continue; } arena.changeArenaOptionBy("ROTTEN_FLESH_AMOUNT", itemStack.getAmount()); VersionUtils.sendParticles("CLOUD", arena.getPlayers(), location, 50, 2, 2, 2); - if(!arena.checkLevelUpRottenFlesh() || arena.getArenaOption("ROTTEN_FLESH_LEVEL") >= 30) { + if (!arena.checkLevelUpRottenFlesh() || arena.getArenaOption("ROTTEN_FLESH_LEVEL") >= 30) { return; } - for(Player player : arena.getPlayers()) { + for (Player player : arena.getPlayers()) { + player.setHealth(VersionUtils.getMaxHealth(player)); VersionUtils.setMaxHealth(player, VersionUtils.getMaxHealth(player) + 2.0); new MessageBuilder("IN_GAME_MESSAGES_VILLAGE_ROTTEN_FLESH_LEVEL_UP").asKey().player(player).sendPlayer(); } @@ -339,14 +377,14 @@ public void onSecretWellDrop(InventoryPickupItemEvent event) { @EventHandler(ignoreCancelled = true) public void onCombust(EntityCombustEvent event) { // Ignore if this is caused by an event lower down the chain. - if(event instanceof EntityCombustByEntityEvent || event instanceof EntityCombustByBlockEvent - || !(event.getEntity() instanceof Creature) - || event.getEntity().getWorld().getEnvironment() != World.Environment.NORMAL) { + if (event instanceof EntityCombustByEntityEvent || event instanceof EntityCombustByBlockEvent + || !(event.getEntity() instanceof Creature) + || event.getEntity().getWorld().getEnvironment() != World.Environment.NORMAL) { return; } - for(Arena arena : plugin.getArenaRegistry().getPluginArenas()) { - if(arena.getEnemies().contains(event.getEntity())) { + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (arena.getEnemies().contains(event.getEntity()) || arena.getSpecialEntities().contains(event.getEntity())) { event.setCancelled(true); break; } diff --git a/src/main/java/plugily/projects/villagedefense/handlers/hologram/ArmorStandHologram.java b/src/main/java/plugily/projects/villagedefense/handlers/hologram/ArmorStandHologram.java new file mode 100644 index 000000000..5eadcd6a7 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/hologram/ArmorStandHologram.java @@ -0,0 +1,268 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.hologram; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Item; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.Main; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author Plajer + *

+ * Created at 06.10.2023 + */ +public class ArmorStandHologram { + + private static final Main plugin = JavaPlugin.getPlugin(Main.class); + private final List armorStands = new ArrayList<>(); + private Item entityItem; + private ItemStack item; + private List lines = new ArrayList<>(); + private Location location; + private PickupHandler pickupHandler = null; + private TouchHandler touchHandler = null; + + public ArmorStandHologram() { + } + + public ArmorStandHologram(Location location) { + this.location = location; + plugin.getNewHologramManager().getHolograms().add(this); + } + + public ArmorStandHologram(Location location, @NotNull String... lines) { + this.location = location; + this.lines = Arrays.asList(lines); + plugin.getNewHologramManager().getHolograms().add(this); + append(); + } + + public ArmorStandHologram(Location location, @NotNull List lines) { + this.location = location; + this.lines = lines; + plugin.getNewHologramManager().getHolograms().add(this); + append(); + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public ItemStack getItem() { + return item; + } + + public Item getEntityItem() { + return entityItem; + } + + @NotNull + public List getLines() { + return lines; + } + + @NotNull + public List getArmorStands() { + return armorStands; + } + + public ArmorStandHologram overwriteLines(@NotNull String... lines) { + this.lines = Arrays.asList(lines); + append(); + return this; + } + + public ArmorStandHologram overwriteLines(@NotNull List lines) { + this.lines = lines; + append(); + return this; + } + + public ArmorStandHologram overwriteLine(@NotNull String line) { + this.lines = Collections.singletonList(line); + append(); + return this; + } + + public ArmorStandHologram appendLines(@NotNull String... lines) { + this.lines.addAll(Arrays.asList(lines)); + append(); + return this; + } + + public ArmorStandHologram appendLines(@NotNull List lines) { + this.lines.addAll(lines); + append(); + return this; + } + + public ArmorStandHologram appendLine(@NotNull String line) { + this.lines.add(line); + append(); + return this; + } + + public ArmorStandHologram appendItem(@NotNull ItemStack item) { + this.item = item; + append(); + return this; + } + + public void delete() { + for (ArmorStand armor : armorStands) { + armor.setCustomNameVisible(false); + armor.remove(); + plugin.getNewHologramManager().getArmorStands().remove(armor); + } + if (entityItem != null) { + entityItem.remove(); + } + plugin.getNewHologramManager().getHolograms().remove(this); + armorStands.clear(); + } + + public boolean isDeleted() { + return entityItem == null && armorStands.isEmpty(); + } + + private void append() { + delete(); + + World world = location.getWorld(); + if (world == null) { + return; + } + + double distanceAbove = -0.27; + double y = location.getY(); + + for (String line : lines) { + y += distanceAbove; + ArmorStand armorStand = getEntityArmorStand(y); + armorStand.setCustomName(line); + plugin.getDebugger().debug("Creating armorstand with name {0}", line); + armorStands.add(armorStand); + plugin.getNewHologramManager().getArmorStands().add(armorStand); + } + + if (item != null && item.getType() != org.bukkit.Material.AIR) { + entityItem = world.dropItem(location, item); + //set random uuid in meta to prevent item merging for multiple holograms being close + ItemMeta meta = entityItem.getItemStack().getItemMeta(); + meta.setLore(Arrays.asList(UUID.randomUUID().toString())); + entityItem.getItemStack().setItemMeta(meta); + entityItem.setMetadata("PLUGILY_HOLOGRAM", new FixedMetadataValue(plugin, true)); + /*if(VersionUtils.isPaper()) { + entityItem.setCanMobPickup(false); + }*/ + entityItem.setCustomNameVisible(false); + + if (ServerVersion.Version.isCurrentEqualOrHigher(ServerVersion.Version.v1_10_R1)) { + entityItem.setGravity(true); + } + + if (ServerVersion.Version.isCurrentHigher(ServerVersion.Version.v1_8_R3)) { + entityItem.setInvulnerable(true); + } + VersionUtils.teleport(entityItem, location); + } + } + + /** + * @param y the y axis of the hologram + * @return {@link ArmorStand} + */ + private ArmorStand getEntityArmorStand(double y) { + Location loc = location.clone(); + loc.setY(y); + + World world = loc.getWorld(); + if (ServerVersion.Version.isCurrentHigher(ServerVersion.Version.v1_8_R1)) { + world.getNearbyEntities(location, 0.2, 0.2, 0.2).forEach(entity -> { + if (entity instanceof ArmorStand && !armorStands.contains(entity) && !plugin.getNewHologramManager().getArmorStands().contains(entity)) { + entity.remove(); + entity.setCustomNameVisible(false); + plugin.getNewHologramManager().getArmorStands().remove(entity); + } + }); + } + ArmorStand stand = (ArmorStand) world.spawnEntity(loc, EntityType.ARMOR_STAND); + stand.setVisible(false); + stand.setGravity(false); + stand.setCustomNameVisible(true); + stand.setMetadata("PLUGILY_HOLOGRAM", new FixedMetadataValue(plugin, true)); + return stand; + } + + public PickupHandler getPickupHandler() { + return pickupHandler; + } + + /** + * Set a handler which triggers on player pickup item event + * + * @param handler which should be executed on pickup + */ + public ArmorStandHologram setPickupHandler(PickupHandler handler) { + plugin.getNewHologramManager().getHolograms().remove(this); + this.pickupHandler = handler; + plugin.getNewHologramManager().getHolograms().add(this); + return this; + } + + public boolean hasPickupHandler() { + return pickupHandler != null; + } + + public TouchHandler getTouchHandler() { + return touchHandler; + } + + public ArmorStandHologram setTouchHandler(TouchHandler handler) { + plugin.getNewHologramManager().getHolograms().remove(this); + this.touchHandler = handler; + plugin.getNewHologramManager().getHolograms().add(this); + return this; + } + + public boolean hasTouchHandler() { + return touchHandler != null; + } + +} \ No newline at end of file diff --git a/src/main/java/plugily/projects/villagedefense/handlers/hologram/NewHologramManager.java b/src/main/java/plugily/projects/villagedefense/handlers/hologram/NewHologramManager.java new file mode 100644 index 000000000..e77fcefa3 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/hologram/NewHologramManager.java @@ -0,0 +1,141 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.hologram; + +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import plugily.projects.minigamesbox.classic.PluginMain; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyEntityPickupItemEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Plajer + *

+ * Created at 06.10.2023 + */ +public class NewHologramManager implements Listener { + + private final PluginMain plugin; + private final List armorStands = new ArrayList<>(); + private final List holograms = new ArrayList<>(); + public NewHologramManager(PluginMain plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public List getArmorStands() { + return armorStands; + } + + public List getHolograms() { + return holograms; + } + + @EventHandler + public void onHologramDamage(EntityDamageByEntityEvent event) { + if (!event.getEntity().hasMetadata("PLUGILY_HOLOGRAM")) { + return; + } + if (!(event.getDamager() instanceof Player)) { + return; + } + if (onTouch((Player) event.getDamager(), event.getEntity())) { + event.setCancelled(true); + } + } + + @EventHandler + public void onHologramTouch(PlayerInteractAtEntityEvent event) { + if (!event.getRightClicked().hasMetadata("PLUGILY_HOLOGRAM")) { + return; + } + if (onTouch(event.getPlayer(), event.getRightClicked())) { + event.setCancelled(true); + } + } + + private boolean onTouch(Player player, Entity entity) { + for (ArmorStandHologram hologram : holograms) { + if (!hologram.hasTouchHandler()) { + continue; + } + Item entityItem = hologram.getEntityItem(); + boolean touch = false; + if (entity.equals(entityItem)) { + touch = true; + } + if (!touch) { + for (ArmorStand stand : hologram.getArmorStands()) { + if (entity.equals(stand)) { + touch = true; + break; + } + } + } + if (touch) { + if (plugin.getUserManager().getUser(player).isSpectator()) { + return false; + } + hologram.getTouchHandler().onTouch(player); + return true; + } + } + return false; + } + + @EventHandler + public void onItemPickup(PlugilyEntityPickupItemEvent event) { + if (!event.getItem().hasMetadata("PLUGILY_HOLOGRAM")) { + return; + } + if (!(event.getEntity() instanceof Player)) { + return; + } + Player player = (Player) event.getEntity(); + if (plugin.getUserManager().getUser(player).getArena() == null) { + return; + } + for (ArmorStandHologram hologram : holograms) { + if (!hologram.hasPickupHandler()) { + continue; + } + Item entityItem = hologram.getEntityItem(); + Item item = event.getItem(); + if (item.equals(entityItem)) { + if (plugin.getUserManager().getUser(player).isSpectator()) { + return; + } + event.setCancelled(true); + hologram.getPickupHandler().onPickup(player); + return; + } + } + //pickup not handled for known hologram, cancel it + event.setCancelled(true); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/hologram/PickupHandler.java b/src/main/java/plugily/projects/villagedefense/handlers/hologram/PickupHandler.java new file mode 100644 index 000000000..0818c2a2f --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/hologram/PickupHandler.java @@ -0,0 +1,34 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.hologram; + +import org.bukkit.entity.Player; + +/** + * Interface to handle items which are being picked up by players. + */ +public interface PickupHandler { + + /** + * Called when a player picks up the entity item of a hologram. + * + * @param player the player who picked up the entity item + */ + public void onPickup(Player player); +} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/hologram/TouchHandler.java b/src/main/java/plugily/projects/villagedefense/handlers/hologram/TouchHandler.java new file mode 100644 index 000000000..e49fce856 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/hologram/TouchHandler.java @@ -0,0 +1,32 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.hologram; + +import org.bukkit.entity.Player; + +/** + * @author Plajer + *

+ * Created at 06.10.2023 + */ +public interface TouchHandler { + + void onTouch(Player player); + +} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/powerup/PowerupHandler.java b/src/main/java/plugily/projects/villagedefense/handlers/powerup/PowerupHandler.java deleted file mode 100644 index afda46f1b..000000000 --- a/src/main/java/plugily/projects/villagedefense/handlers/powerup/PowerupHandler.java +++ /dev/null @@ -1,65 +0,0 @@ - -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.handlers.powerup; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import plugily.projects.minigamesbox.classic.api.event.player.PlugilyPlayerPowerupPickupEvent; -import plugily.projects.minigamesbox.classic.handlers.powerup.BasePowerup; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.ArenaUtils; - -/** - * @author Tigerpanzer_02 - *

- * Created at 20.12.2021 - */ -public class PowerupHandler implements Listener { - - private final Main plugin; - - public PowerupHandler(Main plugin) { - this.plugin = plugin; - plugin.getServer().getPluginManager().registerEvents(this, plugin); - } - - @EventHandler - public void onPowerUpPickup(PlugilyPlayerPowerupPickupEvent event) { - BasePowerup powerup = event.getPowerup(); - Arena arena = plugin.getArenaRegistry().getArena(event.getArena().getId()); - if(arena == null) { - return; - } - switch(powerup.getKey().toLowerCase()) { - case "map-clean": - ArenaUtils.removeSpawnedEnemies(arena); - break; - case "golem-raid": - for(int i = 0; i < (plugin.getPowerupRegistry().getLongestEffect(powerup) == 0 ? 3 : plugin.getPowerupRegistry().getLongestEffect(powerup)); i++) { - arena.spawnGolem(arena.getStartLocation(), event.getPlayer()); - } - break; - default: - break; - } - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgrade.java b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgrade.java new file mode 100644 index 000000000..aa939528e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgrade.java @@ -0,0 +1,185 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.upgrade; + +import org.bukkit.entity.EntityType; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EntityUpgrade { + + private String id; + private String metadataKey; + private String name; + private List description; + private int slot; + private int cost; + private EntityType applicableEntity; + private boolean hidden = false; + private int surviveWaves = -1; + private String dependsOn; + private Map upgradeData = new HashMap<>(); + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getMetadataKey() { + return metadataKey; + } + + public void setMetadataKey(String metadataKey) { + this.metadataKey = metadataKey; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getDescription() { + return description; + } + + public void setDescription(List description) { + this.description = description; + } + + public int getSlot() { + return slot; + } + + public void setSlot(int slot) { + this.slot = slot; + } + + public int getCost() { + return cost; + } + + public void setCost(int cost) { + this.cost = cost; + } + + public EntityType getApplicableEntity() { + return applicableEntity; + } + + public void setApplicableEntity(EntityType applicableEntity) { + this.applicableEntity = applicableEntity; + } + + public boolean isHidden() { + return hidden; + } + + public void setHidden(boolean hidden) { + this.hidden = hidden; + } + + public int getSurviveWaves() { + return surviveWaves; + } + + public void setSurviveWaves(int surviveWaves) { + this.surviveWaves = surviveWaves; + } + + public String getDependsOn() { + return dependsOn; + } + + public void setDependsOn(String dependsOn) { + this.dependsOn = dependsOn; + } + + public String getDependencyMetadataKey() { + return "VD_" + dependsOn; + } + + public Map getUpgradeData() { + return upgradeData; + } + + public static class Builder { + + private EntityUpgrade upgrade = new EntityUpgrade(); + + public Builder withId(String id) { + upgrade.setId(id); + upgrade.setMetadataKey("VD_" + id); + return this; + } + + public Builder withName(String name) { + upgrade.setName(name); + return this; + } + + public Builder withDescription(List description) { + upgrade.setDescription(description); + return this; + } + + public Builder atSlot(int slot) { + upgrade.setSlot(slot); + return this; + } + + public Builder withCost(int cost) { + upgrade.setCost(cost); + return this; + } + + public Builder withApplicableEntity(EntityType applicableEntity) { + upgrade.setApplicableEntity(applicableEntity); + return this; + } + + public Builder isHidden(int waveUnlock) { + upgrade.setSurviveWaves(waveUnlock); + upgrade.setHidden(true); + return this; + } + + public Builder andDependsOn(String id) { + upgrade.setDependsOn(id); + return this; + } + + public Builder putUpgradeData(String key, double value) { + upgrade.upgradeData.put(key, value); + return this; + } + + public EntityUpgrade build() { + return upgrade; + } + + } +} \ No newline at end of file diff --git a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgradeHandlerEvents.java b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgradeHandlerEvents.java new file mode 100644 index 000000000..6b434ff8e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgradeHandlerEvents.java @@ -0,0 +1,460 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.upgrade; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +//todo merge into single event +public class EntityUpgradeHandlerEvents implements Listener { + + private final Main plugin; + private final Map unstoppableStreak = new HashMap<>(); + + public EntityUpgradeHandlerEvents(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onSwarmAwareness(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Wolf wolf)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + EntityUpgrade swarmAwareness1 = plugin.getEntityUpgradeManager().getUpgrade("WOLF_SWARM_AWARENESS_1"); + EntityUpgrade swarmAwareness2 = plugin.getEntityUpgradeManager().getUpgrade("WOLF_SWARM_AWARENESS_2"); + if (!wolf.hasMetadata(swarmAwareness1.getMetadataKey()) + && !wolf.hasMetadata(swarmAwareness2.getMetadataKey())) { + return; + } + double increase = 0; + int nearby = 0; + for (Entity entity : plugin.getBukkitHelper().getNearbyEntities(event.getDamager().getLocation(), 3)) { + if (entity instanceof Wolf) { + nearby++; + } + } + if (event.getDamager().hasMetadata(swarmAwareness2.getMetadataKey())) { + increase = swarmAwareness2.getUpgradeData().get("increase"); + } else { + increase = swarmAwareness1.getUpgradeData().get("increase"); + } + double bonusPercent = Math.min(increase * nearby, 30) / 100.0; + event.setDamage(event.getDamage() + (event.getDamage() * bonusPercent)); + return; + } + } + + @EventHandler + public void onFinalDefense(EntityDeathEvent event) { + if (!(event.getEntity() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade finalDefense = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_FINAL_DEFENSE"); + if (!ironGolem.hasMetadata(finalDefense.getMetadataKey())) { + return; + } + VersionUtils.sendParticles("EXPLOSION_HUGE", arena.getPlayers(), ironGolem.getLocation(), 5); + for (Entity en : plugin.getBukkitHelper().getNearbyEntities(ironGolem.getLocation(), 6)) { + if (NewCreatureUtils.isEnemy(en)) { + ((Creature) en).damage(KitSpecifications.LETHAL_DAMAGE, ironGolem); + } + } + for (Entity en : plugin.getBukkitHelper().getNearbyEntities(ironGolem.getLocation(), 9)) { + if (NewCreatureUtils.isEnemy(en)) { + ((Creature) en).addPotionEffect(new PotionEffect(PotionEffectType.SLOW, Integer.MAX_VALUE, 1)); + ((Creature) en).damage(0.5, ironGolem); + } + } + return; + } + } + + @EventHandler + public void onUnstoppableStreak(EntityDeathEvent event) { + if (!(event.getEntity().getKiller() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade unstoppableStreak1 = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_UNSTOPPABLE_STREAK_1"); + EntityUpgrade unstoppableStreak2 = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_UNSTOPPABLE_STREAK_2"); + if (!ironGolem.hasMetadata(unstoppableStreak1.getMetadataKey()) + && !ironGolem.hasMetadata(unstoppableStreak2.getMetadataKey())) { + return; + } + double increaseValue; + if (ironGolem.hasMetadata(unstoppableStreak2.getMetadataKey())) { + increaseValue = unstoppableStreak2.getUpgradeData().get("increase"); + } else { + increaseValue = unstoppableStreak1.getUpgradeData().get("increase"); + } + if (unstoppableStreak.containsKey(ironGolem.getUniqueId())) { + Bukkit.getScheduler().cancelTask(unstoppableStreak.get(ironGolem.getUniqueId())); + } + final double originalDamage = ironGolem.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getBaseValue(); + ironGolem.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(originalDamage + increaseValue); + int taskId = Bukkit.getScheduler().runTaskLater(plugin, () -> ironGolem.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(originalDamage), 20 * 5).getTaskId(); + unstoppableStreak.put(ironGolem.getUniqueId(), taskId); + return; + } + } + + @EventHandler + public void onToughening(EntityDamageEvent event) { + if (!(event.getEntity() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade toughening = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_TOUGHENING"); + if (!ironGolem.hasMetadata(toughening.getMetadataKey())) { + return; + } + if (event.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION || event.getCause() == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) { + if (ironGolem.hasMetadata("VD_GOLEM_EXPLOSION_TIME")) { + Instant date = new Date(ironGolem.getMetadata("VD_GOLEM_EXPLOSION_TIME").get(0).asLong()).toInstant(); + if (Duration.between(date, Instant.now()).abs().toSeconds() <= 8) { + event.setDamage(event.getDamage() - (event.getDamage() * 0.3)); + } else { + ironGolem.removeMetadata("VD_GOLEM_EXPLOSION_TIME", plugin); + } + } + ironGolem.setMetadata("VD_GOLEM_EXPLOSION_TIME", new FixedMetadataValue(plugin, System.currentTimeMillis())); + } + if (ironGolem.getHealth() < ironGolem.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue() * 0.4) { + event.setDamage(event.getDamage() * 0.75); + } + return; + } + } + + @EventHandler + public void onWillToSurvive(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade willToSurvive = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_SURVIVOR"); + if (!ironGolem.hasMetadata(willToSurvive.getMetadataKey())) { + return; + } + double healAmount = event.getDamage() * 0.05; + ironGolem.setHealth(Math.min(ironGolem.getHealth() + healAmount, VersionUtils.getMaxHealth(ironGolem))); + return; + } + } + + @EventHandler + public void onBannerOfCommand(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade bannerOfCommand = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_BANNER_OF_COMMAND"); + for (Entity entity : ironGolem.getNearbyEntities(6, 6, 6)) { + if (!(entity instanceof IronGolem golem)) { + continue; + } + if (golem.hasMetadata(bannerOfCommand.getMetadataKey())) { + event.setDamage(event.getDamage() + (event.getDamage() * 0.1)); + } + } + return; + } + } + + @EventHandler + public void onRemembranceLament(EntityDeathEvent event) { + if (!(event.getEntity() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade remembranceLament = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_LAMENT"); + if (!ironGolem.hasMetadata(remembranceLament.getMetadataKey())) { + return; + } + for (Creature creature : arena.getEnemies()) { + if (KitHelper.executeEnemy(creature, ironGolem)) { + VersionUtils.sendParticles("LAVA", arena.getPlayers(), creature.getLocation(), 20); + } + } + List toHeal = new ArrayList<>(); + toHeal.addAll(arena.getPlayersLeft()); + toHeal.addAll(arena.getVillagers()); + toHeal.addAll(arena.getWolves()); + toHeal.addAll(arena.getIronGolems()); + for (LivingEntity livingEntity : toHeal) { + livingEntity.setHealth(VersionUtils.getMaxHealth(livingEntity)); + } + for (Player player : arena.getPlayers()) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&aOur beloved Iron Golem has died and protected the Village as a final wish, rest in peace.")); + } + } + } + + @EventHandler + public void onDeepWounds(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Wolf wolf) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + EntityUpgrade deepWounds = plugin.getEntityUpgradeManager().getUpgrade("WOLF_DEEP_WOUNDS"); + if (!wolf.hasMetadata(deepWounds.getMetadataKey())) { + return; + } + if (ThreadLocalRandom.current().nextInt(0, 100) <= 25) { + ((LivingEntity) event.getEntity()).addPotionEffect(new PotionEffect(PotionEffectType.POISON, 20 * 3, 0)); + } + } + } + + @EventHandler + public void onWolfPack(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Wolf wolf) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + if (event.getEntity().hasMetadata("VD_WOLF_PACK_MARKED")) { + Instant date = new Date(event.getEntity().getMetadata("VD_WOLF_PACK_MARKED").get(0).asLong()).toInstant(); + if (Duration.between(date, Instant.now()).abs().toSeconds() <= 5) { + event.setDamage(event.getDamage() + (event.getDamage() * 0.1)); + } else { + event.getEntity().removeMetadata("VD_WOLF_PACK_MARKED", plugin); + } + } + EntityUpgrade wolfPack = plugin.getEntityUpgradeManager().getUpgrade("WOLF_WOLF_PACK"); + if (wolf.hasMetadata(wolfPack.getMetadataKey())) { + event.getEntity().removeMetadata("VD_WOLF_PACK_MARKED", plugin); + event.getEntity().setMetadata("VD_WOLF_PACK_MARKED", new FixedMetadataValue(plugin, System.currentTimeMillis())); + } + } + } + + @EventHandler + public void onBloodyRevengeDeath(EntityDeathEvent event) { + if (!(event.getEntity() instanceof Wolf wolf)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + EntityUpgrade bloodyRevenge = plugin.getEntityUpgradeManager().getUpgrade("WOLF_BLOODY_REVENGE"); + for (Wolf arenaWolf : arena.getWolves()) { + if (!arenaWolf.hasMetadata(bloodyRevenge.getMetadataKey())) { + continue; + } + arenaWolf.setMetadata("VD_WOLF_BLOODY_REVENGE", new FixedMetadataValue(plugin, true)); + Bukkit.getScheduler().runTaskLater(plugin, () -> arenaWolf.removeMetadata("VD_WOLF_BLOODY_REVENGE", plugin), 20 * 5); + } + return; + } + } + + @EventHandler + public void onBloodyRevengeAttack(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Wolf wolf) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + if (!wolf.hasMetadata("VD_WOLF_BLOODY_REVENGE")) { + return; + } + double healAmount = event.getDamage() * 0.05; + wolf.setHealth(Math.min(wolf.getHealth() + healAmount, VersionUtils.getMaxHealth(wolf))); + event.setDamage(event.getDamage() + (event.getDamage() * 0.1)); + Vector velocity = event.getEntity().getLocation().getDirection().multiply(-1).normalize().multiply(0.3); + event.getEntity().setVelocity(velocity); + } + } + + @EventHandler + public void onRobber(EntityDeathEvent event) { + if (!(event.getEntity().getKiller() instanceof Wolf wolf)) { + return; + } + if (!wolf.hasMetadata("VD_OWNER_UUID")) { + return; + } + UUID playerId = UUID.fromString(wolf.getMetadata("VD_OWNER_UUID").get(0).asString()); + Player owner = Bukkit.getPlayer(playerId); + User user = plugin.getUserManager().getUser(owner); + if (user == null) { + return; + } + user.adjustStatistic(plugin.getStatsStorage().getStatisticType("ORBS"), ThreadLocalRandom.current().nextInt(4, 12)); + } + + @EventHandler + public void onWolfAlpha(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Wolf wolf)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + EntityUpgrade wolfAlpha = plugin.getEntityUpgradeManager().getUpgrade("WOLF_ALPHA"); + for (Entity entity : wolf.getNearbyEntities(6, 6, 6)) { + if (!(entity instanceof IronGolem golem)) { + continue; + } + if (golem.hasMetadata(wolfAlpha.getMetadataKey())) { + event.setDamage(event.getDamage() + (event.getDamage() * 0.1)); + } + } + return; + } + } + + @EventHandler + public void onMoreThanDeath(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Wolf wolf)) { + return; + } + if (wolf.hasMetadata("VD_WOLF_MORE_THAN_DEATH")) { + event.setDamage(0); + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getWolves().contains(wolf)) { + continue; + } + EntityUpgrade moreThanDeath = plugin.getEntityUpgradeManager().getUpgrade("WOLF_MORE_THAN_DEATH"); + if (!wolf.hasMetadata(moreThanDeath.getMetadataKey())) { + return; + } + if (event.getDamage() >= wolf.getHealth()) { + event.setDamage(0); + wolf.setMetadata("VD_WOLF_MORE_THAN_DEATH", new FixedMetadataValue(plugin, true)); + double defaultValue = wolf.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getBaseValue(); + wolf.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).setBaseValue(defaultValue + (defaultValue * 0.75)); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + wolf.removeMetadata("VD_WOLF_MORE_THAN_DEATH", plugin); + wolf.damage(KitSpecifications.LETHAL_DAMAGE); + }, 20 * 5); + } + } + } + + @EventHandler + public void onIronWillDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade ironWill = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_IRON_WILL"); + if (!ironGolem.hasMetadata(ironWill.getMetadataKey())) { + return; + } + int defaultAmount = plugin.getConfig().getInt("Limit.Spawn.Villagers", 10); + int missing = defaultAmount - arena.getVillagers().size(); + event.setDamage(event.getDamage() + (event.getDamage() * (0.03 * missing))); + return; + } + } + + @EventHandler + public void onIronWillReceiveDamage(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof IronGolem ironGolem)) { + return; + } + for (Arena arena : plugin.getArenaRegistry().getPluginArenas()) { + if (!arena.getIronGolems().contains(ironGolem)) { + continue; + } + EntityUpgrade ironWill = plugin.getEntityUpgradeManager().getUpgrade("GOLEM_IRON_WILL"); + if (!ironGolem.hasMetadata(ironWill.getMetadataKey())) { + return; + } + int defaultAmount = plugin.getConfig().getInt("Limit.Spawn.Villagers", 10); + int missing = defaultAmount - arena.getVillagers().size(); + event.setDamage(event.getDamage() - (event.getDamage() * (0.03 * missing))); + return; + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgradeMenu.java b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgradeMenu.java deleted file mode 100644 index 4d259cb40..000000000 --- a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/EntityUpgradeMenu.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.handlers.upgrade; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.FixedMetadataValue; -import org.jetbrains.annotations.Nullable; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.minigamesbox.inventory.normal.NormalFastInv; -import plugily.projects.villagedefense.Main; -import plugily.projects.villagedefense.api.event.player.VillagePlayerEntityUpgradeEvent; -import plugily.projects.villagedefense.creatures.CreatureUtils; -import plugily.projects.villagedefense.events.EntityUpgradeListener; -import plugily.projects.villagedefense.handlers.upgrade.upgrades.Upgrade; -import plugily.projects.villagedefense.handlers.upgrade.upgrades.UpgradeBuilder; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * @author Plajer - *

- * Created at 18.06.2019 - */ -public class EntityUpgradeMenu { - - private final List upgrades = new ArrayList<>(); - private final Main plugin; - - public EntityUpgradeMenu(Main plugin) { - this.plugin = plugin; - new EntityUpgradeListener(this); - registerUpgrade(new UpgradeBuilder("Damage") - .entity(Upgrade.EntityType.BOTH).slot(2, 1).maxTier(4).metadata("VD_Damage") - //2.0 + (tier * 3) - .tierValue(0, 2.0).tierValue(1, 5.0).tierValue(2, 8.0).tierValue(3, 11.0).tierValue(4, 14.0) - .build()); - registerUpgrade(new UpgradeBuilder("Health") - .entity(Upgrade.EntityType.BOTH).slot(2, 2).maxTier(4).metadata("VD_Health") - //100.0 + (100.0 * (tier / 2.0)) - .tierValue(0, 100.0).tierValue(1, 150.0).tierValue(2, 200.0).tierValue(3, 250.0).tierValue(4, 300.0) - .build()); - registerUpgrade(new UpgradeBuilder("Speed") - .entity(Upgrade.EntityType.BOTH).slot(2, 3).maxTier(4).metadata("VD_Speed") - //0.25 + (0.25 * ((double) tier / 5.0)) - .tierValue(0, 0.25).tierValue(1, 0.3).tierValue(2, 0.35).tierValue(3, 0.4).tierValue(4, 0.45) - .build()); - registerUpgrade(new UpgradeBuilder("Swarm-Awareness") - .entity(Upgrade.EntityType.WOLF).slot(3, 4).maxTier(2).metadata("VD_SwarmAwareness") - //tier * 0.2 - .tierValue(0, 0).tierValue(1, 0.2).tierValue(2, 0.4) - .build()); - registerUpgrade(new UpgradeBuilder("Final-Defense") - .entity(Upgrade.EntityType.IRON_GOLEM).slot(3, 4).maxTier(2).metadata("VD_FinalDefense") - //tier * 5 - .tierValue(0, 0).tierValue(1, 5).tierValue(2, 10) - .build()); - } - - /** - * Registers new upgrade - * - * @param upgrade upgrade to registry - */ - public void registerUpgrade(Upgrade upgrade) { - upgrades.add(upgrade); - } - - @Nullable - public Upgrade getUpgrade(String id) { - for(Upgrade upgrade : upgrades) { - if(upgrade.getId().equals(id)) { - return upgrade; - } - } - return null; - } - - /** - * Opens menu with upgrades for wolf or golem - * - * @param livingEntity entity to check upgrades for - * @param player player who will see inventory - */ - public void openUpgradeMenu(LivingEntity livingEntity, Player player) { - NormalFastInv gui = new NormalFastInv(6 * 9, color("UPGRADE_MENU_TITLE")); - gui.addClickHandler(inventoryClickEvent -> inventoryClickEvent.setCancelled(true)); - User user = plugin.getUserManager().getUser(player); - - for(Upgrade upgrade : upgrades) { - if(upgrade.getApplicableFor() != Upgrade.EntityType.BOTH && !livingEntity.getType().toString().equals(upgrade.getApplicableFor().toString())) { - continue; - } - int x = upgrade.getSlotX(); - int y = upgrade.getSlotY(); - gui.setItem(x + y * 9, upgrade.asItemStack(getTier(livingEntity, upgrade)), event -> { - int nextTier = getTier(livingEntity, upgrade) + 1; - int cost = upgrade.getCost(nextTier); - if(nextTier > upgrade.getMaxTier()) { - player.sendMessage(color("UPGRADE_MENU_MAX_TIER")); - return; - } - - int orbs = user.getStatistic("ORBS"); - if(orbs < cost) { - player.sendMessage(color("UPGRADE_MENU_CANNOT_AFFORD")); - return; - } - - user.setStatistic("ORBS", orbs - cost); - player.sendMessage(color("UPGRADE_MENU_UPGRADED_ENTITY").replace("%tier%", Integer.toString(nextTier))); - applyUpgrade(livingEntity, upgrade); - - Bukkit.getPluginManager().callEvent(new VillagePlayerEntityUpgradeEvent(plugin.getArenaRegistry().getArena(player), livingEntity, player, upgrade, nextTier)); - player.closeInventory(); - openUpgradeMenu(livingEntity, player); - }); - for(int i = 0; i < upgrade.getMaxTier(); i++) { - if(i < getTier(livingEntity, upgrade)) { - gui.setItem((x + 1 + i) + y * 9, new ItemBuilder(XMaterial.YELLOW_STAINED_GLASS_PANE.parseItem()).name(" ").build()); - } else { - gui.setItem((x + 1 + i) + y * 9, new ItemBuilder(XMaterial.WHITE_STAINED_GLASS_PANE.parseItem()).name(" ").build()); - } - } - } - applyStatisticsBookOfEntityToGui(gui, livingEntity); - gui.open(player); - } - - private String color(String key) { - return new MessageBuilder(key).asKey().build(); - } - - private void applyStatisticsBookOfEntityToGui(NormalFastInv gui, LivingEntity livingEntity) { - String[] lore = color("UPGRADE_MENU_STATS_ITEM_DESCRIPTION").split(";"); - - for(int a = 0; a < lore.length; a++) { - Upgrade speed = getUpgrade("Speed"); - Upgrade damage = getUpgrade("Damage"); - Upgrade health = getUpgrade("Health"); - - lore[a] = lore[a].replace("%speed%", Double.toString(speed.getValueForTier(getTier(livingEntity, speed)))) - .replace("%damage%", Double.toString(damage.getValueForTier(getTier(livingEntity, damage)))) - .replace("%max_hp%", Double.toString(health.getValueForTier(getTier(livingEntity, health)))) - .replace("%current_hp%", Double.toString(livingEntity.getHealth())); - } - - gui.setItem(4, new ItemBuilder(new ItemStack(Material.BOOK)) - .name(color("UPGRADE_MENU_STATS_ITEM_NAME")) - .lore(lore) - .build()); - } - - /** - * Applies upgrade for target entity - * automatically increments current tier - * - * @param entity target entity - * @param upgrade upgrade to apply - * @return true if applied successfully, false if tier is max and cannot be applied more - */ - public boolean applyUpgrade(Entity entity, Upgrade upgrade) { - List meta = entity.getMetadata(upgrade.getMetadataAccessor()); - - if(meta.isEmpty()) { - entity.setMetadata(upgrade.getMetadataAccessor(), new FixedMetadataValue(plugin, 1)); - applyUpgradeEffect(entity, upgrade, 1); - return true; - } - - if(meta.get(0).asInt() == upgrade.getMaxTier()) { - return false; - } - - int tier = getTier(entity, upgrade) + 1; - entity.setMetadata(upgrade.getMetadataAccessor(), new FixedMetadataValue(plugin, tier)); - applyUpgradeEffect(entity, upgrade, tier); - if(upgrade.getMaxTier() == tier) { - VersionUtils.playSound(entity.getLocation(), "BLOCK_ANVIL_USE"); - VersionUtils.sendParticles("EXPLOSION_LARGE", (Set) null, entity.getLocation(), 5); - } - return true; - } - - private void applyUpgradeEffect(Entity entity, Upgrade upgrade, int tier) { - org.bukkit.Location entityLocation = entity.getLocation(); - - VersionUtils.sendParticles("FIREWORKS_SPARK", null, entityLocation.add(0, 1, 0), 30, 0.7, 0.7, 0.7); - VersionUtils.sendParticles("HEART", (Set) null, entityLocation.add(0, 1.6, 0), 5); - VersionUtils.playSound(entityLocation, "ENTITY_PLAYER_LEVELUP"); - - int[] baseValues = new int[]{getTier(entity, getUpgrade("Health")), getTier(entity, getUpgrade("Speed")), getTier(entity, getUpgrade("Damage"))}; - - if(areAllEqualOrHigher(baseValues) && getMinValue(baseValues) == 4) { - //final mode! rage!!! - VersionUtils.setGlowing(entity, true); - } - - switch(upgrade.getId()) { - case "Damage": - if(entity.getType() == EntityType.WOLF) { - CreatureUtils.getCreatureInitializer().applyDamageModifier((LivingEntity) entity, 2.0 + (tier * 3)); - } - //attribute damage doesn't exist for golems - break; - case "Health": - LivingEntity living = (LivingEntity) entity; - - VersionUtils.setMaxHealth(living, 100.0 + (100.0 * (tier / 2.0))); - living.setHealth(VersionUtils.getMaxHealth(living)); - break; - case "Speed": - CreatureUtils.getCreatureInitializer().applySpeedModifier((LivingEntity) entity, 0.25 + (0.25 * (tier / 5.0))); - break; - case "Swarm-Awareness": - case "Final-Defense": - //do nothing they are used within events - break; - default: - break; - } - } - - public List getUpgrades() { - return upgrades; - } - - private boolean areAllEqualOrHigher(int[] numbers) { - for(int i = 1; i < numbers.length; i++) { - if(numbers[0] < numbers[i]) { - return false; - } - } - return true; - } - - private int getMinValue(int[] numbers) { - int minValue = numbers[0]; - for(int i = 1; i < numbers.length; i++) { - if(numbers[i] < minValue) { - minValue = numbers[i]; - } - } - return minValue; - } - - /** - * @param entity entity to check - * @param upgrade upgrade type - * @return current tier of upgrade for target entity - */ - public int getTier(Entity entity, Upgrade upgrade) { - List meta = entity.getMetadata(upgrade.getMetadataAccessor()); - return meta.isEmpty() ? 0 : meta.get(0).asInt(); - } - - public Main getPlugin() { - return plugin; - } -} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/NewEntityUpgradeManager.java b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/NewEntityUpgradeManager.java new file mode 100644 index 000000000..7a0da61c3 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/NewEntityUpgradeManager.java @@ -0,0 +1,638 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.handlers.upgrade; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.attribute.Attribute; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.jetbrains.annotations.Nullable; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.MiscUtils; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.inventory.normal.NormalFastInv; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.ArenaManager; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class NewEntityUpgradeManager { + + public static final String UPGRADES_DISABLED_METADATA = "VD_UPGRADES_DISABLED"; + + private final List registeredUpgrades = new ArrayList<>(); + private final Main plugin; + + public NewEntityUpgradeManager(Main plugin) { + this.plugin = plugin; + registerUpgrades(); + } + + private void registerUpgrades() { + registerGolemUpgrades(); + registerWolfUpgrades(); + } + + private void registerGolemUpgrades() { + for (int i = 0; i < 3; i++) { + EntityUpgrade.Builder builder = new EntityUpgrade.Builder() + .withId("GOLEM_HEALTH_AND_REGEN_" + (i + 1)) + .withName(color("&a&lHEALTH AND REGEN " + toRoman(i + 1))) + .withDescription(listFromStrings( + color("&aUpgrade Max Health to &e&l" + (100 * (i + 1)) + " HP"), + color("&aand Per Wave Regeneration to &e&l" + (2 * (i + 1)) + " HP"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(10 + i) + .putUpgradeData("max_hp", 100 * (i + 1)) + .putUpgradeData("regen", 2 * (i + 1)) + .withCost(150 * (i + 1)); + if (i > 0) { + builder = builder.andDependsOn("GOLEM_HEALTH_AND_REGEN_" + i); + } + registeredUpgrades.add(builder.build()); + } + for (int i = 0; i < 3; i++) { + EntityUpgrade.Builder builder = new EntityUpgrade.Builder() + .withId("GOLEM_DAMAGE_AND_SPEED_" + (i + 1)) + .withName(color("&a&lDAMAGE AND SPEED " + toRoman(i + 1))) + .withDescription(listFromStrings( + color("&aIncrease Damage by &e&l" + (3 + (i * 3)) + " DMG"), + color("&aand Movement Speed by &e&l" + (0.25 + ((i + 1) * 0.05)) + " MS"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(14 + i) + .putUpgradeData("damage", 3 + (i * 3)) + .putUpgradeData("movement_speed", 0.25 + ((i + 1) * 0.05)) + .withCost(150 * (i + 1)); + if (i > 0) { + builder = builder.andDependsOn("GOLEM_DAMAGE_AND_SPEED_" + i); + } + registeredUpgrades.add(builder.build()); + } + for (int i = 0; i < 2; i++) { + EntityUpgrade.Builder builder = new EntityUpgrade.Builder() + .withId("GOLEM_UNSTOPPABLE_STREAK_" + (i + 1)) + .withName(color("&6&lUNSTOPPABLE STREAK " + toRoman(i + 1))) + .withDescription(listFromStrings( + color("&aEvery kill increases damage"), + color("&aby &e&l" + (5 + (i * 5)) + "%&a for five seconds"), + color("&aand consecutive kills reset the timer"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(28 + i) + .putUpgradeData("increase", 5 + (i * 5)) + .withCost(200 * (i + 1)); + if (i > 0) { + builder = builder.andDependsOn("GOLEM_UNSTOPPABLE_STREAK_" + i); + } + registeredUpgrades.add(builder.build()); + } + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("GOLEM_FINAL_DEFENSE") + .withName(color("&6&lFINAL DEFENSE")) + .withDescription(listFromStrings( + color("&aOn death &e&lLETHALLY DAMAGE"), + color("&aenemies within six blocks and &e&lPERMA"), + color("&e&lSLOW&a all enemies within nine blocks"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(32) + .withCost(250) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("GOLEM_TOUGHENING") + .withName(color("&6&lTOUGHENING")) + .withDescription(listFromStrings( + color("&aReceive &e&l25% LESS DMG&a while"), + color("&abelow 40% HP and receive &e&l30% LESS DMG"), + color("&afrom explosion if recently damaged"), + color("&aby an explosion within eight seconds"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(33) + .withCost(300) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("GOLEM_IRON_WILL") + .withName(color("&6&lIRON WILL")) + .withDescription(listFromStrings( + color("&aIncrease &e&lDAMAGE and ARMOR"), + color("&aby &e&l3%&a for every one"), + color("&avillager killed in game"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(34) + .withCost(300) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("GOLEM_SURVIVOR") + .withName(color("&b&lWILL TO SURVIVE")) + .withDescription(listFromStrings( + color("&aReceive &e&l5% LIFESTEAL&a and"), + color("&e&l10% MAX HEALTH REGEN&a every wave"), + color("&aUnlocked for surviving three"), + color("&aand more waves in game"), + "", + color("&8(Survivor upgrade)") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(48) + .isHidden(4) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("GOLEM_BANNER_OF_COMMAND") + .withName(color("&b&lBANNER OF COMMAND")) + .withDescription(listFromStrings( + color("&aInspire nearby Iron Golems"), + color("&awith &e&l10% BONUS DMG"), + color("&awithin six blocks radius"), + color("&aUnlocked for surviving five"), + color("&aand more waves in game"), + "", + color("&8(Survivor upgrade)") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(49) + .isHidden(7) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("GOLEM_LAMENT") + .withName(color("&b&lREMEMBRANCE LAMENT")) + .withDescription(listFromStrings( + color("&aOn death &e&lKILL EVERY"), + color("&aalive enemy and &e&lHEAL&a every"), + color("&aalive ally (villager, pet & player)"), + color("&ato 100% HP as a final gift"), + color("&aUnlocked for surviving seven"), + color("&aand more waves in game"), + "", + color("&8(Survivor upgrade)") + )) + .withApplicableEntity(EntityType.IRON_GOLEM) + .atSlot(50) + .isHidden(10) + .build()); + } + + private void registerWolfUpgrades() { + for (int i = 0; i < 3; i++) { + EntityUpgrade.Builder builder = new EntityUpgrade.Builder() + .withId("WOLF_HEALTH_AND_REGEN_" + (i + 1)) + .withName(color("&a&lHEALTH AND REGEN " + toRoman(i + 1))) + .withDescription(listFromStrings( + color("&aUpgrade Max Health to &e&l" + (30 * (i + 1)) + " HP"), + color("&aand Per Wave Regeneration to &e&l" + (1.5 * (i + 1)) + " HP"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(10 + i) + .putUpgradeData("max_hp", 30 * (i + 1)) + .putUpgradeData("regen", 1.5 * (i + 1)) + .withCost(150 * (i + 1)); + if (i > 0) { + builder = builder.andDependsOn("WOLF_HEALTH_AND_REGEN_" + i); + } + registeredUpgrades.add(builder.build()); + } + for (int i = 0; i < 3; i++) { + EntityUpgrade.Builder builder = new EntityUpgrade.Builder() + .withId("WOLF_DAMAGE_AND_SPEED_" + (i + 1)) + .withName(color("&a&lDAMAGE AND SPEED " + toRoman(i + 1))) + .withDescription(listFromStrings( + color("&aIncrease Damage by &e&l" + (2 + (i * 2)) + " DMG"), + color("&aand Movement Speed by &e&l" + (0.25 + ((i + 1) * 0.05)) + " MS"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(14 + i) + .putUpgradeData("damage", 2 + (i * 2)) + .putUpgradeData("movement_speed", 0.25 + ((i + 1) * 0.05)) + .withCost(150 * (i + 1)); + if (i > 0) { + builder = builder.andDependsOn("WOLF_DAMAGE_AND_SPEED_" + i); + } + registeredUpgrades.add(builder.build()); + } + for (int i = 0; i < 2; i++) { + EntityUpgrade.Builder builder = new EntityUpgrade.Builder() + .withId("WOLF_SWARM_AWARENESS_" + (i + 1)) + .withName(color("&6&lSWARM AWARENESS " + toRoman(i + 1))) + .withDescription(listFromStrings( + color("&aWolf deals &e&l" + (3 + (i * 2)) + "% BONUS DMG&a per"), + color("&awolf nearby within three blocks"), + color("&aradius capped at 30% BONUS DMG"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(28 + i) + .putUpgradeData("increase", 3 + (i * 2)) + .withCost(200 * (i + 1)); + if (i > 0) { + builder = builder.andDependsOn("WOLF_SWARM_AWARENESS_" + i); + } + registeredUpgrades.add(builder.build()); + } + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("WOLF_BLOODY_REVENGE") + .withName(color("&6&lBLOODY REVENGE")) + .withDescription(listFromStrings( + color("&aOn ally wolf death &e&lENRAGE"), + color("&athe wolf to receive &e&l5% LIFESTEAL"), + color("&e&l10% BONUS DAMAGE&a and &e&lKNOCKBACK"), + color("&afor five seconds"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(32) + .withCost(250) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("WOLF_WOLF_PACK") + .withName(color("&6&lWOLF PACK")) + .withDescription(listFromStrings( + color("&aAttacking an enemy &e&lINCREASES"), + color("&e&lDAMAGE&a dealt by other wolves"), + color("&aby &e&l10% DMG&a for five seconds"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(33) + .withCost(300) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("WOLF_DEEP_WOUNDS") + .withName(color("&6&lDEEP WOUNDS")) + .withDescription(listFromStrings( + color("&aReceive &e&l25% CHANCE&a when"), + color("&aattacking an enemy to apply"), + color("&e&lBLEEDING&a for three seconds"), + color("&e&lCOST:&a %cost_value% orbs"), + "", + color("&8Click to purchase") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(34) + .withCost(300) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("WOLF_ROBBER") + .withName(color("&b&lROBBER")) + .withDescription(listFromStrings( + color("&aGenerate &e&l4-12 BONUS ORBS"), + color("&ato owner for every enemy killed"), + color("&aUnlocked for surviving three"), + color("&aand more waves in game"), + "", + color("&8(Survivor upgrade)") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(48) + .isHidden(4) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("WOLF_ALPHA") + .withName(color("&b&lALPHA WOLF")) + .withDescription(listFromStrings( + color("&aInspire nearby Wolves"), + color("&awith &e&l10% BONUS DMG"), + color("&awithin six blocks radius"), + color("&aUnlocked for surviving five"), + color("&aand more waves in game"), + "", + color("&8(Survivor upgrade)") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(49) + .isHidden(7) + .build()); + registeredUpgrades.add(new EntityUpgrade.Builder() + .withId("WOLF_MORE_THAN_DEATH") + .withName(color("&b&lMORE THAN DEATH")) + .withDescription(listFromStrings( + color("&aUpon receiving fatal damage"), + color("&abe &e&lUNKILLABLE&a and receive"), + color("&e&l75% BONUS DMG&a for five seconds"), + color("&athen perish into the shadows"), + color("&aUnlocked for surviving seven"), + color("&aand more waves in game"), + "", + color("&8(Survivor upgrade)") + )) + .withApplicableEntity(EntityType.WOLF) + .atSlot(50) + .isHidden(10) + .build()); + } + + private List listFromStrings(String... lines) { + return new ArrayList<>(Arrays.asList(lines)); + } + + public List getRegisteredUpgrades() { + return registeredUpgrades; + } + + @Nullable + public EntityUpgrade getUpgrade(String id) { + for (EntityUpgrade upgrade : registeredUpgrades) { + if (upgrade.getId().equals(id)) { + return upgrade; + } + } + return null; + } + + /** + * Opens menu with upgrades for wolf or golem + * + * @param livingEntity entity to check upgrades for + * @param player player who will see inventory + */ + public void openUpgradeMenu(LivingEntity livingEntity, Player player) { + NormalFastInv gui = new NormalFastInv(6 * 9, color("&e&lENTITY UPGRADES")); + gui.addClickHandler(inventoryClickEvent -> inventoryClickEvent.setCancelled(true)); + User user = plugin.getUserManager().getUser(player); + + for (EntityUpgrade upgrade : registeredUpgrades) { + if (!upgrade.getApplicableEntity().equals(livingEntity.getType())) { + continue; + } + gui.setItem(upgrade.getSlot(), upgradeAsItem(livingEntity, upgrade), event -> { + event.setCancelled(true); + if (upgrade.isHidden()) { + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1, 1); + return; + } + if (livingEntity.hasMetadata(upgrade.getMetadataKey())) { + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1, 1); + return; + } + if (upgrade.getDependsOn() != null && !livingEntity.hasMetadata(upgrade.getDependencyMetadataKey())) { + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1, 1); + return; + } + int orbs = user.getStatistic("ORBS"); + if (orbs < upgrade.getCost()) { + new MessageBuilder("UPGRADE_MENU_CANNOT_AFFORD").asKey().player(player).sendPlayer(); + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1, 1); + return; + } + user.setStatistic("ORBS", orbs - upgrade.getCost()); + player.sendMessage(color("&aSuccessfully upgraded entity!")); + user.getArena().changeArenaOptionBy("TOTAL_ORBS_SPENT", orbs); + applyUpgradeWithVisuals(livingEntity, player, upgrade); + + openUpgradeMenu(livingEntity, player); + }); + applyStatisticsBookOfEntityToGui(gui, livingEntity); + } + gui.open(player); + } + + private void applyStatisticsBookOfEntityToGui(NormalFastInv gui, LivingEntity entity) { + List lore = new ArrayList<>(); + double healPower = ArenaManager.DEFAULT_PET_HEAL_POWER; + double defaultHeal = entity instanceof IronGolem ? 2.0 : 1.0; + String prefix = entity instanceof IronGolem ? "GOLEM_" : "WOLF_"; + for (int i = 3; i > 0; i--) { + EntityUpgrade heal = plugin.getEntityUpgradeManager().getUpgrade(prefix + "HEALTH_AND_REGEN_" + i); + if (entity.hasMetadata(heal.getMetadataKey())) { + defaultHeal += heal.getUpgradeData().getOrDefault("regen", 0.0); + break; + } + } + healPower = healPower * defaultHeal; + lore.add("&a&lHEALTH: &7" + entity.getHealth() + "/" + VersionUtils.getMaxHealth(entity) + " (&a&lREGEN &7" + healPower + " HP/wave)"); + lore.add("&a&lDAMAGE: &7" + entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getBaseValue() + " DMG"); + lore.add("&a&lMOVEMENT SPEED: &7" + entity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED).getBaseValue() + " MS"); + int totalKills = 0; + if (entity.hasMetadata("VD_ENTITY_KILLS")) { + totalKills = entity.getMetadata("VD_ENTITY_KILLS").get(0).asInt(); + } + lore.add("&a&lKILLS: &7" + totalKills); + gui.setItem(4, new ItemBuilder(new ItemStack(Material.BOOK)) + .name(color("&e&lCURRENT STATISTICS")) + .lore( + lore.stream() + .map(this::color) + .collect(Collectors.toList()) + ) + .build()); + } + + private ItemStack upgradeAsItem(LivingEntity entity, EntityUpgrade upgrade) { + Material icon; + String name = upgrade.getName(); + List lore = upgrade.getDescription(); + if (entity.hasMetadata(upgrade.getMetadataKey())) { + icon = Material.LIME_DYE; + name = color("&a&l✓ ") + name; + } else { + if (upgrade.isHidden()) { + icon = Material.MAGENTA_DYE; + name = color("&c&lSECRET UPGRADE"); + lore = listFromStrings( + color("&aThis upgrade will be"), + color("&aautomatically unlocked when"), + color("&aentity survives " + upgrade.getSurviveWaves() + " waves") + ); + } else { + icon = Material.GRAY_DYE; + name = color("&c&l✘ ") + name; + } + } + lore = lore.stream() + .map(line -> line.replace("%cost_value%", String.valueOf(upgrade.getCost()))) + .collect(Collectors.toList()); + return new ItemBuilder(icon) + .name(name) + .lore(lore) + .build(); + } + + private String toRoman(int number) { + return switch (number) { + case 1 -> "I"; + case 2 -> "II"; + case 3 -> "III"; + default -> "?"; + }; + } + + private String color(String text) { + return ChatColor.translateAlternateColorCodes('&', text); + } + + public boolean applyUpgradeSilent(Entity entity, Player player, EntityUpgrade upgrade) { + List meta = entity.getMetadata(upgrade.getMetadataKey()); + + if (!meta.isEmpty()) { + return false; + } + entity.setMetadata(upgrade.getMetadataKey(), new FixedMetadataValue(plugin, true)); + applyUpgradeEffect(entity, player, upgrade, true); + applyUpgradeOnEntity(entity, upgrade); + return true; + } + + /** + * Applies upgrade for target entity + * + * @param entity target entity + * @param player player which upgraded target + * @param upgrade upgrade to apply + * @return true if applied successfully, false if cannot be applied + */ + public boolean applyUpgradeWithVisuals(Entity entity, Player player, EntityUpgrade upgrade) { + List meta = entity.getMetadata(upgrade.getMetadataKey()); + + if (!meta.isEmpty()) { + return false; + } + entity.setMetadata(upgrade.getMetadataKey(), new FixedMetadataValue(plugin, true)); + applyUpgradeEffect(entity, player, upgrade, false); + applyUpgradeOnEntity(entity, upgrade); + return true; + } + + private void applyUpgradeEffect(Entity entity, Player player, EntityUpgrade upgrade, boolean silent) { + if (!silent) { + applyParticlesAndSounds(entity, upgrade); + } + int totalLevel = 0; + for (EntityUpgrade entityUpgrade : registeredUpgrades) { + if (entityUpgrade.getApplicableEntity() == entity.getType() && entity.hasMetadata(entityUpgrade.getMetadataKey())) { + totalLevel++; + } + } + entity.setCustomName(NewCreatureUtils.getHealthNameTag((Creature) entity)); + User user = plugin.getUserManager().getUser(player); + ChatColor targetColor = null; + if (totalLevel >= 13) { + targetColor = ChatColor.RED; + } else if (totalLevel == 12) { + targetColor = ChatColor.GOLD; + } else if (totalLevel == 11) { + targetColor = ChatColor.YELLOW; + } else if (totalLevel == 10) { + targetColor = ChatColor.WHITE; + } + if (targetColor != null) { + try { + for (Player arenaPlayer : user.getArena().getPlayers()) { + plugin.getGlowingEntities().setGlowing(entity, arenaPlayer, ChatColor.GOLD); + } + } catch (Exception ignored) { + } + } + } + + private void applyUpgradeOnEntity(Entity entity, EntityUpgrade upgrade) { + LivingEntity living = (LivingEntity) entity; + if (upgrade.getId().contains("HEALTH_AND_REGEN")) { + VersionUtils.setMaxHealth(living, upgrade.getUpgradeData().get("max_hp")); + living.setHealth(VersionUtils.getMaxHealth(living)); + } else if (upgrade.getId().contains("DAMAGE_AND_SPEED")) { + double baseDamage = living.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).getBaseValue(); + MiscUtils.getEntityAttribute(living, Attribute.GENERIC_ATTACK_DAMAGE).ifPresent(ai -> ai.setBaseValue(baseDamage + upgrade.getUpgradeData().get("damage"))); + MiscUtils.getEntityAttribute(living, Attribute.GENERIC_MOVEMENT_SPEED).ifPresent(ai -> ai.setBaseValue(upgrade.getUpgradeData().get("movement_speed"))); + } + } + + private void applyParticlesAndSounds(Entity entity, EntityUpgrade upgrade) { + Location targetLocation = entity.getLocation().clone(); + if (entity instanceof IronGolem) { + targetLocation = targetLocation.add(0, 1.6, 0); + } else { + targetLocation = targetLocation.add(0, 0.75, 0); + } + if (upgrade.getId().contains("HEALTH_AND_REGEN")) { + VersionUtils.sendParticles("HEART", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("DAMAGE_AND_SPEED")) { + VersionUtils.sendParticles("CRIT", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("UNSTOPPABLE_STREAK")) { + VersionUtils.sendParticles("EXPLOSION_LARGE", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("FINAL_DEFENSE") || upgrade.getId().contains("LAMENT")) { + VersionUtils.sendParticles("DAMAGE_INDICATOR", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("SURVIVOR") || upgrade.getId().contains("TOUGHENING")) { + VersionUtils.sendParticles("DRIP_LAVA", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("BANNER_OF_COMMAND") || upgrade.getId().contains("ALPHA")) { + VersionUtils.sendParticles("ENCHANTMENT_TABLE", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("SWARM_AWARENESS")) { + VersionUtils.sendParticles("SOUL", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("BLOODY_REVENGE") || upgrade.getId().contains("PACK")) { + VersionUtils.sendParticles("VILLAGER_ANGRY", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("DEEP_WOUNDS") || upgrade.getId().contains("MORE_THAN_DEATH")) { + VersionUtils.sendParticles("GLOW", null, targetLocation, 15, 0.7, 0.7, 0.7); + } else if (upgrade.getId().contains("ROBBER")) { + VersionUtils.sendParticles("SNEEZE", null, targetLocation, 15, 0.7, 0.7, 0.7); + } + if (upgrade.isHidden()) { + targetLocation.getWorld().playSound(targetLocation, Sound.ENTITY_PLAYER_LEVELUP, 1, 0.25f); + } else { + targetLocation.getWorld().playSound(targetLocation, Sound.ENTITY_PLAYER_LEVELUP, 1, 0.5f); + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/upgrades/Upgrade.java b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/upgrades/Upgrade.java deleted file mode 100644 index 03451a82f..000000000 --- a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/upgrades/Upgrade.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.handlers.upgrade.upgrades; - -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.Main; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * @author Plajer - *

- * Created at 18.06.2019 - */ -public class Upgrade { - - private static Main plugin; - private final String id; - private int slotX; - private int slotY; - private EntityType entityType; - private int maxTier; - private String name; - private List description = new ArrayList<>(); - private String metadataAccessor; - private final String configAccessor; - private final Map tieredValues = new HashMap<>(); - - public Upgrade(String id) { - this.id = id; - configAccessor = "Entity-Upgrades." + id + "-Tiers"; - } - - public static void init(Main plugin) { - Upgrade.plugin = plugin; - } - - public void setEntityType(EntityType entityType) { - this.entityType = entityType; - } - - public void setTierValue(int tier, double value) { - tieredValues.put(tier, value); - } - - public String getId() { - return id; - } - - public int getSlotX() { - return slotX; - } - - public int getSlotY() { - return slotY; - } - - public void setSlot(int x, int y) { - slotX = x; - slotY = y; - } - - public EntityType getApplicableFor() { - return entityType; - } - - public int getMaxTier() { - return maxTier; - } - - public void setMaxTier(int maxTier) { - this.maxTier = maxTier; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getDescription() { - return description; - } - - public void setDescription(List description) { - this.description = description; - } - - public String getMetadataAccessor() { - return metadataAccessor; - } - - public void setMetadataAccessor(String metadataAccessor) { - this.metadataAccessor = metadataAccessor; - } - - public double getValueForTier(int tier) { - return tieredValues.getOrDefault(tier, tieredValues.get(maxTier)); - } - - public int getCost(int tier) { - return plugin.getEntityUpgradesConfig().getInt(configAccessor + "." + tier); - } - - public ItemStack asItemStack(int currentTier) { - double valCurrent = tieredValues.get(currentTier); - int nextTier = currentTier + 1; - double valNext = tieredValues.getOrDefault(nextTier, valCurrent); - return new ItemBuilder(XMaterial.BLACK_STAINED_GLASS_PANE.parseItem()) - .name(getName()) - .lore(getDescription().stream().map(lore -> lore = new MessageBuilder(lore).build() - .replace("%cost%", Integer.toString(getCost(nextTier))) - .replace("%tier%", Integer.toString(nextTier)) - .replace("%from%", Double.toString(valCurrent)) - .replace("%to%", Double.toString(valNext))).collect(Collectors.toList())).build(); - } - - public enum EntityType { - BOTH, IRON_GOLEM, WOLF - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/upgrades/UpgradeBuilder.java b/src/main/java/plugily/projects/villagedefense/handlers/upgrade/upgrades/UpgradeBuilder.java deleted file mode 100644 index 8f2459d69..000000000 --- a/src/main/java/plugily/projects/villagedefense/handlers/upgrade/upgrades/UpgradeBuilder.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.handlers.upgrade.upgrades; - -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.villagedefense.Main; - -import java.util.Arrays; -import java.util.List; - -/** - * @author Plajer - *

- * Created at 18.06.2019 - */ -public class UpgradeBuilder { - - private static Main plugin; - private final Upgrade upgrade; - - public UpgradeBuilder(String id) { - upgrade = new Upgrade(id); - upgrade.setName(new MessageBuilder(plugin.getLanguageConfig().getString("Upgrade-Menu.Upgrades." + id + ".Name")).build()); - upgrade.setDescription(Arrays.asList(new MessageBuilder(plugin.getLanguageConfig().getString("Upgrade-Menu.Upgrades." + id + ".Description")).build().split(";"))); - } - - public static void init(Main plugin) { - UpgradeBuilder.plugin = plugin; - } - - //for other usages - public UpgradeBuilder name(String name) { - upgrade.setName(new MessageBuilder(name).build()); - return this; - } - - //for other usages - public UpgradeBuilder lore(List lore) { - upgrade.setDescription(lore); - return this; - } - - public UpgradeBuilder slot(int x, int y) { - upgrade.setSlot(x, y); - return this; - } - - public UpgradeBuilder entity(Upgrade.EntityType type) { - upgrade.setEntityType(type); - return this; - } - - public UpgradeBuilder maxTier(int maxTier) { - upgrade.setMaxTier(maxTier); - return this; - } - - public UpgradeBuilder metadata(String metaAccessor) { - upgrade.setMetadataAccessor(metaAccessor); - return this; - } - - public UpgradeBuilder tierValue(int tier, double val) { - upgrade.setTierValue(tier, val); - return this; - } - - public Upgrade build() { - return upgrade; - } - -} \ No newline at end of file diff --git a/src/main/java/plugily/projects/villagedefense/kits/BuilderKit.java b/src/main/java/plugily/projects/villagedefense/kits/BuilderKit.java new file mode 100644 index 000000000..f10e9a95c --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/BuilderKit.java @@ -0,0 +1,393 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.MaterialUtils; +import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; +import plugily.projects.villagedefense.utils.ProtocolUtils; +import plugily.projects.villagedefense.utils.Utils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Plajer + *

+ * Created at 11.08.2023 + */ +public class BuilderKit extends PremiumKit implements AbilitySource, Listener, ChatDisplayable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_BUILDER_"; + private final Map knockbackResistantArenas = new HashMap<>(); + + public BuilderKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Builder"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.SUPPORT, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0041"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Builder.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Builder.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_NAME", new Message("Kit.Content.Builder.Game-Item.Fence.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_DESCRIPTION", new Message("Kit.Content.Builder.Game-Item.Fence.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_NAME", new Message("Kit.Content.Builder.Game-Item.Door.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_DESCRIPTION", new Message("Kit.Content.Builder.Game-Item.Door.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_NAME", new Message("Kit.Content.Builder.Game-Item.Earthed.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_DESCRIPTION", new Message("Kit.Content.Builder.Game-Item.Earthed.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_ACTIVATE", new Message("Kit.Content.Builder.Game-Item.Earthed.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_ACTIVE_ACTION_BAR", new Message("Kit.Content.Builder.Game-Item.Earthed.Active-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_PROTECTED_BY_ACTION_BAR", new Message("Kit.Content.Builder.Game-Item.Earthed.Knock-Protected-By-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_NAME", new Message("Kit.Content.Builder.Game-Item.Blockage.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_DESCRIPTION", new Message("Kit.Content.Builder.Game-Item.Blockage.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_ACTIVATE", new Message("Kit.Content.Builder.Game-Item.Blockage.Activate", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.builder"); + } + + @Override + public void giveKitItems(Player player) { + ArmorHelper.setColouredArmor(Color.RED, player); + player.getInventory().addItem(WeaponHelper.getEnchanted(new ItemStack(Material.STONE_SWORD), new org.bukkit.enchantments.Enchantment[]{org.bukkit.enchantments.Enchantment.DURABILITY}, new int[]{10})); + + player.getInventory().setItem(2, new ItemBuilder(new ItemStack(XMaterial.OAK_FENCE.parseMaterial(), 3)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_DESCRIPTION")) + .build()); + player.getInventory().setItem(3, new ItemBuilder(new ItemStack(getMaterial(), 2)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_DESCRIPTION")) + .build()); + player.getInventory().setItem(4, new ItemBuilder(XMaterial.CLAY_BALL.parseMaterial()) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_DESCRIPTION")) + .build()); + player.getInventory().setItem(5, new ItemBuilder(XMaterial.IRON_BARS.parseMaterial()) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_DESCRIPTION")) + .build()); + player.getInventory().setItem(6, new ItemStack(Material.SADDLE)); + player.getInventory().setItem(8, new ItemStack(Material.COOKED_BEEF, 10)); + } + + @Override + public Material getMaterial() { + return Utils.getCachedDoor(null); + } + + @Override + public void reStock(Player player) { + Arena arena = (Arena) getPlugin().getUserManager().getUser(player).getArena(); + int fences = (int) Settings.PASSIVE_FENCE_COUNT.getForArenaState(arena); + player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.OAK_FENCE.parseMaterial(), fences)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_DESCRIPTION")) + .build()); + if (arena.getWave() % (int) Settings.PASSIVE_DOOR_MODULO.getForArenaState(arena) == 0) { + player.getInventory().addItem(new ItemBuilder(new ItemStack(getMaterial(), 1)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_DESCRIPTION")) + .build()); + } + if (arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_PASSIVE_POWER_INCREASED").asKey().send(player); + } else if (arena.getWave() == KitSpecifications.GameTimeState.LATE.getStartWave()) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_PASSIVE_POWER_INCREASED").asKey().send(player); + } + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if (!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), BuilderKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_NAME").asKey().build())) { + onEarthedCast(stack, user); + } else if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_NAME").asKey().build())) { + onBlockageCast(stack, user); + } else if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_FENCE_NAME").asKey().build())) { + onBarrierPlace(stack, user); + } + } + + private void onEarthedCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("builder_earthed")) { + return; + } + int cooldown = 20; + user.setCooldown("builder_earthed", cooldown); + int castTime = 10; + user.setCooldown("builder_earthed_running", castTime); + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_ACTIVATE").asKey().send(user.getPlayer()); + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_ACTIVE_ACTION_BAR"); + List buffMessages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_EARTHED_PROTECTED_BY_ACTION_BAR"); + Arena arena = (Arena) user.getArena(); + knockbackResistantArenas.put(arena, user.getPlayer()); + new BukkitRunnable() { + int tick = 0; + int messageIndex = 0; + int buffMessageIndex = 0; + + @Override + public void run() { + if (tick % 10 == 0) { + for (Player player : arena.getPlayersLeft()) { + VersionUtils.sendParticles("CRIT_MAGIC", null, player.getLocation(), 5, 0, 0, 0); + VersionUtils.sendActionBar(player, buffMessages.get(buffMessageIndex) + .replace("%player%", user.getPlayer().getName())); + } + VersionUtils.sendActionBar(user.getPlayer(), messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("builder_earthed_running")))); + messageIndex++; + buffMessageIndex++; + if (messageIndex > messages.size() - 1) { + messageIndex = 0; + } + if (buffMessageIndex > buffMessages.size() - 1) { + buffMessageIndex = 0; + } + } + if (tick >= 20 * castTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(user.getPlayer(), ""); + cancel(); + knockbackResistantArenas.remove(arena); + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private void onBlockageCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("builder_blockage")) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = (int) Settings.ABILITY_BLOCKAGE_COOLDOWN.getForArenaState((Arena) user.getArena()); + user.setCooldown("builder_blockage", cooldown); + int castTime = 15; + user.setCooldown("builder_blockage_running", cooldown); + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_BLOCKAGE_ACTIVATE").asKey().send(user.getPlayer()); + for (Creature enemy : ((Arena) user.getArena()).getEnemies()) { + enemy.setMetadata("VD_DOOR_BLOCK_BAN", new FixedMetadataValue(getPlugin(), true)); + enemy.setMetadata("VD_DOOR_BLOCK_BAN_SOURCE", new FixedMetadataValue(getPlugin(), user.getPlayer().getUniqueId())); + } + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { + for (Creature enemy : ((Arena) user.getArena()).getEnemies()) { + enemy.removeMetadata("VD_DOOR_BLOCK_BAN", getPlugin()); + enemy.removeMetadata("VD_DOOR_BLOCK_BAN_SOURCE", getPlugin()); + } + }, 20L * castTime); + } + + private void onBarrierPlace(ItemStack stack, User user) { + Player player = user.getPlayer(); + Block block = null; + for (Block blocks : player.getLastTwoTargetBlocks(null, 5)) { + if (blocks.getType() == Material.AIR) { + block = blocks; + } + } + if (block == null) { + XSound.ENTITY_VILLAGER_NO.play(player); + return; + } + getPlugin().getBukkitHelper().takeOneItem(player, stack); + + XSound.ENTITY_VILLAGER_YES.play(player); + ZombieBarrier zombieBarrier = new ZombieBarrier(); + zombieBarrier.setLocation(block.getLocation()); + + VersionUtils.sendParticles("FIREWORKS_SPARK", user.getArena().getPlayers(), block.getLocation(), 20); + int castTime = (int) Settings.PASSIVE_FENCE_CAST_TIME.getForArenaState((Arena) user.getArena()); + final Block finalBlock = block; + new BukkitRunnable() { + int time = castTime; + + @Override + public void run() { + time -= 1; + if (time <= 9) { + int stage = 9 - time; + ProtocolUtils.sendBlockBreakAnimation(finalBlock, stage); + } + + if (time <= 0) { + ProtocolUtils.removeBlockBreakAnimation(finalBlock); + finalBlock.setType(Material.AIR); + XSound.BLOCK_WOOD_BREAK.play(finalBlock.getLocation()); + Location loc = finalBlock.getLocation().clone(); + //centered location, more or less accurate + loc.add(loc.getX() > 0 ? 0.5 : -0.5, 0.0, loc.getZ() > 0 ? 0.5 : -0.5); + finalBlock.getWorld().spawnParticle(XParticle.getParticle("EXPLOSION_LARGE"), loc, 1); + cancel(); + } + } + }.runTaskTimer(getPlugin(), 20, 20); + block.setType(XMaterial.OAK_FENCE.parseMaterial()); + } + + @EventHandler + public void onEarthedDamage(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena((Player) event.getEntity()); + if (arena == null || !knockbackResistantArenas.containsKey(arena)) { + return; + } + arena.getAssistHandler().doRegisterBuffOnAlly(knockbackResistantArenas.get(arena), (Player) event.getEntity()); + Vector vector = new Vector(); + event.getEntity().setVelocity(vector); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> event.getEntity().setVelocity(vector), 1L); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onDoorPlace(BlockPlaceEvent event) { + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(event.getPlayer()); + if (arena == null) { + return; + } + if (getPlugin().getUserManager().getUser(event.getPlayer()).isSpectator()) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (!displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_DOOR_NAME").asKey().build())) { + event.setCancelled(true); + return; + } + List locations = arena.getMapRestorerManager().getGameDoorLocations(); + Location above = event.getBlock().getLocation().add(0, 1, 0); + if ((!locations.contains(event.getBlock().getLocation()) && !locations.contains(above)) + || !MaterialUtils.isDoor(stack.getType())) { + XSound.ENTITY_VILLAGER_NO.play(event.getPlayer()); + event.setCancelled(true); + return; + } + XSound.ENTITY_VILLAGER_YES.play(event.getPlayer()); + //to override world guard protection + event.setCancelled(false); + } + + private enum Settings { + PASSIVE_FENCE_COUNT(1, 2, 3), PASSIVE_FENCE_CAST_TIME(10, 12, 14), PASSIVE_DOOR_MODULO(5, 3, 2), + ABILITY_BLOCKAGE_COOLDOWN(0, 40, 30); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + + private static class ZombieBarrier { + private Location location; + private int seconds = 10; + + void setLocation(Location location) { + this.location = location; + } + + void decrementSeconds() { + seconds--; + } + + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ChatDisplayable.java b/src/main/java/plugily/projects/villagedefense/kits/ChatDisplayable.java new file mode 100644 index 000000000..046d3e02f --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ChatDisplayable.java @@ -0,0 +1,29 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +/** + * Interface for returning characters to display at chat to format it with custom textures with Look and Feel resource pack. + * Village Defense Gold improvement. + */ +public interface ChatDisplayable { + + String getChatPrefix(); + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/CleanerKit.java b/src/main/java/plugily/projects/villagedefense/kits/CleanerKit.java new file mode 100644 index 000000000..3adec2362 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/CleanerKit.java @@ -0,0 +1,356 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.arena.ArenaState; +import plugily.projects.minigamesbox.classic.arena.PluginArena; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.handlers.language.TitleBuilder; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +/** + * Created by Tom on 18/08/2014. + */ +public class CleanerKit extends PremiumKit implements Listener, AbilitySource, ChatDisplayable, ScoreboardModifiable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_CLEANER_"; + //this metadata must be given to every enemy killed by poplust to avoid recursive calls and stack overflow in the listener + private static final String KILL_METADATA = "VD_POPLUST_DEATH"; + private final Random random = new Random(); + + public CleanerKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Cleaner"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + schedulePopAwe(); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.DAMAGE_DEALER, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0042"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Cleaner.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Cleaner.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_NAME", new Message("Kit.Content.Cleaner.Game-Item.Cleansing-Stick.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_DESCRIPTION", new Message("Kit.Content.Cleaner.Game-Item.Cleansing-Stick.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_ACTIVATE", new Message("Kit.Content.Cleaner.Game-Item.Cleansing-Stick.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_NAME", new Message("Kit.Content.Cleaner.Game-Item.Poplust.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_DESCRIPTION", new Message("Kit.Content.Cleaner.Game-Item.Poplust.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_ACTIVATE", new Message("Kit.Content.Cleaner.Game-Item.Poplust.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_ACTIVE_ACTION_BAR", new Message("Kit.Content.Cleaner.Game-Item.Poplust.Active-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_ACTIVE_TITLE", new Message("Kit.Content.Cleaner.Game-Item.Poplust.Active-Title", "")); + } + + private void schedulePopAwe() { + //passive only works for alive players not dead ones + Bukkit.getScheduler().runTaskTimer(getPlugin(), () -> { + for(PluginArena pluginArena : getPlugin().getArenaRegistry().getArenas()) { + Arena arena = (Arena) pluginArena; + if(arena.getArenaState() != ArenaState.IN_GAME || arena.getEnemies().isEmpty()) { + continue; + } + for(Player player : arena.getPlayersLeft()) { + if(!(getPlugin().getUserManager().getUser(player).getKit() instanceof CleanerKit)) { + continue; + } + executeRandomPops(arena, player, (int) Settings.PASSIVE_POP_COUNT.getForArenaState(arena)); + } + } + }, 20 * 5L, 20 * 5L); + } + + private void executeRandomPops(Arena arena, Player player, int amount) { + for(int i = 0; i < amount; i++) { + Creature enemy = arena.getEnemies().get(random.nextInt(arena.getEnemies().size())); + if (enemy.hasMetadata("VD_UNPOPPABLE")) { + KitHelper.maxHealthPercentDamage(enemy, player, 15.0); + VersionUtils.sendParticles("LAVA", arena.getPlayers(), enemy.getLocation(), 20); + continue; + } + if(KitHelper.executeEnemy(enemy, player)) { + VersionUtils.sendParticles("LAVA", arena.getPlayers(), enemy.getLocation(), 20); + } + } + player.playSound(player, Sound.BLOCK_LAVA_POP, 1, 1); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.cleaner"); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "cleaner_cleansing", "Cleansing Wand", wave, KitSpecifications.GameTimeState.EARLY), + ScoreboardModifiable.renderAbilityCooldown(user, "cleaner_poplust", "Poplust", wave, KitSpecifications.GameTimeState.MID), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + @Override + public void giveKitItems(Player player) { + ArmorHelper.setColouredArmor(Color.YELLOW, player); + player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); + + player.getInventory().setItem(3, new ItemBuilder(new ItemStack(XMaterial.BLAZE_ROD.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_DESCRIPTION")) + .build()); + player.getInventory().setItem(4, new ItemBuilder(new ItemStack(XMaterial.SUNFLOWER.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_DESCRIPTION")) + .build()); + player.getInventory().setItem(5, new ItemStack(Material.SADDLE)); + player.getInventory().setItem(8, new ItemStack(Material.COOKED_BEEF, 10)); + } + + @Override + public Material getMaterial() { + return Material.BLAZE_POWDER; + } + + @Override + public void reStock(Player player) { + Arena arena = (Arena) getPlugin().getUserManager().getUser(player).getArena(); + if(arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_PASSIVE_POWER_INCREASED").asKey().send(player); + } else if(arena.getWave() == KitSpecifications.GameTimeState.LATE.getStartWave()) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_PASSIVE_POWER_INCREASED").asKey().send(player); + } + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if(!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), CleanerKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if(displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_NAME").asKey().build())) { + onCleansingCast(stack, user); + } else if(displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_NAME").asKey().build())) { + onPoplustPreCast(stack, user); + } + } + + private void onCleansingCast(ItemStack stack, User user) { + if(!user.checkCanCastCooldownAndMessage("cleaner_cleansing")) { + return; + } + int cooldown = getCleansingCooldown((Arena) user.getArena()); + user.setCooldown("cleaner_cleansing", cooldown); + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), cooldown * 20); + + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_CLEANSING_STICK_ACTIVATE").asKey().send(user.getPlayer()); + int popsPerCycle = 5; + int splitAmount = (int) Settings.CLEANSING_POP_COUNT.getForArenaState((Arena) user.getArena()) / popsPerCycle; + for (int i = 1; i < splitAmount + 1; i++) { + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { + XSound.BLOCK_LAVA_POP.play(user.getPlayer()); + executeRandomPops((Arena) user.getArena(), user.getPlayer(), popsPerCycle); + }, 10L * splitAmount * i); + } + } + + private int getCleansingCooldown(Arena arena) { + switch(KitSpecifications.getTimeState(arena)) { + case LATE: + return getKitsConfig().getInt("Kit-Cooldown.Cleaner.Cleansing-Wand.III", 35); + case MID: + return getKitsConfig().getInt("Kit-Cooldown.Cleaner.Cleansing-Wand.II", 40); + case EARLY: + default: + return getKitsConfig().getInt("Kit-Cooldown.Cleaner.Cleansing-Wand.I", 45); + } + } + + private void onPoplustPreCast(ItemStack stack, User user) { + if(!user.checkCanCastCooldownAndMessage("cleaner_poplust")) { + return; + } + if(KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + onPoplustCast(stack, user); + } + + private void onPoplustCast(ItemStack stack, User user) { + Arena arena = (Arena) user.getArena(); + int cooldown = getKitsConfig().getInt("Kit-Cooldown.Cleaner.Poplust", 75); + user.setCooldown("cleaner_poplust", cooldown); + final int castTime = (int) Settings.POPLUST_CAST_TIME.getForArenaState(arena); + user.setCooldown("cleaner_poplust_running", castTime); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_ACTIVATE").asKey().send(user.getPlayer()); + + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_ACTIVE_ACTION_BAR"); + Player player = user.getPlayer(); + player.setMetadata("VD_CLEANER_POPLUST", new FixedMetadataValue(getPlugin(), true)); + new BukkitRunnable() { + int tick = 0; + int messageIndex = 0; + + @Override + public void run() { + if(tick % 10 == 0) { + VersionUtils.sendActionBar(player, messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("cleaner_poplust_running")))); + new TitleBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_POPLUST_ACTIVE_TITLE").asKey().send(player); + messageIndex++; + if(messageIndex > messages.size() - 1) { + messageIndex = 0; + } + } + if (tick >= 20 * castTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + cancel(); + player.removeMetadata("VD_CLEANER_POPLUST", getPlugin()); + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + } + + @EventHandler + public void onPoplustDamage(EntityDamageByEntityEvent event) { + if(!(event.getDamager() instanceof Player)) { + return; + } + Player damager = (Player) event.getDamager(); + if(getPlugin().getArenaRegistry().getArena(damager) == null) { + return; + } + User user = getPlugin().getUserManager().getUser(damager); + if (!damager.hasMetadata("VD_CLEANER_POPLUST") || user.isSpectator() || !NewCreatureUtils.isEnemy(event.getEntity()) + || event.getEntity().hasMetadata(KILL_METADATA)) { + return; + } + LivingEntity entity = (LivingEntity) event.getEntity(); + Arena arena = ((Arena) user.getArena()); + arena.getAssistHandler().doRegisterBuffOnAlly(damager, user.getPlayer()); + if (entity.hasMetadata("VD_UNPOPPABLE")) { + KitHelper.maxHealthPercentDamage(entity, user.getPlayer(), 15.0); + XSound.BLOCK_LAVA_POP.play(user.getPlayer()); + VersionUtils.sendParticles("LAVA", user.getArena().getPlayers(), entity.getLocation(), 15); + return; + } + if (KitHelper.canExecuteEnemy(entity, user.getPlayer())) { + entity.setMetadata(KILL_METADATA, new FixedMetadataValue(getPlugin(), true)); + KitHelper.executeEnemy(entity, user.getPlayer()); + XSound.BLOCK_LAVA_POP.play(user.getPlayer()); + VersionUtils.sendParticles("LAVA", user.getArena().getPlayers(), entity.getLocation(), 15); + } + } + + private enum Settings { + PASSIVE_POP_COUNT(1, 2, 3), CLEANSING_POP_COUNT(8, 11, 14), POPLUST_CAST_TIME(0, 7, 11); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch(KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/CrusaderKit.java b/src/main/java/plugily/projects/villagedefense/kits/CrusaderKit.java new file mode 100644 index 000000000..c942e8c39 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/CrusaderKit.java @@ -0,0 +1,527 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.EnumWrappers; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.WorldBorder; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.actionbar.ActionBar; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.ParticleDisplay; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.ActionBarPriority; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * @author Plajer + *

+ * Created at 30.08.2023 + */ +public class CrusaderKit extends PremiumKit implements AbilitySource, Listener, ChatDisplayable, ScoreboardModifiable { + + private static final String COURAGE_METADATA = "VD_CRUSADER_COURAGE"; + private static final String UNKILLABLE_METADATA = "VD_CRUSADER_UNKILLABLE"; + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_CRUSADER_"; + + public CrusaderKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Crusader"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.TANK, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0043"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Crusader.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Crusader.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_NAME", new Message("Kit.Content.Crusader.Game-Item.Courageous.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_DESCRIPTION", new Message("Kit.Content.Crusader.Game-Item.Courageous.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_ACTIVATE", new Message("Kit.Content.Crusader.Game-Item.Courageous.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_AURA_ACTION_BAR", new Message("Kit.Content.Crusader.Game-Item.Crusader.Aura-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_STACKS", new Message("Kit.Content.Crusader.Game-Item.Courageous.Stacks.Base", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_STACKS_MAX", new Message("Kit.Content.Crusader.Game-Item.Courageous.Stacks.Max", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_NAME", new Message("Kit.Content.Crusader.Game-Item.Glory-To-The-King.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_DESCRIPTION", new Message("Kit.Content.Crusader.Game-Item.Glory-To-The-King.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_ACTIVATE", new Message("Kit.Content.Crusader.Game-Item.Glory-To-The-King.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_ACTIVE_ACTION_BAR", new Message("Kit.Content.Crusader.Game-Item.Glory-To-The-King.Active-Action-Bar", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return player.hasPermission("villagedefense.kit.crusader") || getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "crusader_courageous", "Courageous", wave, KitSpecifications.GameTimeState.EARLY), + ScoreboardModifiable.renderAbilityCooldown(user, "crusader_glorytotheking", "Glory to the King", wave, KitSpecifications.GameTimeState.MID), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + @Override + public void giveKitItems(Player player) { + ArmorHelper.setArmor(player, ArmorHelper.ArmorType.LEATHER); + ItemStack itemStack = XMaterial.STONE_SWORD.parseItem(); + ItemMeta meta = itemStack.getItemMeta(); + meta.setUnbreakable(true); + itemStack.setItemMeta(meta); + player.getInventory().addItem(itemStack); + + player.getInventory().setItem(3, new ItemBuilder(new ItemStack(XMaterial.GOAT_HORN.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_DESCRIPTION")) + .build()); + + player.getInventory().setItem(4, new ItemBuilder(new ItemStack(XMaterial.NETHER_STAR.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_DESCRIPTION")) + .build()); + + player.getInventory().setItem(5, new ItemStack(Material.SADDLE)); + player.getInventory().setItem(8, new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 6)); + User user = getPlugin().getUserManager().getUser(player); + doDisplayCourageBar(user); + } + + @Override + public Material getMaterial() { + return Material.MAGMA_CREAM; + } + + @Override + public void reStock(Player player) { + User user = getPlugin().getUserManager().getUser(player); + doDisplayCourageBar(user); + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); + if (arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_PASSIVE_POWER_INCREASED").asKey().send(player); + } else if (arena.getWave() == KitSpecifications.GameTimeState.LATE.getStartWave()) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_PASSIVE_POWER_INCREASED").asKey().send(player); + } + } + + private void doDisplayCourageBar(User user) { + getPlugin().getActionBarManager().clearActionBarsFromPlayer(user.getPlayer()); + new BukkitRunnable() { + @Override + public void run() { + int stacks = 0; + if (user.getPlayer().hasMetadata(COURAGE_METADATA)) { + stacks = user.getPlayer().getMetadata(COURAGE_METADATA).get(0).asInt(); + } + MessageBuilder message; + if (stacks >= 75) { + message = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_STACKS_MAX").asKey(); + } else { + message = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_STACKS").asKey().integer(stacks); + } + getPlugin().getActionBarManager().addActionBar(user.getPlayer(), new ActionBar(message, ActionBar.ActionBarType.DISPLAY, ActionBarPriority.LOW_PRIORITY)); + if (!getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + cancel(); + getPlugin().getActionBarManager().clearActionBarsFromPlayer(user.getPlayer()); + } + } + }.runTaskTimer(getPlugin(), 0, 5); + } + + @EventHandler + public void onStunAura(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player player) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + User user = getPlugin().getUserManager().getUser(player); + if (player.hasMetadata("VD_CRUSADER_STUN_AURA")) { + NewCreatureUtils.doStunEnemy((Creature) event.getEntity(), (int) Settings.PASSIVE_STUN_DURATION.getForArenaState((Arena) user.getArena())); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onUnkillableDamage(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + User user = getPlugin().getUserManager().getUser((Player) event.getEntity()); + if (user == null || user.getArena() == null || user.isSpectator() || !(user.getKit() instanceof CrusaderKit)) { + return; + } + if (user.getPlayer().hasMetadata(UNKILLABLE_METADATA) && user.getPlayer().getHealth() - event.getDamage() <= 0) { + event.setDamage(0); + user.getPlayer().setHealth(1); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onBlastDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof TNTPrimed)) { + return; + } + TNTPrimed primed = (TNTPrimed) event.getDamager(); + if (!primed.hasMetadata("VD_PRIMED_TNT")) { + return; + } + if (!(event.getEntity() instanceof Player)) { + return; + } + User user = getPlugin().getUserManager().getUser((Player) event.getEntity()); + if (user == null || user.getArena() == null || !(user.getKit() instanceof CrusaderKit)) { + return; + } + KitSpecifications.GameTimeState state = KitSpecifications.getTimeState((Arena) user.getArena()); + if (state == KitSpecifications.GameTimeState.EARLY) { + return; + } + event.setDamage(0); + } + + @EventHandler + public void onIronWillCast(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + Player damager = (Player) event.getDamager(); + User user = getPlugin().getUserManager().getUser(damager); + if (user.isSpectator() || !(user.getKit() instanceof CrusaderKit)) { + return; + } + if (((Arena) user.getArena()).getSpecialEntities().contains(event.getEntity())) { + return; + } + String metadata = "VD_CRUSADER_HITS"; + if (damager.hasMetadata(metadata)) { + int totalHits = damager.getMetadata(metadata).get(0).asInt(); + totalHits++; + if (totalHits == 3) { + damager.playSound(damager, Sound.BLOCK_ANVIL_PLACE, 0.2f, 1.5f); + Creature enemy = ((Creature) event.getEntity()); + NewCreatureUtils.doStunEnemy(enemy, (int) Settings.PASSIVE_STUN_DURATION.getForArenaState((Arena) user.getArena())); + damager.removeMetadata(metadata, getPlugin()); + doIncreaseCourage(damager, (int) Settings.PASSIVE_STACKS_AMOUNT.getForArenaState((Arena) user.getArena())); + return; + } + damager.setMetadata(metadata, new FixedMetadataValue(getPlugin(), totalHits)); + } else { + damager.setMetadata(metadata, new FixedMetadataValue(getPlugin(), 1)); + } + } + + private void doIncreaseCourage(Player player, int amount) { + if (player.hasMetadata(COURAGE_METADATA)) { + int stacks = player.getMetadata(COURAGE_METADATA).get(0).asInt(); + stacks += amount; + stacks = Math.min(stacks, 75); + player.setMetadata(COURAGE_METADATA, new FixedMetadataValue(getPlugin(), stacks)); + } else { + player.setMetadata(COURAGE_METADATA, new FixedMetadataValue(getPlugin(), amount)); + } + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if (!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), CrusaderKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_NAME").asKey().build())) { + event.setCancelled(true); + onCourageousCast(stack, user); + } else if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_NAME").asKey().build())) { + event.setCancelled(true); + onGloryToTheKingCast(stack, user); + } + } + + private void onCourageousCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("crusader_courageous")) { + return; + } + int cooldown = 5; + user.setCooldown("crusader_courageous", cooldown); + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), cooldown * 20); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_ACTIVATE").asKey().send(user.getPlayer()); + + int stacks = 0; + Player player = user.getPlayer(); + if (player.hasMetadata(COURAGE_METADATA)) { + stacks = player.getMetadata(COURAGE_METADATA).get(0).asInt(); + } + player.addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, 20 * 5, 1)); + if (stacks >= 10) { + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 20 * 5, 1)); + } + if (stacks >= 30) { + KitHelper.healPlayer(player, VersionUtils.getMaxHealth(player) * 0.5); + } else if (stacks >= 20) { + KitHelper.healPlayer(player, VersionUtils.getMaxHealth(player) * 0.25); + } + if (stacks >= 40) { + player.addPotionEffect(new PotionEffect(PotionEffectType.REGENERATION, 20 * 8, 0)); + } + if (stacks >= 50) { + doPrepareBurnAura(user); + } + //todo stun aura as well as burn aura action bar + if (stacks >= 75) { + player.setMetadata("VD_CRUSADER_STUN_AURA", new FixedMetadataValue(getPlugin(), true)); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> player.removeMetadata("VD_CRUSADER_STUN_AURA", getPlugin()), 20 * 8); + } + playRandomHorn(player); + player.removeMetadata(COURAGE_METADATA, getPlugin()); + } + + private void playRandomHorn(Player player) { + switch (ThreadLocalRandom.current().nextInt(0, 7)) { + case 0 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_0, .75f, 1); + case 1 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_1, .75f, 1); + case 2 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_2, .75f, 1.25f); + case 3 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_3, .75f, 1.5f); + case 4 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_4, .75f, 1.25f); + case 5 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_5, .75f, 1.75f); + case 6 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_6, .75f, 1.5f); + case 7 -> player.playSound(player, Sound.ITEM_GOAT_HORN_SOUND_7, .75f, 1.5f); + } + } + + private void doPrepareBurnAura(User user) { + int castTime = 8; + user.setCooldown("crusader_burn_aura", 8); + Player player = user.getPlayer(); + getPlugin().getActionBarManager().addActionBar(player, new ActionBar(LANGUAGE_ACCESSOR + "GAME_ITEM_COURAGEOUS_AURA_ACTION_BAR", castTime)); + new BukkitRunnable() { + int tick = 0; + + @Override + public void run() { + //apply effects only once per second, particles every tick + XParticle.circle(3.5, 28, ParticleDisplay.simple(player.getLocation().add(0, 0.5, 0), XParticle.getParticle("SMOKE_NORMAL"))); + if (tick % 20 == 0) { + for (Entity entity : player.getNearbyEntities(3.5, 3.5, 3.5)) { + if (!NewCreatureUtils.isEnemy(entity) || entity.equals(player)) { + continue; + } + entity.setFireTicks(25); + } + } + if (tick >= 20 * castTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + cancel(); + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private void onGloryToTheKingCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("crusader_glorytotheking")) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + Player player = user.getPlayer(); + player.setMetadata(UNKILLABLE_METADATA, new FixedMetadataValue(getPlugin(), true)); + int castTime = 10; + int cooldown = getUltimateCooldown((Arena) user.getArena()); + user.setCooldown("crusader_glorytotheking", cooldown); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> player.removeMetadata(UNKILLABLE_METADATA, getPlugin()), 20L * castTime); + KitHelper.scheduleAbilityCooldown(stack, player, castTime, cooldown); + XSound.BLOCK_PORTAL_TRIGGER.play(player, 1f, 0f); + player.removeMetadata(COURAGE_METADATA, getPlugin()); + user.setCooldown("crusader_glorytotheking_running", castTime); + + getPlugin().getActionBarManager().addActionBar(player, new ActionBar(LANGUAGE_ACCESSOR + "GAME_ITEM_GLORY_TO_THE_KING_ACTIVE_ACTION_BAR", castTime)); + setWorldBorder(player, true); + new BukkitRunnable() { + int tick = 0; + boolean border = true; + + @Override + public void run() { + if (tick >= 20 * (castTime - 2) && tick % 5 == 0) { + border = !border; + setWorldBorder(player, border); + } + if (tick >= 20 * castTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + cancel(); + setWorldBorder(player, false); + if (getPlugin().getArenaRegistry().isInArena(user.getPlayer()) && !user.isSpectator()) { + XSound.ITEM_SHIELD_BREAK.play(player); + KitHelper.healPlayer(player, VersionUtils.getMaxHealth(player) * 0.5); + } + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private void setWorldBorder(Player player, boolean warn) { + if (ServerVersion.Version.isCurrentEqualOrLower(ServerVersion.Version.v1_16_R3)) { + doLegacyBorder(player, warn); + } else { + doNewBorder(player, warn); + } + } + + @Deprecated + //testme + private void doLegacyBorder(Player player, boolean warn) { + PacketContainer container = new PacketContainer(PacketType.Play.Server.WORLD_BORDER); + WorldBorder border = player.getWorld().getWorldBorder(); + container.getWorldBorderActions().write(0, EnumWrappers.WorldBorderAction.INITIALIZE); + container.getDoubles().write(0, player.getLocation().getX()); + container.getDoubles().write(1, player.getLocation().getZ()); + container.getDoubles().write(2, border.getSize()); + container.getDoubles().write(3, border.getSize()); + container.getIntegers().write(0, 29999984); + container.getIntegers().write(1, 0); + container.getIntegers().write(2, (int) (warn ? border.getSize() : border.getWarningDistance())); + container.getLongs().write(0, 0L); + ProtocolLibrary.getProtocolManager().sendServerPacket(player, container); + } + + private void doNewBorder(Player player, boolean warn) { + PacketContainer container = new PacketContainer(PacketType.Play.Server.INITIALIZE_BORDER); + WorldBorder border = player.getWorld().getWorldBorder(); + container.getDoubles().write(0, player.getLocation().getX()); + container.getDoubles().write(1, player.getLocation().getZ()); + container.getDoubles().write(2, warn ? 0 : border.getSize()); + container.getDoubles().write(3, warn ? 0 : border.getSize()); + container.getIntegers().write(0, warn ? 1 : 29999984); + container.getIntegers().write(1, 0); + container.getIntegers().write(2, warn ? 5 : border.getWarningDistance()); + container.getLongs().write(0, 0L); + ProtocolLibrary.getProtocolManager().sendServerPacket(player, container); + } + + private int getUltimateCooldown(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return 25; + case MID: + return 40; + case EARLY: + default: + return 0; + } + } + + private enum Settings { + PASSIVE_STUN_DURATION(2, 3, 4), PASSIVE_STACKS_AMOUNT(1, 2, 3), ULTIMATE_HEAL_POWER(0, 4, 5); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/KitsMenu.java b/src/main/java/plugily/projects/villagedefense/kits/KitsMenu.java new file mode 100644 index 000000000..db1fffdc3 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/KitsMenu.java @@ -0,0 +1,144 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import plugily.projects.minigamesbox.classic.api.event.player.PlugilyPlayerChooseKitEvent; +import plugily.projects.minigamesbox.classic.arena.PluginArena; +import plugily.projects.minigamesbox.classic.handlers.items.SpecialItem; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.kits.basekits.Kit; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.inventory.common.item.SimpleClickableItem; +import plugily.projects.minigamesbox.inventory.normal.NormalFastInv; +import plugily.projects.villagedefense.Main; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class KitsMenu implements Listener { + + private final Main plugin; + private final Map> registeredKits = new HashMap<>(); + + public KitsMenu(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + public void registerKit(KitCategory category, Kit kit) { + registeredKits.computeIfAbsent(category, v -> new ArrayList<>()).add(kit); + } + + public void openMenu(Player player) { + NormalFastInv gui = new NormalFastInv(44, new MessageBuilder("KIT_KIT_MENU_TITLE").asKey().build()); + gui.setBorderItem(new SimpleClickableItem(new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE).name(" ").build(), e -> e.setCancelled(true))); + for (Map.Entry> entry : registeredKits.entrySet()) { + int startSlot = entry.getKey().getStartSlot(); + for (int i = 0; i < 6; i++) { + gui.setItem(startSlot + i, new ItemBuilder(Material.GRAY_STAINED_GLASS_PANE).name(" ").build(), e -> e.setCancelled(true)); + } + gui.setItem(startSlot - 1, + new ItemBuilder(entry.getKey().getIcon()) + .name(plugin.getLanguageManager().getLanguageMessage(entry.getKey().getLanguageAccessor() + ".Name")) + .lore(plugin.getLanguageManager().getLanguageList(entry.getKey().getLanguageAccessor() + ".Lore")) + .build(), + e -> e.setCancelled(true) + ); + for (Kit kit : entry.getValue()) { + gui.setItem(startSlot, new SimpleClickableItem(new ItemBuilder(kit.getItemStack()).flags(ItemFlag.HIDE_ATTRIBUTES).build(), event -> { + event.setCancelled(true); + if (!(event.isLeftClick() || event.isRightClick()) || !(event.getWhoClicked() instanceof Player) || !ItemUtils.isItemStackNamed(event.getCurrentItem())) { + return; + } + PluginArena arena = plugin.getArenaRegistry().getArena(player); + if (arena == null) { + return; + } + PlugilyPlayerChooseKitEvent chooseKitEvent = new PlugilyPlayerChooseKitEvent(player, kit, arena); + Bukkit.getPluginManager().callEvent(chooseKitEvent); + if (chooseKitEvent.isCancelled()) { + return; + } + plugin.getUserManager().getUser(player).setKit(kit); + new MessageBuilder("KIT_CHOOSE").asKey().value(kit.getName()).player(player).sendPlayer(); + })); + startSlot++; + } + } + gui.refresh(); + gui.open(player); + } + + //copy from core + @EventHandler + public void onSpecialItem(PlugilyPlayerInteractEvent event) { + if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.PHYSICAL) { + return; + } + Player player = event.getPlayer(); + + ItemStack itemStack = VersionUtils.getItemInHand(player); + if (!ItemUtils.isItemStackNamed(itemStack)) { + return; + } + + SpecialItem relatedSpecialItem = plugin.getSpecialItemManager().getRelatedSpecialItem(itemStack); + if (relatedSpecialItem == plugin.getSpecialItemManager().getInvalidItem()) { + return; + } + event.setCancelled(true); + if (relatedSpecialItem.getPermission() != null && !relatedSpecialItem.getPermission().isEmpty()) { + if (!plugin.getBukkitHelper().hasPermission(player, relatedSpecialItem.getPermission())) { + return; + } + } + + if (plugin.getSpecialItemManager().getSpecialItem("KIT_SELECTOR_MENU").getPath().equals(relatedSpecialItem.getPath())) { + openMenu(player); + } + } + + @AllArgsConstructor + @Getter + public enum KitCategory { + DAMAGE_DEALER(Material.CHERRY_SIGN, 11, "Gold-Messages.Kit-Selector.Damage-Section"), + SUPPORT(Material.BAMBOO_SIGN, 20, "Gold-Messages.Kit-Selector.Support-Section"), + TANK(Material.WARPED_SIGN, 29, "Gold-Messages.Kit-Selector.Tank-Section"); + + private final Material icon; + private final int startSlot; + private final String languageAccessor; + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/free/KnightKit.java b/src/main/java/plugily/projects/villagedefense/kits/KnightKit.java similarity index 62% rename from src/main/java/plugily/projects/villagedefense/kits/free/KnightKit.java rename to src/main/java/plugily/projects/villagedefense/kits/KnightKit.java index ada30f677..1c6d63a7e 100644 --- a/src/main/java/plugily/projects/villagedefense/kits/free/KnightKit.java +++ b/src/main/java/plugily/projects/villagedefense/kits/KnightKit.java @@ -1,22 +1,22 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ -package plugily.projects.villagedefense.kits.free; +package plugily.projects.villagedefense.kits; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -32,7 +32,7 @@ /** * Created by Tom on 14/08/2014. */ -public class KnightKit extends FreeKit { +public class KnightKit extends FreeKit implements ChatDisplayable { public KnightKit() { setName(new MessageBuilder("KIT_CONTENT_KNIGHT_NAME").asKey().build()); @@ -43,6 +43,11 @@ public KnightKit() { getPlugin().getKitRegistry().setDefaultKit(this); } + @Override + public String getChatPrefix() { + return ""; + } + @Override public boolean isUnlockedByPlayer(Player player) { return true; diff --git a/src/main/java/plugily/projects/villagedefense/kits/MedicKit.java b/src/main/java/plugily/projects/villagedefense/kits/MedicKit.java new file mode 100644 index 000000000..c186530be --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/MedicKit.java @@ -0,0 +1,377 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import org.bukkit.Color; +import org.bukkit.EntityEffect; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Golem; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.ParticleDisplay; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.ArenaUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by Tom on 1/12/2015. + */ +public class MedicKit extends PremiumKit implements Listener, AbilitySource, ChatDisplayable, ScoreboardModifiable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_MEDIC_"; + + public MedicKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Medic"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.SUPPORT, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0044"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Medic.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Medic.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_NAME", new Message("Kit.Content.Medic.Game-Item.Aura.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_DESCRIPTION", new Message("Kit.Content.Medic.Game-Item.Aura.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_ACTIVE_ACTION_BAR", new Message("Kit.Content.Medic.Game-Item.Aura.Active-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_HEALED_BY_ACTION_BAR", new Message("Kit.Content.Medic.Game-Item.Aura.Healed-By-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_NAME", new Message("Kit.Content.Medic.Game-Item.Homecoming.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_DESCRIPTION", new Message("Kit.Content.Medic.Game-Item.Homecoming.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_ACTIVATE", new Message("Kit.Content.Medic.Game-Item.Homecoming.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_RESPAWNED_BY_TITLE", new Message("Kit.Content.Medic.Game-Item.Homecoming.Respawned-By-Title", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_RESPAWNED_BY_SUBTITLE", new Message("Kit.Content.Medic.Game-Item.Homecoming.Respawned-By-Subtitle", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.medic"); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "medic_aura", "Healing Aura", wave, KitSpecifications.GameTimeState.MID), + ScoreboardModifiable.renderAbilityCooldown(user, "medic_homecoming", "Homecoming", wave, KitSpecifications.GameTimeState.MID), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + @Override + public void giveKitItems(Player player) { + ItemStack itemStack = XMaterial.STONE_SWORD.parseItem(); + ItemMeta meta = itemStack.getItemMeta(); + meta.setUnbreakable(true); + itemStack.setItemMeta(meta); + player.getInventory().addItem(itemStack); + + ArmorHelper.setColouredArmor(Color.WHITE, player); + player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); + player.getInventory().addItem(VersionUtils.getPotion(PotionType.REGEN, 1, true)); + + player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.GHAST_TEAR.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_DESCRIPTION")) + .build()); + player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.GOLD_NUGGET.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_DESCRIPTION")) + .build()); + } + + @Override + public Material getMaterial() { + return Material.GHAST_TEAR; + } + + @Override + public void reStock(Player player) { + User user = getPlugin().getUserManager().getUser(player); + Arena arena = (Arena) user.getArena(); + int heal = (int) Settings.PASSIVE_HEAL_POWER.getForArenaState(arena); + for(Player arenaPlayer : arena.getPlayersLeft()) { + double maxHealth = VersionUtils.getMaxHealth(arenaPlayer); + //todo useless?? all players are healed before next wave + if(arenaPlayer.getHealth() + heal > maxHealth) { + arenaPlayer.setHealth(maxHealth); + arenaPlayer.setFoodLevel(20); + } else { + arenaPlayer.setHealth(arenaPlayer.getHealth() + heal); + } + arena.getAssistHandler().doRegisterBuffOnAlly(player, arenaPlayer); + } + for(Villager villager : arena.getVillagers()) { + villager.setHealth(Math.min(villager.getHealth() + heal, VersionUtils.getMaxHealth(villager))); + villager.setCustomName(NewCreatureUtils.getHealthNameTag(villager)); + } + if(arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_NAME").asKey().build()).send(player); + } else if(arena.getWave() == KitSpecifications.GameTimeState.LATE.getStartWave()) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_NAME").asKey().build()).send(player); + } + } + + @EventHandler + public void onCreatureHit(EntityDamageByEntityEvent e) { + if(!(e.getEntity() instanceof Creature) || !(e.getDamager() instanceof Player)) { + return; + } + User user = getPlugin().getUserManager().getUser((Player) e.getDamager()); + if(!(user.getKit() instanceof MedicKit) || Math.random() > 0.1) { + return; + } + healNearbyPlayers(user.getPlayer(), e.getDamager()); + } + + private void healNearbyPlayers(Player source, Entity en) { + for(Entity entity : en.getNearbyEntities(5, 5, 5)) { + if(!(entity instanceof Player)) { + continue; + } + KitHelper.healPlayer(source, (Player) entity, 1.0); + } + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if(!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), MedicKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if(displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_NAME").asKey().build())) { + onHomecomingPreCast(stack, user); + } else if(displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_NAME").asKey().build())) { + onAuraPreCast(stack, user); + } + } + + private void onHomecomingPreCast(ItemStack stack, User user) { + if(!user.checkCanCastCooldownAndMessage("medic_homecoming")) { + return; + } + if(KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = getKitsConfig().getInt("Kit-Cooldown.Medic.Homecoming", 60); + user.setCooldown("medic_homecoming", cooldown); + + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), cooldown * 20); + onHomecomingCast(user); + } + + private void onHomecomingCast(User user) { + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_ACTIVATE").asKey().send(user.getPlayer()); + List left = user.getArena().getPlayersLeft(); + user.getPlayer().playEffect(EntityEffect.valueOf("TOTEM_RESURRECT")); + + String title = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_RESPAWNED_BY_TITLE").asKey().player(user.getPlayer()).build(); + String subTitle = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_HOMECOMING_RESPAWNED_BY_SUBTITLE").asKey().player(user.getPlayer()).build(); + for(Player arenaPlayer : user.getArena().getPlayers()) { + if(left.contains(arenaPlayer)) { + continue; + } + VersionUtils.sendTitles(arenaPlayer, title, subTitle, 5, 40, 5); + arenaPlayer.playEffect(EntityEffect.valueOf("TOTEM_RESURRECT")); + int amplifier = (int) Settings.HEAL_AURA_POWER.getForArenaState((Arena) user.getArena()); + arenaPlayer.addPotionEffect(new PotionEffect(PotionEffectType.HEALTH_BOOST, 30 * 20, amplifier)); + arenaPlayer.addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 30 * 20, amplifier)); + ((Arena) user.getArena()).getAssistHandler().doRegisterBuffOnAlly(user.getPlayer(), arenaPlayer); + } + ArenaUtils.bringDeathPlayersBack((Arena) user.getArena()); + } + + private void onAuraPreCast(ItemStack stack, User user) { + if(!user.checkCanCastCooldownAndMessage("medic_aura")) { + return; + } + if(KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = getAuraCooldown((Arena) user.getArena()); + user.setCooldown("medic_aura", cooldown); + int castTime = 10; + user.setCooldown("medic_aura_running", castTime); + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + onAuraCast(user, castTime); + } + + private int getAuraCooldown(Arena arena) { + switch(KitSpecifications.getTimeState(arena)) { + case LATE: + return getKitsConfig().getInt("Kit-Cooldown.Medic.Aura.II", 15); + case MID: + return getKitsConfig().getInt("Kit-Cooldown.Medic.Aura.I", 30); + case EARLY: + default: + return 0; + } + } + + public void onAuraCast(User user, int castTime) { + Player player = user.getPlayer(); + player.playSound(player, Sound.ENTITY_PLAYER_LEVELUP, 1, 1.5f); + + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_ACTIVE_ACTION_BAR"); + List healingMessages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_AURA_HEALED_BY_ACTION_BAR"); + new BukkitRunnable() { + int tick = 0; + int messageIndex = 0; + int healingMessageIndex = 0; + + @Override + public void run() { + //apply effects only once per second, particles every 5 ticks + if(tick % 5 == 0 && ServerVersion.Version.isCurrentEqualOrHigher(ServerVersion.Version.v1_9_R1)) { + XParticle.circle(3.5, 18, ParticleDisplay.simple(player.getLocation().add(0, 0.5, 0), XParticle.getParticle("HEART"))); + } + if(tick % 10 == 0) { + int heal = (int) Settings.HEAL_AURA_POWER.getForArenaState((Arena) user.getArena()); + for(LivingEntity entity : getNearbyAllies(player)) { + entity.setHealth(Math.min(entity.getHealth() + heal, VersionUtils.getMaxHealth(entity))); + VersionUtils.sendParticles("HEART", null, entity.getLocation(), 5, 0, 0, 0); + if(!entity.equals(player) && entity instanceof Player) { + VersionUtils.sendActionBar((Player) entity, healingMessages.get(healingMessageIndex) + .replace("%player%", user.getPlayer().getName())); + } + ((Arena) user.getArena()).getAssistHandler().doRegisterBuffOnAlly(player, entity); + } + player.setHealth(Math.min(player.getHealth() + heal, VersionUtils.getMaxHealth(player))); + VersionUtils.sendActionBar(player, messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("medic_aura_running")))); + messageIndex++; + healingMessageIndex++; + if(messageIndex > messages.size() - 1) { + messageIndex = 0; + } + if(healingMessageIndex > healingMessages.size() - 1) { + healingMessageIndex = 0; + } + } + if(tick >= 20 * castTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + cancel(); + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private List getNearbyAllies(Player player) { + return player.getNearbyEntities(3.5, 3.5, 3.5) + .stream() + .filter(e -> e instanceof Player || e instanceof Wolf || e instanceof Golem) + .map(e -> (LivingEntity) e) + .collect(Collectors.toList()); + } + + private enum Settings { + HEAL_AURA_POWER(0, 2, 4), PASSIVE_HEAL_POWER(2, 3, 4), AMPLIFIER_POWER(0, 1, 2); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch(KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ScoreboardModifiable.java b/src/main/java/plugily/projects/villagedefense/kits/ScoreboardModifiable.java new file mode 100644 index 000000000..751e7f206 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ScoreboardModifiable.java @@ -0,0 +1,46 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.List; + +public interface ScoreboardModifiable { + + static String renderAbilityCooldown(User user, String abilityId, String abilityName, int currentWave, KitSpecifications.GameTimeState gameState) { + if (currentWave < gameState.getStartWave()) { + return "&7" + abilityName + ": &c❌"; + } + double cooldown = user.getCooldown(abilityId); + if (cooldown <= 0.0) { + return "&f" + abilityName + ": &a✔"; + } else { + double runningCd = user.getCooldown(abilityId + "_running"); + if (runningCd > 0) { + return "&f" + abilityName + ": &aActive (&6" + (int) runningCd + "s&a)"; + } + return "&f" + abilityName + ": &6" + (int) cooldown + "s"; + } + } + + List getScoreboardLines(User user); + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ShotBowKit.java b/src/main/java/plugily/projects/villagedefense/kits/ShotBowKit.java new file mode 100644 index 000000000..aba14814e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ShotBowKit.java @@ -0,0 +1,301 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * @author Plajer + *

+ * Created at 30.08.2023 + */ +public class ShotBowKit extends PremiumKit implements AbilitySource, Listener, ChatDisplayable, ScoreboardModifiable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_SHOT_BOW_"; + private static final String ARROW_RAIN_KNOCK_METADATA = "VD_SHOTBOW_KNOCKBACK"; + private final Random random = new Random(); + + public ShotBowKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("ShotBow"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.DAMAGE_DEALER, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0046"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Shot-Bow.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Shot-Bow.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ARROW_RAIN_NAME", new Message("Kit.Content.Shot-Bow.Game-Item.Arrow-Rain.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ARROW_RAIN_DESCRIPTION", new Message("Kit.Content.Shot-Bow.Game-Item.Arrow-Rain.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ARROW_RAIN_ACTIVATE", new Message("Kit.Content.Shot-Bow.Game-Item.Arrow-Rain.Activate", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.shotbow"); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "shotbow_arrowrain", "Arrow Rain", wave, KitSpecifications.GameTimeState.MID), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + @Override + public void giveKitItems(Player player) { + ItemStack bow = new ItemStack(Material.BOW); + ItemMeta meta = bow.getItemMeta(); + meta.setUnbreakable(true); + meta.addEnchant(Enchantment.ARROW_INFINITE, 1, true); + bow.setItemMeta(meta); + player.getInventory().addItem(bow); + player.getInventory().setItem(9, new ItemStack(getMaterial(), 1)); + ArmorHelper.setColouredArmor(Color.YELLOW, player); + player.getInventory().setItem(4, new ItemBuilder(new ItemStack(XMaterial.STICK.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ARROW_RAIN_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_ARROW_RAIN_DESCRIPTION")) + .build()); + + player.getInventory().setItem(5, new ItemStack(Material.SADDLE)); + player.getInventory().setItem(8, new ItemStack(XMaterial.COOKED_BEEF.parseMaterial(), 8)); + } + + @Override + public Material getMaterial() { + return Material.ARROW; + } + + @Override + public void reStock(Player player) { + //no restock for this kit + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if(!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), ShotBowKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if(displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ARROW_RAIN_NAME").asKey().build())) { + onArrowRainCast(stack, user); + } + } + + private void onArrowRainCast(ItemStack stack, User user) { + String abilityId = "shotbow_arrowrain"; + if(!user.checkCanCastCooldownAndMessage(abilityId)) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = 20; + user.setCooldown(abilityId, cooldown); + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), 20 * cooldown); + + for(int i = 0; i < Settings.ABILITY_ARROW_RAIN_COUNT.getForArenaState((Arena) user.getArena()); i++) { + Player player = user.getPlayer(); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { + Arrow pr = player.launchProjectile(Arrow.class); + pr.setMetadata(ARROW_RAIN_KNOCK_METADATA, new FixedMetadataValue(getPlugin(), true)); + pr.setVelocity(player.getLocation().getDirection().multiply(4)); + pr.setBounce(false); + pr.setShooter(player); + pr.setCritical(true); + }, 4L * (2L * i)); + } + } + + @EventHandler + public void onArrowDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Arrow) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + Arrow arrow = (Arrow) event.getDamager(); + if(!(arrow.getShooter() instanceof Player)) { + return; + } + Player shooter = (Player) arrow.getShooter(); + User user = getPlugin().getUserManager().getUser(shooter); + if(user == null || user.getArena() == null || !(user.getKit() instanceof ShotBowKit)) { + return; + } + //large knockback for arrow rain ability + if(arrow.hasMetadata(ARROW_RAIN_KNOCK_METADATA)) { + event.getEntity().setVelocity(user.getPlayer().getLocation().getDirection().multiply(5)); + KitHelper.executeEnemy((LivingEntity) event.getEntity(), shooter); + return; + } + Arena arena = (Arena) user.getArena(); + double oneshotChance = Settings.PASSIVE_INSTAKILL_CHANCE.getForArenaState(arena); + double chance = random.nextDouble(); + if(chance <= oneshotChance) { + KitHelper.executeEnemy((LivingEntity) event.getEntity(), shooter); + XSound.BLOCK_NOTE_BLOCK_HARP.play(user.getPlayer()); + return; + } + //apply effective arrows passive from mid game + if(KitSpecifications.getTimeState(arena) == KitSpecifications.GameTimeState.EARLY) { + return; + } + doApplyEffectiveArrows((LivingEntity) event.getEntity(), shooter); + } + + private void doApplyEffectiveArrows(LivingEntity target, Player source) { + int choice = random.nextInt(4) + 1; + switch(choice) { + case 1: { + //lightning aoe + target.getWorld().strikeLightningEffect(target.getLocation()); + KitHelper.maxHealthPercentDamage(target, source, 10.0); + List enemies = target.getNearbyEntities(1.5, 1.5, 1.5) + .stream() + .filter(e -> !target.equals(e)) + .filter(NewCreatureUtils::isEnemy) + .collect(Collectors.toList()); + for(Entity entity : enemies) { + KitHelper.maxHealthPercentDamage((LivingEntity) entity, source, 10.0); + } + break; + } + case 2: + //slowness + if (!target.hasMetadata("VD_UNSTUNNABLE")) { + target.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 10, 1)); + } + break; + case 3: { + //shared combust + List enemies = target.getNearbyEntities(1.5, 1.5, 1.5) + .stream() + .filter(e -> !target.equals(e)) + .filter(NewCreatureUtils::isEnemy) + .map(e -> (LivingEntity) e) + .collect(Collectors.toList()); + for(LivingEntity enemy : enemies) { + enemy.setFireTicks(20 * 10); + enemy.damage(0, source); + } + break; + } + case 4: + default: + //weakness + target.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 20 * 10, 1)); + break; + } + } + + private enum Settings { + PASSIVE_INSTAKILL_CHANCE(0.1, 0.2, 0.3), ABILITY_ARROW_RAIN_COUNT(0, 8, 12); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch(KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/TornadoKit.java b/src/main/java/plugily/projects/villagedefense/kits/TornadoKit.java new file mode 100644 index 000000000..d25fd18f0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/TornadoKit.java @@ -0,0 +1,438 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import org.bukkit.Bukkit; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Creature; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.ParticleDisplay; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by Tom on 30/12/2015. + */ +public class TornadoKit extends PremiumKit implements Listener, AbilitySource, ChatDisplayable, ScoreboardModifiable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_TORNADO_"; + private static final int TORNADO_MAX_HEIGHT = 5; + private static final double TORNADO_MAX_RADIUS = 4; + private static final double TORNADO_RADIUS_INCREMENT = TORNADO_MAX_RADIUS / TORNADO_MAX_HEIGHT; + private final List ultimateUsers = new ArrayList<>(); + + public TornadoKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Tornado"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.SUPPORT, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0049"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Tornado.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Tornado.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_NAME", new Message("Kit.Content.Tornado.Game-Item.Tornado.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_DESCRIPTION", new Message("Kit.Content.Tornado.Game-Item.Tornado.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_NAME", new Message("Kit.Content.Tornado.Game-Item.Monsoon.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_DESCRIPTION", new Message("Kit.Content.Tornado.Game-Item.Monsoon.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_ACTIVE_ACTION_BAR", new Message("Kit.Content.Tornado.Game-Item.Monsoon.Active-Action-Bar", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_NAME", new Message("Kit.Content.Tornado.Game-Item.Final-Flight.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_DESCRIPTION", new Message("Kit.Content.Tornado.Game-Item.Final-Flight.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_ACTIVE_ACTION_BAR", new Message("Kit.Content.Tornado.Game-Item.Final-Flight.Active-Action-Bar", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return player.hasPermission("villagedefense.kit.tornado") || getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "tornado_monsoon", "Monsoon", wave, KitSpecifications.GameTimeState.EARLY), + ScoreboardModifiable.renderAbilityCooldown(user, "tornado_final_flight", "Final Flight", wave, KitSpecifications.GameTimeState.MID), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + @Override + public void giveKitItems(Player player) { + ArmorHelper.setArmor(player, ArmorHelper.ArmorType.GOLD); + ItemStack itemStack = XMaterial.STONE_SWORD.parseItem(); + ItemMeta meta = itemStack.getItemMeta(); + meta.setUnbreakable(true); + itemStack.setItemMeta(meta); + player.getInventory().addItem(itemStack); + + player.getInventory().addItem(new ItemStack(Material.SADDLE)); + player.getInventory().addItem(new ItemBuilder(new ItemStack(getMaterial(), 5)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_DESCRIPTION")) + .build()); + player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.OXEYE_DAISY.parseMaterial(), 1)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_DESCRIPTION")) + .build()); + player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.FEATHER.parseMaterial(), 1)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_DESCRIPTION")) + .build()); + } + + @Override + public Material getMaterial() { + return XMaterial.COBWEB.parseMaterial(); + } + + @Override + public void reStock(Player player) { + int amount = (int) Settings.RESTOCK_AMOUNT.getForArenaState((Arena) getPlugin().getArenaRegistry().getArena(player)); + player.getInventory().addItem(new ItemBuilder(new ItemStack(getMaterial(), amount)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_DESCRIPTION")) + .build()); + + Arena arena = (Arena) getPlugin().getUserManager().getUser(player).getArena(); + if (arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_DESCRIPTION").asKey().build()).send(player); + } else if (arena.getWave() == KitSpecifications.GameTimeState.LATE.getStartWave()) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_DESCRIPTION").asKey().build()).send(player); + } + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + if (user.isSpectator() || !(user.getKit() instanceof TornadoKit)) { + return; + } + Player player = event.getPlayer(); + if (!getPlugin().getArenaRegistry().isInArena(player)) { + return; + } + + ItemStack stack = VersionUtils.getItemInHand(player); + if (!ItemUtils.isItemStackNamed(stack)) { + return; + } + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (displayName.equalsIgnoreCase(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TORNADO_NAME").asKey().build())) { + onTornadoCast(stack, user); + } else if (displayName.equalsIgnoreCase(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_NAME").asKey().build())) { + onMonsoonPreCast(stack, user); + } else if (displayName.equalsIgnoreCase(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_NAME").asKey().build())) { + onFinalFlightPreCast(stack, user); + } + } + + @EventHandler + public void onDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player)) { + return; + } + Player damager = (Player) event.getDamager(); + if (getPlugin().getArenaRegistry().getArena(damager) == null) { + return; + } + User user = getPlugin().getUserManager().getUser(damager); + if (user.isSpectator() || !(user.getKit() instanceof TornadoKit) + || !ultimateUsers.contains(damager) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + LivingEntity livingEntity = (LivingEntity) event.getEntity(); + new BukkitRunnable() { + int tick = 0; + + @Override + public void run() { + if (tick % 5 == 0) { + livingEntity.setVelocity(new Vector(0, 0.5, 0)); + } + + if (tick % 20 == 0) { + KitHelper.maxHealthPercentDamage(livingEntity, user.getPlayer(), 25.0); + } + if (tick >= 20 * 4 || livingEntity.isDead()) { + this.cancel(); + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private void onTornadoCast(ItemStack stack, User user) { + getPlugin().getBukkitHelper().takeOneItem(user.getPlayer(), stack); + XSound.ENTITY_FIREWORK_ROCKET_LAUNCH.play(user.getPlayer(), 1f, 0f); + new BukkitRunnable() { + final Vector vector = user.getPlayer().getLocation().getDirection(); + Location location = user.getPlayer().getLocation(); + int angle; + int times = 0; + int pierce = 0; + + @Override + public void run() { + int lines = 3; + for (int l = 0; l < lines; l++) { + for (double y = 0; y < TORNADO_MAX_HEIGHT; y += 0.5) { + double radius = y * TORNADO_RADIUS_INCREMENT, + radians = Math.toRadians(360.0 / lines * l + y * 25 - angle), + x = Math.cos(radians) * radius, + z = Math.sin(radians) * radius; + VersionUtils.sendParticles("CLOUD", null, location.clone().add(x, y, z), 1, 0, 0, 0); + } + } + pierce += pushAndDamageNearbyEnemies(location, vector); + location = location.add(vector.getX() / (3 + Math.random() / 2), 0, vector.getZ() / (3 + Math.random() / 2)); + angle += 50; + times++; + + if (pierce >= 20 || times > 55) { + cancel(); + } + } + }.runTaskTimer(getPlugin(), 1, 1); + } + + private int pushAndDamageNearbyEnemies(Location location, Vector vector) { + int pierce = 0; + for (LivingEntity entity : getNearbyEnemies(location, 2)) { + pierce++; + + if (!entity.hasMetadata("VD_UNSTUNNABLE")) { + Vector velocity = vector.multiply(1.5).setY(0).add(new Vector(0, 1, 0)); + if (VersionUtils.isPaper() && (vector.getX() > 4.0 || vector.getZ() > 4.0)) { + velocity = vector.setX(2.0).setZ(1.0); // Paper's sh*t + } + entity.setVelocity(velocity); + } + entity.damage(5.0); + } + return pierce; + } + + private void onMonsoonPreCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("tornado_monsoon")) { + return; + } + final int castTime = (int) Settings.MONSOON_CAST_TIME.getForArenaState((Arena) user.getArena()); + int cooldown = getKitsConfig().getInt("Kit-Cooldown.Tornado.Monsoon", 20); + user.setCooldown("tornado_monsoon", cooldown); + user.setCooldown("tornado_monsoon_running", castTime); + + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + onMonsoonCast(user); + } + + private void onMonsoonCast(User user) { + Player player = user.getPlayer(); + final int spellTime = (int) Settings.MONSOON_CAST_TIME.getForArenaState((Arena) user.getArena()); + + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_MONSOON_ACTIVE_ACTION_BAR"); + new BukkitRunnable() { + int spellTick = 0; + int messageIndex = 0; + + @Override + public void run() { + if (ServerVersion.Version.isCurrentEqualOrHigher(ServerVersion.Version.v1_9_R1)) { + XParticle.circle(4, 15, ParticleDisplay.simple(player.getLocation().add(0, 0.5, 0), XParticle.getParticle("CLOUD"))); + } + if (spellTick % 5 == 0) { + for (LivingEntity entity : getNearbyEnemies(player.getLocation(), 4)) { + Vector vector = entity.getLocation().toVector().subtract(player.getLocation().toVector()).normalize(); + vector.add(new Vector(0, 0.1, 0)); + if (!entity.hasMetadata("VD_UNSTUNNABLE")) { + entity.setVelocity(vector.multiply(1.5)); + entity.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 9999, 2, false, true)); + } + entity.playEffect(EntityEffect.HURT); + ((Arena) user.getArena()).getAssistHandler().doRegisterDebuffOnEnemy(player, (Creature) entity); + } + XSound.BLOCK_SNOW_STEP.play(player, 1f, 0f); + } + if (spellTick % 10 == 0) { + VersionUtils.sendActionBar(player, messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("tornado_monsoon_running")))); + messageIndex++; + if (messageIndex > messages.size() - 1) { + messageIndex = 0; + } + } + if (spellTick >= 20 * spellTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + cancel(); + return; + } + spellTick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private List getNearbyEnemies(Location location, int radius) { + return location.getWorld() + .getNearbyEntities(location, radius, radius, radius) + .stream() + .filter(NewCreatureUtils::isEnemy) + .map(e -> (LivingEntity) e) + .collect(Collectors.toList()); + } + + private void onFinalFlightPreCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("tornado_final_flight")) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = getKitsConfig().getInt("Kit-Cooldown.Tornado.Final-Flight", 45); + user.setCooldown("tornado_final_flight", cooldown); + int castTime = 10; + user.setCooldown("tornado_final_flight_running", castTime); + + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + onFinalFlightCast(user); + } + + private void onFinalFlightCast(User user) { + Player player = user.getPlayer(); + final int spellTime = 10; + ultimateUsers.add(user.getPlayer()); + + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_FINAL_FLIGHT_ACTIVE_ACTION_BAR"); + new BukkitRunnable() { + int spellTick = 0; + int messageIndex = 0; + + @Override + public void run() { + if (spellTick % 10 == 0) { + VersionUtils.sendActionBar(player, messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("tornado_final_flight_running")))); + messageIndex++; + if (messageIndex > messages.size() - 1) { + messageIndex = 0; + } + } + if (spellTick >= 20 * spellTime || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + ultimateUsers.remove(user.getPlayer()); + cancel(); + return; + } + spellTick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> ultimateUsers.remove(user.getPlayer()), spellTime * 20L); + } + + private enum Settings { + RESTOCK_AMOUNT(2, 3, 5), MONSOON_CAST_TIME(6, 9, 12); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return earlyValue; + case MID: + return midValue; + case EARLY: + default: + return lateValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/WizardKit.java b/src/main/java/plugily/projects/villagedefense/kits/WizardKit.java new file mode 100644 index 000000000..30d5c9c9e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/WizardKit.java @@ -0,0 +1,674 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits; + +import lombok.SneakyThrows; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.EulerAngle; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.ParticleDisplay; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * @author Plajer + *

+ * Created at 01.03.2018 + *

+ */ +public class WizardKit extends PremiumKit implements Listener, AbilitySource, ChatDisplayable, ScoreboardModifiable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_WIZARD_"; + private final Random random = new Random(); + private final List abilityUsers = new ArrayList<>(); + + public WizardKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Wizard"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getKitRegistry().registerKit(this); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.DAMAGE_DEALER, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0050"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Wizard.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Wizard.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME", new Message("Kit.Content.Wizard.Game-Item.Wand.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGE_READY", new Message("Kit.Content.Wizard.Game-Item.Wand.Name-Overcharge-Ready", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGED", new Message("Kit.Content.Wizard.Game-Item.Wand.Name-Overcharged", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGED_2", new Message("Kit.Content.Wizard.Game-Item.Wand.Name-Overcharged-2", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_DESCRIPTION", new Message("Kit.Content.Wizard.Game-Item.Wand.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_OVERCHARGE_NOT_READY", new Message("Kit.Content.Wizard.Game-Item.Wand.Overcharge-Not-Ready", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_NAME", new Message("Kit.Content.Wizard.Game-Item.Ascension.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_DESCRIPTION", new Message("Kit.Content.Wizard.Game-Item.Ascension.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_ACTIVATE", new Message("Kit.Content.Wizard.Game-Item.Ascension.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_ACTIVE_ACTION_BAR", new Message("Kit.Content.Wizard.Game-Item.Ascension.Active-Action-Bar", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.wizard"); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + renderOvercharge(user), + ScoreboardModifiable.renderAbilityCooldown(user, "wizard_ascension", "Ascension", wave, KitSpecifications.GameTimeState.MID), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + private String renderOvercharge(User user) { + if (abilityUsers.contains(user.getPlayer())) { + return "&fOvercharge: &aActive"; + } + for (ItemStack itemStack : user.getPlayer().getInventory()) { + if (itemStack == null || !itemStack.hasItemMeta() || itemStack.getType() != Material.GOLDEN_HOE) { + continue; + } + //dig speed is used as a flag for overcharge + if (itemStack.getItemMeta().hasEnchant(Enchantment.DIG_SPEED)) { + return "&fOvercharge: &a✔"; + } else { + Damageable damageable = (Damageable) itemStack.getItemMeta(); + int max = itemStack.getType().getMaxDurability() - 1; + int percent = (int) ((1 - ((double) damageable.getDamage() / (double) max)) * 100); + return "&fOvercharge: &6" + percent + "%"; + } + } + return "&fOvercharge: &60%"; + } + + @Override + public void giveKitItems(Player player) { + ItemStack wandItem = new ItemBuilder(getMaterial()) + .flags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_ATTRIBUTES) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_DESCRIPTION")) + .build(); + Damageable damageable = (Damageable) wandItem.getItemMeta(); + damageable.setDamage(31); + wandItem.setItemMeta(damageable); + player.getInventory().setItem(3, wandItem); + player.getInventory().setItem(4, new ItemBuilder(new ItemStack(XMaterial.SPIDER_EYE.parseMaterial(), 1)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_DESCRIPTION")) + .build()); + player.getInventory().setItem(5, new ItemStack(Material.SADDLE)); + + ArmorHelper.setColouredArmor(Color.fromRGB(100, 149, 237), player); + player.getInventory().setItem(8, new ItemStack(Material.SADDLE)); + } + + @Override + public Material getMaterial() { + return Material.GOLDEN_HOE; + } + + @Override + public void reStock(Player player) { + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); + if (arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build()).send(player); + } else if (arena.getWave() == KitSpecifications.GameTimeState.LATE.getStartWave()) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_NAME").asKey().build()).send(player); + } + } + + @EventHandler + public void onDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player)) { + return; + } + Player damager = (Player) event.getDamager(); + if (getPlugin().getArenaRegistry().getArena(damager) == null) { + return; + } + User user = getPlugin().getUserManager().getUser(damager); + if (user.isSpectator() || !(user.getKit() instanceof WizardKit) || !abilityUsers.contains(damager) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + LivingEntity entity = (LivingEntity) event.getEntity(); + if (!entity.hasMetadata("VD_UNSTUNNABLE")) { + entity.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * 3, 3, false, true)); + } + entity.setFireTicks(20 * 3); + ((Arena) user.getArena()).getAssistHandler().doRegisterDebuffOnEnemy(user.getPlayer(), (Creature) entity); + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if (!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), WizardKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ChatColor.translateAlternateColorCodes('&', ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta())); + if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_NAME").asKey().build())) { + event.setCancelled(true); + onAscensionPreCast(stack, user); + } else if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) { + String wandDefault = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build(); + String wandOverchargeReady = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGE_READY").asKey().build(); + String wandOvercharge = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGED").asKey().build(); + String wandOvercharge2 = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGED_2").asKey().build(); + if (displayName.equals(wandDefault) || displayName.equals(wandOvercharge) + || displayName.equals(wandOvercharge2) || displayName.equals(wandOverchargeReady)) { + event.setCancelled(true); + onWandPreCast(stack, user); + } + } else if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) { + String wandDefault = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build(); + if (displayName.equals(wandDefault)) { + event.setCancelled(true); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_OVERCHARGE_NOT_READY").asKey().player(user.getPlayer()).sendPlayer(); + return; + } + String wandOverchargeReady = new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGE_READY").asKey().build(); + if (displayName.equals(wandOverchargeReady)) { + event.setCancelled(true); + onWandOverchargePreCast(stack, user); + } + } + } + + private void onAscensionPreCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("wizard_ascension")) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = 70; + user.setCooldown("wizard_ascension", cooldown); + int castTime = 12; + user.setCooldown("wizard_ascension_running", castTime); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_ACTIVATE").asKey().send(user.getPlayer()); + + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + onAscensionCast(stack, user); + } + + @SneakyThrows + private void onAscensionCast(ItemStack stack, User user) { + Player player = user.getPlayer(); + double yDefault = player.getLocation().getY(); + player.getWorld().strikeLightningEffect(player.getLocation()); + Location particleLocation = player.getLocation().clone(); + particleLocation.setY(yDefault + 0.3); + KitHelper.damageNearbyPercent(player, 10.0, 1.5); + XParticle.circle(0.25, 7, ParticleDisplay.simple(particleLocation, XParticle.getParticle("SMOKE_NORMAL"))); + player.playSound(player, Sound.BLOCK_BEACON_POWER_SELECT, 1, 0.25f); + List locations = new ArrayList<>(); + locations.add(player.getLocation().clone().add(3.25, 0, 0)); + locations.add(player.getLocation().clone().add(0, 0, 3.25)); + locations.add(player.getLocation().clone().add(-3.25, 0, 0)); + locations.add(player.getLocation().clone().add(0, 0, -3.25)); + for (int i = 0; i < 4; i++) { + final int finalI = i; + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> spawnAscensionProjectile(locations.get(finalI), user, finalI), 10 * (i + 1)); + } + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_ASCENSION_ACTIVE_ACTION_BAR"); + new BukkitRunnable() { + int tick = 0; + double radius = 0.25; + int particlesAmount = 7; + int messageIndex = 0; + + @Override + public void run() { + for (double t = 0; t < Math.PI * 2; t += Math.PI / 10) { + double x = Math.sin(t) * 0.5 * 2.0; + double y = Math.sin(t * 2) * 0.5 * 2.0; + + double rotatedX = x; + double rotatedY = y * Math.cos(Math.PI / 4); + + Location pLoc = player.getLocation(); + Location location = new Location(pLoc.getWorld(), pLoc.getX() + rotatedX, yDefault + 2.25 + rotatedY, pLoc.getZ()); + location = location.setDirection(location.getDirection().normalize().multiply(-1)); + + // Spawn particle + player.getLocation().getWorld().spawnParticle(Particle.SMOKE_NORMAL, location, 1, 0, 0, 0, 0); + } + XParticle.circle(radius, particlesAmount, ParticleDisplay.simple(particleLocation, XParticle.getParticle("SMOKE_NORMAL"))); + for (Entity entity : player.getLocation().getNearbyEntities(2.5, 2.5, 2.5)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + if (!entity.hasMetadata("VD_UNSTUNNABLE")) { + Vector vector = entity.getLocation().toVector().subtract(player.getLocation().toVector()).normalize(); + vector.add(new Vector(0, 0.1, 0)); + entity.setVelocity(vector.multiply(1.2)); + } + } + if (player.getY() - yDefault < 1.5) { + double value = 0.1; + if (tick <= 10) { + value = 0.25; + } else if (tick <= 20) { + value = 0.15; + } + player.setVelocity(new Vector(0, value, 0)); + } + if (radius <= 3.5) { + radius += 0.15; + particlesAmount += 1; + } + particleLocation.setX(player.getLocation().getX()); + particleLocation.setZ(player.getLocation().getZ()); + if (tick % 10 == 0) { + VersionUtils.sendActionBar(player, messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("wizard_ascension_running")))); + messageIndex++; + if (messageIndex > messages.size() - 1) { + messageIndex = 0; + } + } + + if (tick >= 20 * 12 || !getPlugin().getArenaRegistry().isInArena(user.getPlayer()) || user.isSpectator()) { + //reset action bar + VersionUtils.sendActionBar(player, ""); + this.cancel(); + for (Entity entity : player.getNearbyEntities(4, 4, 4)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + ((LivingEntity) entity).damage(1.5, player); + entity.setFireTicks(20 * 3); + } + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private void spawnAscensionProjectile(Location targetLocation, User user, int i) { + ArmorStand projectile = spawnProjectile(targetLocation); + projectile.getEquipment().setHelmet(new ItemStack(Material.WITHER_SKELETON_SKULL)); + projectile.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, projectile.getLocation().add(0, 0.5, 0), 1, 0, 0, 0, 0); + projectile.getWorld().playSound(projectile.getLocation(), Sound.ENTITY_WITHER_SHOOT, 0.75f, .5f); + XSound.BLOCK_END_PORTAL_FRAME_FILL.play(user.getPlayer(), 0.25f, 0.25f); + LivingEntity targetEntity = rollNearbyEntity(user.getPlayer().getLocation()); + if (targetEntity != null) { + targetEntity.setMetadata("VD_WIZARD_ULTIMATE_TARGET", new FixedMetadataValue(getPlugin(), projectile.getUniqueId())); + } + final LivingEntity finalEntity = targetEntity; + new BukkitRunnable() { + final Location location = targetLocation; + final double speed = 0.25; + double positionModifier = 0; + int rotation = 0; + int aliveTicks = 0; + LivingEntity target = finalEntity; + + @Override + public void run() { + Location newPosition = location.clone(); + if (positionModifier <= 1.5) { + positionModifier += 0.1; + newPosition = newPosition.add(0, 0.1, 0); + } else { + if (target == null || target.isDead()) { + target = rollNearbyEntity(user.getPlayer().getLocation()); + } + if (target != null) { + target.setMetadata("VD_WIZARD_ULTIMATE_TARGET", new FixedMetadataValue(getPlugin(), projectile.getUniqueId())); + Location currentLocation = projectile.getLocation().clone(); + double distance = currentLocation.distance(target.getLocation()); + if (distance > 0.1) { + double dx = target.getX() - currentLocation.getX(); + double dy = target.getY() - currentLocation.getY(); + double dz = target.getZ() - currentLocation.getZ(); + + double length = Math.sqrt(dx * dx + dy * dy + dz * dz); + dx /= length; + dy /= length; + dz /= length; + + dx *= speed; + dy *= speed; + dz *= speed; + newPosition = newPosition.add(dx, dy, dz); + } else { + //damage only every second tick + if (aliveTicks % 2 == 0) { + KitHelper.maxHealthPercentDamage(target, user.getPlayer(), Settings.WAND_PERCENT_DAMAGE.getForArenaState((Arena) user.getArena())); + } + if (target.isDead()) { + for (Entity entity : user.getPlayer().getLocation().getNearbyEntities(6, 6, 6)) { + if (!NewCreatureUtils.isEnemy(entity) || entity.hasMetadata("VD_WIZARD_ULTIMATE_TARGET")) { + continue; + } + entity.setMetadata("VD_WIZARD_ULTIMATE_TARGET", new FixedMetadataValue(getPlugin(), projectile.getUniqueId())); + target = (LivingEntity) entity; + break; + } + } + } + } + } + + rotation += 10; + if (rotation >= 360) { + rotation -= 360; + } + //spawn before location update + location.getWorld().spawnParticle(Particle.DRAGON_BREATH, projectile.getEyeLocation(), 1, 0, 0, 0, 0); + location.set(newPosition.getX(), newPosition.getY(), newPosition.getZ()); + projectile.teleport(location); + projectile.setHeadPose(new EulerAngle(Math.toRadians(rotation), Math.toRadians(rotation), 0)); + + if (aliveTicks >= (20 * 10) + (10 * (4 - i))) { + if (target != null) { + target.removeMetadata("VD_WIZARD_ULTIMATE_TARGET", getPlugin()); + } + projectile.getWorld().spawnParticle(Particle.SOUL, projectile.getLocation(), 5, 0.15, 0.15, 0.15, 0); + projectile.remove(); + cancel(); + } + aliveTicks++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private LivingEntity rollNearbyEntity(Location location) { + List entities = location.getNearbyLivingEntities(6) + .stream() + .filter(NewCreatureUtils::isEnemy) + .filter(e -> !e.hasMetadata("VD_WIZARD_ULTIMATE_TARGET")) + .collect(Collectors.toList()); + if (entities.isEmpty()) { + return null; + } + return entities.get(random.nextInt(entities.size())); + } + + private void onWandOverchargePreCast(ItemStack stack, User user) { + Damageable meta = (Damageable) stack.getItemMeta(); + meta.setDisplayName(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build()); + user.getPlayer().playSound(user.getPlayer(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1.5f); + abilityUsers.add(user.getPlayer()); + new BukkitRunnable() { + int ticks = 0; + boolean toggle = false; + + @Override + public void run() { + if (toggle) { + ComplementAccessor.getComplement().setDisplayName(meta, new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGED_2").asKey().build()); + } else { + ComplementAccessor.getComplement().setDisplayName(meta, new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGED").asKey().build()); + } + toggle = !toggle; + meta.setDamage(Math.min(stack.getType().getMaxDurability() - 1, meta.getDamage() + 2)); + if (ticks >= 210 || meta.getDamage() >= stack.getType().getMaxDurability() - 1) { + meta.removeEnchantments(); + ComplementAccessor.getComplement().setDisplayName(meta, new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME").asKey().build()); + abilityUsers.remove(user.getPlayer()); + cancel(); + } + stack.setItemMeta(meta); + ticks += 20; + } + }.runTaskTimer(getPlugin(), 20, 20); + } + + private void onWandPreCast(ItemStack stack, User user) { + //no cooldown message, this ability is spammy no need for such message + if (user.getCooldown("wizard_staff") > 0) { + return; + } + double cooldown = Settings.WAND_COOLDOWN.getForArenaState((Arena) user.getArena()); + user.setCooldown("wizard_staff", cooldown); + + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), (int) (cooldown * 20)); + onWandCast(stack, user); + } + + private void onWandCast(ItemStack stack, User user) { + final int finalPierce = (int) Settings.DEFAULT_PIERCE.getForArenaState((Arena) user.getArena()); + Location startLocation = user.getPlayer().getLocation().add(0, 0.75, 0); + startLocation.setDirection(startLocation.getDirection().normalize()); + ArmorStand projectile = spawnProjectile(startLocation); + Material skull = Material.WITHER_SKELETON_SKULL; + if (abilityUsers.contains(user.getPlayer())) { + skull = Material.CREEPER_HEAD; + } + projectile.getEquipment().setHelmet(new ItemStack(skull)); + new BukkitRunnable() { + final Location location = startLocation; + Vector direction = location.getDirection().normalize(); + double positionModifier = 0; + int rotation = 0; + int aliveTicks = 0; + int pierce = finalPierce; + boolean anyHit = false; + boolean anyKill = false; + + @Override + public void run() { + positionModifier += 0.15; + double x = direction.getX() * positionModifier; + double y = direction.getY() * positionModifier; + double z = direction.getZ() * positionModifier; + Location newPosition = location.clone().add(x, y, z); + + boolean localHit = false; + boolean localKill = false; + for (Entity entity : newPosition.getNearbyEntities(0.5, 0.5, 0.5)) { + if (pierce <= 0 || !NewCreatureUtils.isEnemy(entity) || entity.equals(user.getPlayer())) { + continue; + } + LivingEntity livingEntity = (LivingEntity) entity; + double maxHealthPercent = Settings.WAND_PERCENT_DAMAGE.getForArenaState((Arena) user.getArena()); + KitHelper.maxHealthPercentDamage(livingEntity, user.getPlayer(), maxHealthPercent); + if (!entity.hasMetadata("VD_UNSTUNNABLE")) { + Vector pushDirection = entity.getLocation().toVector().subtract(projectile.getLocation().add(0, 1.5, 0).toVector()).normalize(); + entity.setVelocity(pushDirection.multiply(1.5)); + } + localHit = true; + if (entity.isDead() || ((LivingEntity) entity).getHealth() <= 0) { + localKill = true; + } + VersionUtils.sendParticles("DAMAGE_INDICATOR", null, entity.getLocation(), 1, 0, 0, 0); + pierce--; + } + if (localKill && !anyKill) { + XSound.ENTITY_GENERIC_HURT.play(user.getPlayer()); + anyKill = true; + anyHit = true; + location.getWorld().playSound(location, Sound.ENTITY_GENERIC_HURT, 1, 1); + if (!stack.getItemMeta().hasEnchants()) { + Damageable damageable = (Damageable) stack.getItemMeta(); + damageable.setDamage(Math.max(1, damageable.getDamage() - 1)); + if (damageable.getDamage() <= (short) 1) { + damageable.addEnchant(Enchantment.DIG_SPEED, 1, true); + ComplementAccessor.getComplement().setDisplayName(damageable, new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_WAND_NAME_OVERCHARGE_READY").asKey().build()); + user.getPlayer().playSound(user.getPlayer(), Sound.ENTITY_BLAZE_SHOOT, 1, 0.25f); + } + stack.setItemMeta(damageable); + } + } + if (localHit && !anyHit) { + XSound.ENTITY_GENERIC_DEATH.play(user.getPlayer()); + location.getWorld().playSound(location, Sound.ENTITY_GENERIC_DEATH, 1, 1); + anyHit = true; + } + + if (newPosition.getBlock().getType().isSolid()) { + Vector normal = getSurfaceNormal(newPosition.getBlock()); + direction = direction.subtract(normal.multiply(2 * direction.dot(normal))); + positionModifier -= 0.1; + newPosition = location.clone().add(direction.normalize().multiply(0.12)); + newPosition.getWorld().spawnParticle(Particle.WHITE_SMOKE, newPosition, 3, 0.1, 0.1, 0.1, 0); + } + rotation += 10; + if (rotation >= 360) { + rotation -= 360; + } + //spawn before location update + location.getWorld().spawnParticle(Particle.DRAGON_BREATH, projectile.getEyeLocation(), 1, 0, 0, 0, 0); + location.set(newPosition.getX(), newPosition.getY(), newPosition.getZ()); + projectile.teleport(location); + projectile.setHeadPose(new EulerAngle(Math.toRadians(rotation), Math.toRadians(rotation), 0)); + + if (aliveTicks >= 60) { + projectile.getWorld().spawnParticle(Particle.SOUL, projectile.getLocation(), 5, 0.15, 0.15, 0.15, 0); + projectile.remove(); + cancel(); + } + aliveTicks++; + } + + private Vector getSurfaceNormal(Block block) { + double x = 0, y = 0, z = 0; + if (block.getX() < location.getBlockX()) { + x = 1; + } else if (block.getX() > location.getBlockX()) { + x = -1; + } else if (block.getY() < location.getBlockY()) { + y = 1; + } else if (block.getY() > location.getBlockY()) { + y = -1; + } else if (block.getZ() < location.getBlockZ()) { + z = 1; + } else if (block.getZ() > location.getBlockZ()) { + z = -1; + } + return new Vector(x, y, z); + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + private ArmorStand spawnProjectile(Location location) { + ArmorStand projectile = (ArmorStand) location.getWorld().spawnEntity(location, EntityType.ARMOR_STAND); + projectile.setVisible(false); + projectile.setGravity(false); + projectile.setSmall(true); + projectile.setInvulnerable(true); + projectile.setBasePlate(false); + return projectile; + } + + private enum Settings { + DEFAULT_PIERCE(3, 4, 5), WAND_COOLDOWN(1.25, 1, 0.75), WAND_PERCENT_DAMAGE(20.0, 25.0, 30.0); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ability/AbilitiesRegistry.java b/src/main/java/plugily/projects/villagedefense/kits/ability/AbilitiesRegistry.java new file mode 100644 index 000000000..c63861a4e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ability/AbilitiesRegistry.java @@ -0,0 +1,34 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.ability; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Plajer + *

+ * Created at 16.08.2023 + */ +public class AbilitiesRegistry { + + private final List abilities = new ArrayList<>(); + private final List influences = new ArrayList<>(); + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ability/Ability.java b/src/main/java/plugily/projects/villagedefense/kits/ability/Ability.java new file mode 100644 index 000000000..3fbcdbdbb --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ability/Ability.java @@ -0,0 +1,38 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.ability; + +import plugily.projects.minigamesbox.classic.user.User; + +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * @author Plajer + *

+ * Created at 16.08.2023 + */ +public class Ability { + + private AbilitySource sourceKit; + private boolean consumable; + private Predicate canCast; + private Consumer onCast; + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ability/AbilityInfluence.java b/src/main/java/plugily/projects/villagedefense/kits/ability/AbilityInfluence.java new file mode 100644 index 000000000..1b23b78db --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ability/AbilityInfluence.java @@ -0,0 +1,34 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.ability; + +import plugily.projects.minigamesbox.classic.user.User; + +/** + * @author Plajer + *

+ * Created at 16.08.2023 + */ +public class AbilityInfluence { + + private User abilityCaster; + private AbilitySource sourceKit; + private String abilityId; + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/ability/AbilitySource.java b/src/main/java/plugily/projects/villagedefense/kits/ability/AbilitySource.java new file mode 100644 index 000000000..e96721872 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/ability/AbilitySource.java @@ -0,0 +1,34 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.ability; + +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; + +/** + * @author Plajer + *

+ * Created at 04.08.2023 + *

+ * Interface that aims to unify all kits abilities together in the upcoming future. + */ +public interface AbilitySource { + + void onAbilityCast(PlugilyPlayerInteractEvent event); + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/free/LightTankKit.java b/src/main/java/plugily/projects/villagedefense/kits/free/LightTankKit.java deleted file mode 100644 index aa218258d..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/free/LightTankKit.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.free; - -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.FreeKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 18/08/2014. - */ -public class LightTankKit extends FreeKit { - - public LightTankKit() { - setName(new MessageBuilder("KIT_CONTENT_LIGHT_TANK_NAME").asKey().build()); - setKey("LightTank"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_LIGHT_TANK_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return true; - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - ArmorHelper.setArmor(player, ArmorHelper.ArmorType.IRON); - VersionUtils.setMaxHealth(player, 26.0); - player.setHealth(26.0); - } - - @Override - public Material getMaterial() { - return Material.LEATHER_CHESTPLATE; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/ArcherKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/ArcherKit.java deleted file mode 100644 index 252eba1d4..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/ArcherKit.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; - -import java.util.List; - -/** - * Created by Tom on 14/08/2014. - */ -public class ArcherKit extends LevelKit { - - public ArcherKit() { - setLevel(getKitsConfig().getInt("Required-Level.Archer")); - setName(new MessageBuilder("KIT_CONTENT_ARCHER_NAME").asKey().build()); - setKey("Archer"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_ARCHER_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.archer"); - } - - @Override - public void giveKitItems(Player player) { - ArmorHelper.setColouredArmor(Color.GREEN, player); - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - player.getInventory().addItem(WeaponHelper.getEnchantedBow(Enchantment.DURABILITY, 10)); - player.getInventory().addItem(new ItemStack(Material.ARROW, 64)); - player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 10)); - } - - @Override - public Material getMaterial() { - return Material.BOW; - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(new ItemStack(Material.ARROW, 15)); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/GolemFriendKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/GolemFriendKit.java deleted file mode 100644 index cd2ac5112..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/GolemFriendKit.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; - -import java.util.List; - -/** - * Created by Tom on 21/07/2015. - */ -public class GolemFriendKit extends LevelKit { - - public GolemFriendKit() { - setName(new MessageBuilder("KIT_CONTENT_GOLEM_FRIEND_NAME").asKey().build()); - setKey("GolemFriend"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_GOLEM_FRIEND_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.GolemFriend")); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.golemfriend"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - ArmorHelper.setColouredArmor(Color.WHITE, player); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); - if(arena != null) { - spawnGolem(player, arena); - } - } - - @Override - public Material getMaterial() { - return Material.IRON_INGOT; - } - - @Override - public void reStock(Player player) { - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); - if(arena != null && arena.getWave() % 5 == 0) { - spawnGolem(player, arena); - } - } - - private void spawnGolem(Player player, Arena arena) { - arena.spawnGolem(arena.getStartLocation(), player); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/HardcoreKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/HardcoreKit.java deleted file mode 100644 index 490887d21..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/HardcoreKit.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 28/07/2015. - */ -public class HardcoreKit extends LevelKit { - - public HardcoreKit() { - setName(new MessageBuilder("KIT_CONTENT_HARDCORE_NAME").asKey().build()); - setKey("Hardcore"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_HARDCORE_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.Hardcore")); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.hardcore"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - ArmorHelper.setColouredArmor(Color.WHITE, player); - player.getInventory().addItem(VersionUtils.getPotion(PotionType.INSTANT_HEAL, 2, true)); - player.getInventory().addItem(new ItemStack(Material.COOKIE, 10)); - VersionUtils.setMaxHealth(player, 10.0); - } - - @Override - public Material getMaterial() { - return XMaterial.PLAYER_HEAD.parseMaterial(); - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(VersionUtils.getPotion(PotionType.INSTANT_HEAL, 2, true)); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/HealerKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/HealerKit.java deleted file mode 100644 index 3d6266720..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/HealerKit.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 18/08/2014. - */ -public class HealerKit extends LevelKit { - - public HealerKit() { - setName(new MessageBuilder("KIT_CONTENT_HEALER_NAME").asKey().build()); - setKey("Healer"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_HEALER_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.Healer")); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.healer"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - ArmorHelper.setColouredArmor(Color.WHITE, player); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - player.getInventory().addItem(VersionUtils.getPotion(PotionType.INSTANT_HEAL, 2, true)); - player.getInventory().addItem(VersionUtils.getPotion(PotionType.REGEN, 1, true)); - } - - @Override - public Material getMaterial() { - return XMaterial.POPPY.parseMaterial(); - } - - @Override - public void reStock(Player player) { - for(int i = 0; i < 2; i++) { - player.getInventory().addItem(VersionUtils.getPotion(PotionType.INSTANT_HEAL, 2, true)); - } - for(int i = 0; i < 2; i++) { - player.getInventory().addItem(VersionUtils.getPotion(PotionType.REGEN, 1, true)); - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/LooterKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/LooterKit.java deleted file mode 100644 index 2d96fcf3f..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/LooterKit.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -import java.util.List; - -/** - * Created by Tom on 21/07/2015. - */ -public class LooterKit extends LevelKit implements Listener { - - public LooterKit() { - setName(new MessageBuilder("KIT_CONTENT_LOOTER_NAME").asKey().build()); - setKey("Looter"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_LOOTER_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.Looter")); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.looter"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - ArmorHelper.setColouredArmor(Color.ORANGE, player); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - } - - @Override - public Material getMaterial() { - return Material.ROTTEN_FLESH; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } - - @EventHandler - public void onDeath(EntityDeathEvent event) { - org.bukkit.entity.LivingEntity entity = event.getEntity(); - if(!(CreatureUtils.isEnemy(entity)) || entity.getKiller() == null) { - return; - } - Player player = entity.getKiller(); - if(getPlugin().getArenaRegistry().getArena(player) == null) { - return; - } - if(getPlugin().getUserManager().getUser(player).getKit() instanceof LooterKit) { - player.getInventory().addItem(new ItemStack(getMaterial(), 1)); - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/MediumTankKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/MediumTankKit.java deleted file mode 100644 index 888486b4b..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/MediumTankKit.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 19/08/2014. - */ -public class MediumTankKit extends LevelKit { - - public MediumTankKit() { - setName(new MessageBuilder("KIT_CONTENT_MEDIUM_TANK_NAME").asKey().build()); - setKey("MediumTank"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_MEDIUM_TANK_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.MediumTank")); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= this.getLevel() || player.hasPermission("villagedefense.kit.mediumtank"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - ArmorHelper.setArmor(player, ArmorHelper.ArmorType.IRON); - VersionUtils.setMaxHealth(player, 32.0); - player.setHealth(32.0); - } - - @Override - public Material getMaterial() { - return Material.IRON_CHESTPLATE; - } - - @Override - public void reStock(Player player) { - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/PuncherKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/PuncherKit.java deleted file mode 100644 index f8554486e..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/PuncherKit.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 18/08/2014. - */ -public class PuncherKit extends LevelKit { - - public PuncherKit() { - setName(new MessageBuilder("KIT_CONTENT_PUNCHER_NAME").asKey().build()); - setKey("Puncher"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_PUNCHER_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.Puncher")); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.puncher"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getEnchanted(XMaterial.DIAMOND_SHOVEL.parseItem(), new Enchantment[]{ - Enchantment.DURABILITY, Enchantment.KNOCKBACK, Enchantment.DAMAGE_ALL}, new int[]{10, 5, 2})); - ArmorHelper.setColouredArmor(Color.BLACK, player); - player.getInventory().addItem(WeaponHelper.getEnchantedBow(Enchantment.DURABILITY, 5)); - player.getInventory().addItem(new ItemStack(Material.ARROW, 25)); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - } - - @Override - public Material getMaterial() { - return XMaterial.DIAMOND_SHOVEL.parseMaterial(); - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/RunnerKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/RunnerKit.java deleted file mode 100644 index 94aedd81a..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/RunnerKit.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 18/08/2014. - */ -public class RunnerKit extends LevelKit { - - public RunnerKit() { - setLevel(getKitsConfig().getInt("Required-Level.Runner")); - setName(new MessageBuilder("KIT_CONTENT_RUNNER_NAME").asKey().build()); - setKey("Runner"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_RUNNER_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.runner"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getEnchanted(new ItemStack(Material.STICK), new Enchantment[]{ - Enchantment.KNOCKBACK, Enchantment.DAMAGE_UNDEAD, Enchantment.DURABILITY}, new int[]{2, 1, 10})); - ArmorHelper.setColouredArmor(Color.BLUE, player); - player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 2)); - player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 1)); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - } - - @Override - public Material getMaterial() { - return XMaterial.FIREWORK_ROCKET.parseMaterial(); - } - - @Override - public void reStock(Player player) { - player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 2)); - player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP, Integer.MAX_VALUE, 1)); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/TerminatorKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/TerminatorKit.java deleted file mode 100644 index cacbc2a81..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/TerminatorKit.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 18/07/2015. - */ -public class TerminatorKit extends LevelKit { - - public TerminatorKit() { - setName(new MessageBuilder("KIT_CONTENT_TERMINATOR_NAME").asKey().build()); - setKey("Terminator"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_TERMINATOR_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.Terminator")); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.terminator"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - player.getInventory().addItem(WeaponHelper.getEnchanted(new ItemStack(Material.BONE), new Enchantment[]{Enchantment.DAMAGE_ALL, Enchantment.KNOCKBACK}, new int[]{3, 7})); - ArmorHelper.setColouredArmor(Color.BLACK, player); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - player.getInventory().addItem(VersionUtils.getPotion(PotionType.STRENGTH, 2, true)); - player.getInventory().addItem(VersionUtils.getPotion(PotionType.REGEN, 1, true)); - } - - @Override - public Material getMaterial() { - return Material.ANVIL; - } - - @Override - public void reStock(Player player) { - for(int i = 0; i < 2; i++) { - player.getInventory().addItem(VersionUtils.getPotion(PotionType.STRENGTH, 2, true)); - } - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/WorkerKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/WorkerKit.java deleted file mode 100644 index c31c57456..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/WorkerKit.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.utils.Utils; - -import java.util.List; - -/** - * Created by Tom on 19/07/2015. - */ -public class WorkerKit extends LevelKit implements Listener { - - public WorkerKit() { - setLevel(getKitsConfig().getInt("Required-Level.Worker")); - setName(new MessageBuilder("KIT_CONTENT_WORKER_NAME").asKey().build()); - setKey("Worker"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_WORKER_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getUserManager().getUser(player).getStatistic("LEVEL") >= getLevel() || player.hasPermission("villagedefense.kit.worker"); - } - - @Override - public void giveKitItems(Player player) { - ArmorHelper.setColouredArmor(Color.PURPLE, player); - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - player.getInventory().addItem(WeaponHelper.getEnchantedBow(Enchantment.DURABILITY, 10)); - player.getInventory().addItem(new ItemStack(XMaterial.ARROW.parseMaterial(), 64)); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_BEEF.parseMaterial(), 10)); - player.getInventory().addItem(new ItemStack(getMaterial(), 2)); - } - - @Override - public Material getMaterial() { - return Utils.getCachedDoor(null); - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(new ItemStack(getMaterial())); - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onDoorPlace(BlockPlaceEvent event) { - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(event.getPlayer()); - if(arena == null) { - return; - } - if(getPlugin().getUserManager().getUser(event.getPlayer()).isSpectator() || !arena.getMapRestorerManager().getGameDoorLocations() - .containsKey(event.getBlock().getLocation())) { - event.setCancelled(true); - return; - } - if(VersionUtils.getItemInHand(event.getPlayer()).getType() != Utils.getCachedDoor(event.getBlock())) { - event.setCancelled(true); - return; - } - //to override world guard protection - event.setCancelled(false); - new MessageBuilder("KIT_CONTENT_WORKER_GAME_ITEM_CHAT").asKey().player(event.getPlayer()).sendPlayer(); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/level/ZombieFinderKit.java b/src/main/java/plugily/projects/villagedefense/kits/level/ZombieFinderKit.java deleted file mode 100644 index 1f5e38a13..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/level/ZombieFinderKit.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.level; - -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.LevelKit; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; - -import java.util.List; -import java.util.Random; - -/** - * Created by Tom on 21/07/2015. - */ -public class ZombieFinderKit extends LevelKit implements Listener { - - public ZombieFinderKit() { - setName(new MessageBuilder("KIT_CONTENT_ZOMBIE_TELEPORTER_NAME").asKey().build()); - setKey("ZombieFinder"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_ZOMBIE_TELEPORTER_DESCRIPTION"); - setDescription(description); - setLevel(getKitsConfig().getInt("Required-Level.ZombieFinder")); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return true; - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - player.getInventory().addItem(new ItemBuilder(WeaponHelper.getEnchanted(new ItemStack(Material.BOOK), new Enchantment[]{Enchantment.DAMAGE_ALL}, new int[]{1})) - .name(new MessageBuilder("KIT_CONTENT_ZOMBIE_TELEPORTER_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_ZOMBIE_TELEPORTER_GAME_ITEM_DESCRIPTION")) - .build()); - } - - @Override - public Material getMaterial() { - return Material.FISHING_ROD; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } - - @EventHandler - public void onTeleport(PlugilyPlayerInteractEvent event) { - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(event.getPlayer()); - if(arena == null || !ItemUtils.isItemStackNamed(event.getItem()) || event.getItem().getType() != Material.BOOK - || !ComplementAccessor.getComplement().getDisplayName(event.getItem().getItemMeta()).equals(new MessageBuilder("KIT_CONTENT_ZOMBIE_TELEPORTER_GAME_ITEM_GUI").asKey().build())) { - return; - } - User user = getPlugin().getUserManager().getUser(event.getPlayer()); - if(user.isSpectator()) { - new MessageBuilder("IN_GAME_SPECTATOR_SPECTATOR_WARNING").asKey().player(user.getPlayer()).sendPlayer(); - return; - } - if(!(user.getKit() instanceof ZombieFinderKit)) { - return; - } - double zombieCooldown = user.getCooldown("zombie"); - if(zombieCooldown > 0 && !user.isSpectator()) { - new MessageBuilder("KIT_COOLDOWN").asKey().integer((int) zombieCooldown).player(user.getPlayer()).sendPlayer(); - return; - } - if(arena.getEnemies().isEmpty()) { - new MessageBuilder("KIT_CONTENT_ZOMBIE_TELEPORTER_TELEPORT_NOT_FOUND").asKey().player(user.getPlayer()).sendPlayer(); - return; - } - - Creature creature = arena.getEnemies().get(arena.getEnemies().size() == 1 ? 0 : getPlugin().getRandom().nextInt(arena.getEnemies().size())); - VersionUtils.teleport(creature, event.getPlayer().getLocation()); - creature.addPotionEffect(new PotionEffect(PotionEffectType.WEAKNESS, 20 * 30, 0)); - new MessageBuilder("KIT_CONTENT_ZOMBIE_TELEPORTER_TELEPORT_ZOMBIE").asKey().player(user.getPlayer()).sendPlayer(); - VersionUtils.playSound(event.getPlayer().getLocation(), "ENTITY_ZOMBIE_DEATH"); - user.setCooldown("zombie", getKitsConfig().getInt("Kit-Cooldown.Zombie-Finder", 30)); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/petsfriend/PetUpgrade.java b/src/main/java/plugily/projects/villagedefense/kits/petsfriend/PetUpgrade.java new file mode 100644 index 000000000..caddc679d --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/petsfriend/PetUpgrade.java @@ -0,0 +1,24 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.petsfriend; + +public record PetUpgrade( + String id +) { +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/petsfriend/PetsFriendKit.java b/src/main/java/plugily/projects/villagedefense/kits/petsfriend/PetsFriendKit.java new file mode 100644 index 000000000..085b5a9b0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/petsfriend/PetsFriendKit.java @@ -0,0 +1,531 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.petsfriend; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.DyeColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.Sound; +import org.bukkit.World; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Creature; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.Player; +import org.bukkit.entity.Wolf; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.scheduler.BukkitRunnable; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewEnemySpawnerManager; +import plugily.projects.villagedefense.arena.villager.CompletionCallback; +import plugily.projects.villagedefense.handlers.hologram.ArmorStandHologram; +import plugily.projects.villagedefense.handlers.upgrade.EntityUpgrade; +import plugily.projects.villagedefense.handlers.upgrade.NewEntityUpgradeManager; +import plugily.projects.villagedefense.kits.ChatDisplayable; +import plugily.projects.villagedefense.kits.KitsMenu; +import plugily.projects.villagedefense.kits.ScoreboardModifiable; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; + +/** + * @author Plajer + *

+ * Created at 11.08.2023 + */ +public class PetsFriendKit extends PremiumKit implements AbilitySource, Listener, ChatDisplayable, ScoreboardModifiable { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_PETS_FRIEND_"; + private final List petNames = Arrays.asList("Rex", "Buddy", "Max", "Daisy", "Bailey", "Molly", "Lucy", "Sadie", "Bella", "Maggie", "Chloe", "Sophie", "Lola", "Zoe", "Abby", "Ginger", "Roxy", "Gracie", "Coco", "Sasha", "Angel", "Lily", "Emma", "Annie", "Rosie", "Ruby", "Lady", "Missy", "Katie", "Dixie", "Penny", "Heidi", "Sandy", "Misty", "Holly", "Shelby", "Jasmine", "Sugar", "Honey", "Dakota", "Josie", "Samantha", "Brandy", "Mocha", "Pebbles", "Cinnamon", "Bonnie", "Kelsey", "Casey", "Chelsea", "Muffin", "Sheba", "Fiona", "Duchess", "Pumpkin", "Precious", "Baby", "Sassy", "Minnie", "Mimi", "Lulu", "Cleo", "Jewel", "Princess", "Amber"); + + public PetsFriendKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("PetsFriend"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + getPlugin().getKitRegistry().registerKit(this); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.SUPPORT, this); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0045"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Pets-Friend.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Pets-Friend.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_SPAWNED", new Message("Kit.Content.Pets-Friend.Game-Item.Passive.Wolf-Spawned", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_AGED", new Message("Kit.Content.Pets-Friend.Game-Item.Passive.Wolf-Aged", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "PASSIVE_GOLEM_SPAWNED", new Message("Kit.Content.Pets-Friend.Game-Item.Passive.Golem-Spawned", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_DIED", new Message("Kit.Content.Pets-Friend.Game-Item.Passive.Wolf-Died", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "PASSIVE_GOLEM_DIED", new Message("Kit.Content.Pets-Friend.Game-Item.Passive.Golem-Died", "")); + + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_NAME", new Message("Kit.Content.Pets-Friend.Game-Item.Recall.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_DESCRIPTION", new Message("Kit.Content.Pets-Friend.Game-Item.Recall.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_ACTIVATE", new Message("Kit.Content.Pets-Friend.Game-Item.Recall.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_NO_ALIVE_PETS", new Message("Kit.Content.Pets-Friend.Game-Item.Recall.No-Alive-Pets", "")); + + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_NAME", new Message("Kit.Content.Pets-Friend.Game-Item.Grave-Danger.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_DESCRIPTION", new Message("Kit.Content.Pets-Friend.Game-Item.Grave-Danger.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_ACTIVATE", new Message("Kit.Content.Pets-Friend.Game-Item.Grave-Danger.Activate", "")); + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.petsfriend"); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "petsfriend_recall", "Recall", wave, KitSpecifications.GameTimeState.EARLY), + ScoreboardModifiable.renderAbilityCooldown(user, "petsfriend_gravedanger", "Grave Danger", wave, KitSpecifications.GameTimeState.MID), + "", + "&e&lPETS:", + renderPet(user, arena, 1), + renderPet(user, arena, 2), + renderPet(user, arena, 3), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + private String renderPet(User user, Arena arena, int petNumber) { + if (arena.getWolves().isEmpty()) { + return "&a" + petNumber + ". &7-------------"; + } + int i = 1; + for (Wolf wolf : arena.getWolves()) { + if (wolf.getMetadata("VD_OWNER_UUID").get(0).asString().equals(user.getPlayer().getUniqueId().toString())) { + if (i != petNumber) { + i++; + continue; + } + if (wolf.getMetadata("VD_PET_DEAD").isEmpty()) { + return "&a" + petNumber + ". &f" + NewCreatureUtils.getHealthNameTag(wolf); + } else { + String customName = wolf.getMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA).get(0).asString(); + return "&a" + petNumber + ". &7&m" + customName + "&r &7&lDead"; + } + } + } + return "&a" + petNumber + ". &7-------------"; + } + + @Override + public void giveKitItems(Player player) { + ItemStack itemStack = XMaterial.STONE_SWORD.parseItem(); + ItemMeta meta = itemStack.getItemMeta(); + meta.setUnbreakable(true); + itemStack.setItemMeta(meta); + player.getInventory().addItem(itemStack); + ArmorHelper.setArmor(player, ArmorHelper.ArmorType.LEATHER); + + player.getInventory().setItem(3, new ItemBuilder(new ItemStack(XMaterial.BONE.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_DESCRIPTION")) + .build()); + player.getInventory().setItem(4, new ItemBuilder(new ItemStack(XMaterial.SHEARS.parseMaterial())) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_DESCRIPTION")) + .build()); + + player.getInventory().setItem(5, new ItemStack(Material.SADDLE)); + player.getInventory().setItem(8, new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); + if (arena == null) { + return; + } + spawnWolf(arena, arena.getStartLocation(), player); + } + + private void doGrowWolf(Wolf wolf, Player player) { + for (int i = 0; i < 12; i++) { + final int finalI = i; + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { + if (finalI % 2 == 0) { + wolf.setBaby(); + } else { + wolf.setAdult(); + } + try { + ((Main) getPlugin()).getGlowingEntities().setGlowing(wolf, player, finalI % 2 == 0 ? ChatColor.BLUE : ChatColor.GOLD); + if (finalI == 11) { + ((Main) getPlugin()).getGlowingEntities().unsetGlowing(wolf, player); + wolf.getWorld().spawnParticle(Particle.HEART, wolf.getLocation().clone().add(0, 1, 0), 5, 0.5, 0.25, 0.5, 0); + wolf.getWorld().playSound(wolf.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 1); + + wolf.setAdult(); + wolf.setCustomName(NewCreatureUtils.getHealthNameTag(wolf)); + } + } catch (Exception ignored) { + } + }, i * 5); + } + } + + @Override + public Material getMaterial() { + return Material.BONE; + } + + @Override + public void reStock(Player player) { + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); + KitSpecifications.GameTimeState timeState = KitSpecifications.getTimeState(arena); + int wolfCount = (int) arena.getWolves() + .stream() + .map(wolf -> UUID.fromString(wolf.getMetadata("VD_OWNER_UUID").get(0).asString())) + .filter(uuid -> player.getUniqueId().equals(uuid)) + .count(); + int wave = arena.getWave(); + if (wave == KitSpecifications.GameTimeState.EARLY.getStartWave() + 5 + || wave == KitSpecifications.GameTimeState.MID.getStartWave() + 4 + || wave == KitSpecifications.GameTimeState.LATE.getStartWave() + 3) { + for (Wolf wolf : arena.getWolves()) { + if (wolf.isAdult()) { + continue; + } + if (wolf.getMetadata("VD_OWNER_UUID").get(0).asString().equals(player.getUniqueId().toString())) { + createPathfinderToPlayer(wolf, player, () -> { + doGrowWolf(wolf, player); + }); + } + new MessageBuilder(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_AGED").asKey().player(player).sendPlayer(); + break; + } + } + if (timeState == KitSpecifications.GameTimeState.MID) { + if (wolfCount == 1) { + new MessageBuilder(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_SPAWNED").player(player).prefix().sendPlayer(); + spawnWolf(arena, player.getLocation(), player); + } + int golemCount = (int) arena.getIronGolems() + .stream() + .map(golem -> UUID.fromString(golem.getMetadata("VD_OWNER_UUID").get(0).asString())) + .filter(uuid -> player.getUniqueId().equals(uuid)) + .count(); + if (golemCount == 0) { + new MessageBuilder(LANGUAGE_ACCESSOR + "PASSIVE_GOLEM_SPAWNED").player(player).prefix().sendPlayer(); + arena.spawnGolemForce(player.getLocation(), player); + } + } else if (timeState == KitSpecifications.GameTimeState.LATE) { + if (wolfCount == 2) { + new MessageBuilder(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_SPAWNED").player(player).prefix().sendPlayer(); + spawnWolf(arena, player.getLocation(), player); + } + } + } + + private Wolf spawnWolf(Arena arena, Location location, Player player) { + Wolf wolf = NewCreatureUtils.spawnWolf(location); + wolf.setMetadata("VD_OWNER_UUID", new FixedMetadataValue(getPlugin(), player.getUniqueId().toString())); + wolf.setMetadata("VD_ALIVE_SINCE_WAVE", new FixedMetadataValue(getPlugin(), arena.getWave())); + String name = petNames.get(ThreadLocalRandom.current().nextInt(petNames.size())); + wolf.setMetadata(NewEnemySpawnerManager.CREATURE_CUSTOM_NAME_METADATA, new FixedMetadataValue(getPlugin(), name)); + wolf.setOwner(player); + wolf.setCustomNameVisible(true); + wolf.setBaby(); + wolf.setAgeLock(true); + wolf.setCollarColor(DyeColor.values()[ThreadLocalRandom.current().nextInt(DyeColor.values().length)]); + wolf.setCustomName(NewCreatureUtils.getHealthNameTag(wolf)); + arena.addWolf(wolf); + return wolf; + } + + @EventHandler + public void onPetDeath(EntityDamageEvent event) { + if (event.getEntityType() != EntityType.IRON_GOLEM && event.getEntityType() != EntityType.WOLF) { + return; + } + if (!(event.getEntity() instanceof Creature creature)) { + return; + } + if (creature.getHealth() - event.getDamage() > 0) { + return; + } + + for (Arena arena : ((Main) getPlugin()).getArenaRegistry().getPluginArenas()) { + boolean contains = false; + if (arena.getIronGolems().contains(creature)) { + Player player = Bukkit.getPlayer(UUID.fromString(creature.getMetadata("VD_OWNER_UUID").get(0).asString())); + new MessageBuilder(LANGUAGE_ACCESSOR + "PASSIVE_GOLEM_DIED").asKey().player(player).sendPlayer(); + contains = true; + } else if (arena.getWolves().contains(creature)) { + Player owner = Bukkit.getPlayer(UUID.fromString(creature.getMetadata("VD_OWNER_UUID").get(0).asString())); + new MessageBuilder(LANGUAGE_ACCESSOR + "PASSIVE_WOLF_DIED").asKey().player(owner).sendPlayer(); + contains = true; + } + if (contains) { + NewCreatureUtils.doMarkPetDead(creature); + for (Creature enemy : arena.getEnemies()) { + if (creature.equals(enemy.getTarget())) { + enemy.setTarget(null); + } + } + event.setCancelled(true); + event.setDamage(0); + return; + } + } + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if (!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), PetsFriendKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_NAME").asKey().build())) { + onRecall(stack, user); + } else if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_NAME").asKey().build())) { + onGraveDangerCast(stack, user); + } + } + + private void onRecall(ItemStack stack, User user) { + Arena arena = ((Arena) user.getArena()); + List pets = getAllAlivePets(arena, user); + if (pets.isEmpty()) { + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_NO_ALIVE_PETS").asKey().send(user.getPlayer()); + return; + } + String abilityId = "petsfriend_recall"; + if (!user.checkCanCastCooldownAndMessage(abilityId)) { + return; + } + int cooldown = 10; + user.setCooldown(abilityId, cooldown); + + Player player = user.getPlayer(); + KitHelper.scheduleAbilityCooldown(stack, player, 5, cooldown); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_RECALL_ACTIVATE").asKey().send(user.getPlayer()); + for (Creature pet : pets) { + pet.setTarget(null); + createPathfinderToPlayer(pet, player, () -> { + }); + } + } + + private void createPathfinderToPlayer(Creature pet, Player player, CompletionCallback completionCallback) { + new BukkitRunnable() { + @Override + public void run() { + if (pet.isDead()) { + this.cancel(); + return; + } + if (pet.getLocation().distanceSquared(player.getLocation()) <= 2) { + completionCallback.onComplete(); + this.cancel(); + return; + } + pet.getPathfinder().moveTo(player, 1.75); + } + }.runTaskTimer(getPlugin(), 0, 5); + } + + private void onGraveDangerCast(ItemStack stack, User user) { + String abilityId = "petsfriend_gravedanger"; + if (!user.checkCanCastCooldownAndMessage(abilityId)) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = 140; + user.setCooldown(abilityId, cooldown); + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), cooldown * 20); + + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_GRAVE_DANGER_ACTIVATE").prefix().player(user.getPlayer()).sendPlayer(); + Arena arena = (Arena) user.getArena(); + List pets = getAllAlivePets(arena, user); + for (Creature pet : pets) { + if (pet instanceof Wolf) { + Wolf newWolf = spawnWolf(arena, pet.getLocation(), user.getPlayer()); + copyAllUpgrades(pet, newWolf, user.getPlayer()); + schedulePetRemoval(newWolf, arena); + continue; + } + Creature newGolem = arena.spawnGolemForce(pet.getLocation(), user.getPlayer()); + copyAllUpgrades(pet, newGolem, user.getPlayer()); + schedulePetRemoval(newGolem, arena); + } + } + + private List getAllAlivePets(Arena arena, User user) { + List pets = arena.getWolves() + .stream() + .filter(w -> w.getMetadata("VD_OWNER_UUID").get(0).asString().equals(user.getPlayer().getUniqueId().toString())) + .collect(Collectors.toList()); + pets.addAll( + arena.getIronGolems() + .stream() + .filter(w -> w.getMetadata("VD_OWNER_UUID").get(0).asString().equals(user.getPlayer().getUniqueId().toString())) + .collect(Collectors.toList()) + ); + return pets.stream() + .filter(pet -> !pet.hasMetadata("VD_PET_DEAD")) + .collect(Collectors.toList()); + } + + private void copyAllUpgrades(Creature origin, Creature target, Player owner) { + NewEntityUpgradeManager upgradeManager = ((Main) getPlugin()).getEntityUpgradeManager(); + for (EntityUpgrade upgrade : upgradeManager.getRegisteredUpgrades()) { + if (!origin.hasMetadata(upgrade.getMetadataKey())) { + continue; + } + upgradeManager.applyUpgradeSilent(target, owner, upgrade); + } + } + + private void schedulePetRemoval(Creature pet, Arena arena) { + ArmorStandHologram petHologram = new ArmorStandHologram(pet.getLocation()) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&e&lCLONED PET")); + pet.getWorld().playSound(pet.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 0.75f); + + new BukkitRunnable() { + int tick = 0; + int castTime = (int) Settings.ULTIMATE_GRAVE_DANGER_CAST_TIME.getForArenaState(arena); + boolean toggle = false; + + @Override + public void run() { + if (tick == castTime * 20 || petHologram.isDeleted() || petHologram.getArmorStands().isEmpty()) { + World world = pet.getLocation().getWorld(); + world.spawnParticle(Particle.EXPLOSION_LARGE, pet.getLocation().clone().add(0, 0.5, 0), 1); + world.playSound(pet.getLocation(), Sound.ENTITY_ENDERMAN_TELEPORT, 1, 0.5f); + if (pet instanceof Wolf wolf) { + arena.removeWolf(wolf); + } else { + arena.removeIronGolem((IronGolem) pet); + } + petHologram.delete(); + cancel(); + return; + } + ArmorStand stand = petHologram.getArmorStands().get(0); + if (pet instanceof Wolf) { + stand.teleport(pet.getLocation().clone().add(0, 0.5, 0)); + } else { + stand.teleport(pet.getLocation().clone().add(0, 1.1, 0)); + } + //postpone countdown until wave starts but still teleport moving holograms + if (!arena.isFighting()) { + return; + } + //todo improve modulo here? + int modulo = tick < 100 ? 10 : tick > 350 ? 3 : 5; + if (tick % modulo == 0) { + String message; + if (toggle) { + message = ChatColor.translateAlternateColorCodes('&', "&c&lCLONED PET (" + ((castTime - tick) / 20) + "s)"); + } else { + message = ChatColor.translateAlternateColorCodes('&', "&e&lCLONED PET (" + ((castTime - tick) / 20) + "s)"); + } + toggle = !toggle; + stand.setCustomName(message); + } + tick++; + } + }.runTaskTimer(getPlugin(), 1, 1); + Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { + if (!petHologram.isDeleted()) { + petHologram.delete(); + } + }, /* remove after 20 seconds to prevent staying even if arena is finished */ 20 * 20); + } + + private enum Settings { + ULTIMATE_GRAVE_DANGER_CAST_TIME(0, 10, 15); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/BlockerKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/BlockerKit.java deleted file mode 100644 index f07684de4..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/BlockerKit.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; -import plugily.projects.minigamesbox.classic.arena.PluginArena; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; - -import java.util.List; - -/** - * Created by Tom on 17/12/2015. - */ -public class BlockerKit extends PremiumKit implements Listener { - - public BlockerKit() { - setName(new MessageBuilder("KIT_CONTENT_BLOCKER_NAME").asKey().build()); - setKey("Blocker"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_BLOCKER_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.blocker"); - } - - @Override - public void giveKitItems(Player player) { - ArmorHelper.setColouredArmor(Color.RED, player); - player.getInventory().addItem(WeaponHelper.getEnchanted(new ItemStack(Material.STONE_SWORD), new org.bukkit.enchantments.Enchantment[]{org.bukkit.enchantments.Enchantment.DURABILITY}, new int[]{10})); - player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 10)); - player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.OAK_FENCE.parseMaterial(), 3)) - .name(new MessageBuilder("KIT_CONTENT_BLOCKER_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_BLOCKER_GAME_ITEM_DESCRIPTION")) - .build()); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - - } - - @Override - public Material getMaterial() { - return Material.BARRIER; - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.OAK_FENCE.parseMaterial(), 3)) - .name(new MessageBuilder("KIT_CONTENT_BLOCKER_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_BLOCKER_GAME_ITEM_DESCRIPTION")) - .build()); - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onBarrierPlace(PlugilyPlayerInteractEvent event) { - if(event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) { - return; - } - - Player player = event.getPlayer(); - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); - if(arena == null) - return; - - ItemStack stack = VersionUtils.getItemInHand(player); - if(!ItemUtils.isItemStackNamed(stack) || !ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()) - .equalsIgnoreCase(new MessageBuilder("KIT_CONTENT_BLOCKER_GAME_ITEM_NAME").asKey().build())) { - return; - } - if(!(getPlugin().getUserManager().getUser(player).getKit() instanceof BlockerKit)) { - return; - } - Block block = null; - for(Block blocks : player.getLastTwoTargetBlocks(null, 5)) { - if(blocks.getType() == Material.AIR) { - block = blocks; - } - } - if(block == null) { - new MessageBuilder("KIT_CONTENT_BLOCKER_PLACE_FAIL").asKey().player(player).sendPlayer(); - return; - } - getPlugin().getBukkitHelper().takeOneItem(player, stack); - event.setCancelled(false); - - new MessageBuilder("KIT_CONTENT_BLOCKER_PLACE_SUCCESS").asKey().player(player).sendPlayer(); - ZombieBarrier zombieBarrier = new ZombieBarrier(); - zombieBarrier.setLocation(block.getLocation()); - - VersionUtils.sendParticles("FIREWORKS_SPARK", arena.getPlayers(), zombieBarrier.location, 20); - removeBarrierLater(zombieBarrier, arena); - block.setType(XMaterial.OAK_FENCE.parseMaterial()); - } - - private void removeBarrierLater(ZombieBarrier zombieBarrier, PluginArena arena) { - new BukkitRunnable() { - @Override - public void run() { - zombieBarrier.decrementSeconds(); - - if(zombieBarrier.seconds <= 0) { - zombieBarrier.location.getBlock().setType(Material.AIR); - VersionUtils.sendParticles("FIREWORKS_SPARK", arena.getPlayers(), zombieBarrier.location, 20); - cancel(); - } - } - }.runTaskTimer(getPlugin(), 20, 20); - } - - private static class ZombieBarrier { - private Location location; - private int seconds = 10; - - void setLocation(Location location) { - this.location = location; - } - - void decrementSeconds() { - seconds--; - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/CleanerKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/CleanerKit.java deleted file mode 100644 index 3b5432be8..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/CleanerKit.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.villagedefense.arena.Arena; -import plugily.projects.villagedefense.arena.ArenaUtils; - -import java.util.List; - -/** - * Created by Tom on 18/08/2014. - */ -public class CleanerKit extends PremiumKit implements Listener { - - public CleanerKit() { - setName(new MessageBuilder("KIT_CONTENT_CLEANER_NAME").asKey().build()); - setKey("Cleaner"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_CLEANER_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.cleaner"); - } - - @Override - public void giveKitItems(Player player) { - ArmorHelper.setColouredArmor(Color.YELLOW, player); - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.WOOD, 10)); - player.getInventory().addItem(new ItemBuilder(Material.BLAZE_ROD) - .name(new MessageBuilder("KIT_CONTENT_CLEANER_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_CLEANER_GAME_ITEM_DESCRIPTION")) - .build()); - player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 10)); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - } - - @Override - public Material getMaterial() { - return Material.BLAZE_POWDER; - } - - @Override - public void reStock(Player player) { - } - - @EventHandler - public void onClean(PlugilyPlayerInteractEvent event) { - ItemStack itemStack = event.getItem(); - if(itemStack == null || itemStack.getType() != Material.BLAZE_ROD) - return; - - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(event.getPlayer()); - if(arena == null || !ItemUtils.isItemStackNamed(itemStack) - || !ComplementAccessor.getComplement().getDisplayName(itemStack.getItemMeta()) - .contains(new MessageBuilder("KIT_CONTENT_CLEANER_GAME_ITEM_NAME").asKey().build())) { - return; - } - User user = getPlugin().getUserManager().getUser(event.getPlayer()); - if(!(user.getKit() instanceof CleanerKit)) { - return; - } - if(user.isSpectator()) { - new MessageBuilder("IN_GAME_SPECTATOR_SPECTATOR_WARNING").asKey().player(user.getPlayer()).sendPlayer(); - return; - } - double cooldown = user.getCooldown("clean"); - if(cooldown > 0 && !user.isSpectator()) { - new MessageBuilder("KIT_COOLDOWN").asKey().integer((int) cooldown).player(user.getPlayer()).sendPlayer(); - return; - } - if(arena.getEnemies().isEmpty()) { - new MessageBuilder("KIT_CONTENT_CLEANER_CLEANED_NOTHING").asKey().player(user.getPlayer()).sendPlayer(); - return; - } - int amount = getKitsConfig().getInt("Kit-Settings.Cleaner.Base-Amount", 10); - if(amount < arena.getEnemies().size()) { - int increaseUnit = arena.getWave() / Math.max(1, getKitsConfig().getInt("Kit-Settings.Cleaner.Increase-After-Wave", 5)); - amount += increaseUnit * Math.max(0, getKitsConfig().getInt("Kit-Settings.Cleaner.Increase-Amount", 5)); - amount = Math.min(amount, getKitsConfig().getInt("Kit-Settings.Cleaner.Max-Amount", 50)); - } - ArenaUtils.removeSpawnedEnemies(arena, amount, getKitsConfig().getDouble("Kit-Settings.Cleaner.Max-Health", 2048)); - - VersionUtils.playSound(event.getPlayer().getLocation(), "ENTITY_ZOMBIE_DEATH"); - new MessageBuilder("KIT_CONTENT_CLEANER_CLEANED_MAP").asKey().arena(arena).player(user.getPlayer()).sendArena(); - user.setCooldown("clean", getKitsConfig().getInt("Kit-Cooldown.Cleaner", 60)); - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/DogFriendKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/DogFriendKit.java deleted file mode 100644 index 6a2bdf124..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/DogFriendKit.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.arena.Arena; - -import java.util.List; - -/** - * Created by Tom on 18/07/2015. - */ -public class DogFriendKit extends PremiumKit { - - public DogFriendKit() { - setName(new MessageBuilder("KIT_CONTENT_DOG_FRIEND_NAME").asKey().build()); - setKey("DogFriend"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_DOG_FRIEND_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.dogfriend"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - ArmorHelper.setArmor(player, ArmorHelper.ArmorType.LEATHER); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); - if(arena == null) { - return; - } - org.bukkit.Location start = arena.getStartLocation(); - for(int i = 0; i < 3; i++) { - arena.spawnWolf(start, player); - } - } - - @Override - public Material getMaterial() { - return Material.BONE; - } - - @Override - public void reStock(Player player) { - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); - if(arena != null) { - arena.spawnWolf(arena.getStartLocation(), player); - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/HeavyTankKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/HeavyTankKit.java deleted file mode 100644 index 348dceb43..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/HeavyTankKit.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 19/08/2014. - */ -public class HeavyTankKit extends PremiumKit { - - public HeavyTankKit() { - setName(new MessageBuilder("KIT_CONTENT_HEAVY_TANK_NAME").asKey().build()); - setKey("HeavyTank"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_HEAVY_TANK_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.heavytank"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getEnchanted(new ItemStack(Material.STICK), new Enchantment[]{Enchantment.DURABILITY, Enchantment.DAMAGE_ALL}, new int[]{10, 2})); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - VersionUtils.setMaxHealth(player, 40.0); - player.setHealth(40.0); - ArmorHelper.setArmor(player, ArmorHelper.ArmorType.IRON); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - } - - @Override - public Material getMaterial() { - return Material.DIAMOND_CHESTPLATE; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/MedicKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/MedicKit.java deleted file mode 100644 index ea4864be2..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/MedicKit.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -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.EntityDamageByEntityEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.List; - -/** - * Created by Tom on 1/12/2015. - */ -public class MedicKit extends PremiumKit implements Listener { - - public MedicKit() { - setName(new MessageBuilder("KIT_CONTENT_MEDIC_NAME").asKey().build()); - setKey("Medic"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_MEDIC_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.medic"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - ArmorHelper.setColouredArmor(Color.WHITE, player); - player.getInventory().addItem(new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); - player.getInventory().addItem(VersionUtils.getPotion(PotionType.REGEN, 1, true)); - } - - @Override - public Material getMaterial() { - return Material.GHAST_TEAR; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } - - @EventHandler - public void onCreatureHit(EntityDamageByEntityEvent e) { - if(!(e.getEntity() instanceof Creature) || !(e.getDamager() instanceof Player)) { - return; - } - User user = getPlugin().getUserManager().getUser((Player) e.getDamager()); - if(!(user.getKit() instanceof MedicKit) || Math.random() > 0.1) { - return; - } - healNearbyPlayers(e.getDamager()); - } - - private void healNearbyPlayers(Entity en) { - for(Entity entity : en.getNearbyEntities(5, 5, 5)) { - if(!(entity instanceof Player)) { - continue; - } - - Player player = (Player) entity; - double newHealth = player.getHealth() + 1; - double maxHealth = VersionUtils.getMaxHealth(player); - - if(maxHealth > newHealth) { - player.setHealth(newHealth); - } else { - player.setHealth(maxHealth); - } - - VersionUtils.sendParticles("HEART", player, player.getLocation(), 20); - } - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/NakedKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/NakedKit.java deleted file mode 100644 index fec96bd69..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/NakedKit.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionType; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Created by Tom on 8/02/2015. - */ -public class NakedKit extends PremiumKit implements Listener { - - private final List armorTypes = new ArrayList<>(); - - public NakedKit() { - setName(new MessageBuilder("KIT_CONTENT_WILD_NAKED_NAME").asKey().build()); - setKey("Naked"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_WILD_NAKED_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - setupArmorTypes(); - } - - private void setupArmorTypes() { - armorTypes.addAll(Arrays.asList( - Material.LEATHER_BOOTS, Material.LEATHER_CHESTPLATE, Material.LEATHER_LEGGINGS, Material.LEATHER_HELMET, - XMaterial.GOLDEN_BOOTS.parseMaterial(), XMaterial.GOLDEN_CHESTPLATE.parseMaterial(), XMaterial.GOLDEN_LEGGINGS.parseMaterial(), XMaterial.GOLDEN_HELMET.parseMaterial(), - Material.DIAMOND_BOOTS, Material.DIAMOND_LEGGINGS, Material.DIAMOND_CHESTPLATE, Material.DIAMOND_HELMET, - Material.IRON_CHESTPLATE, Material.IRON_BOOTS, Material.IRON_HELMET, Material.IRON_LEGGINGS, - Material.CHAINMAIL_BOOTS, Material.CHAINMAIL_LEGGINGS, Material.CHAINMAIL_CHESTPLATE, Material.CHAINMAIL_HELMET) - ); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return player.hasPermission("villagedefense.kit.naked") || getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player); - } - - @Override - public void giveKitItems(Player player) { - ItemStack itemStack = new ItemStack(getMaterial()); - itemStack.addUnsafeEnchantment(Enchantment.DAMAGE_ALL, 6); - itemStack.addUnsafeEnchantment(Enchantment.DAMAGE_UNDEAD, 2); - itemStack.addUnsafeEnchantment(Enchantment.DURABILITY, 10); - player.getInventory().addItem(itemStack); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - } - - @Override - public Material getMaterial() { - return Material.IRON_SWORD; - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(VersionUtils.getPotion(PotionType.INSTANT_HEAL, 1, true)); - } - - @EventHandler - public void onArmor(InventoryClickEvent event) { - if(!(event.getWhoClicked() instanceof Player)) { - return; - } - Player who = (Player) event.getWhoClicked(); - if(!getPlugin().getArenaRegistry().isInArena(who)) { - return; - } - if(!(getPlugin().getUserManager().getUser(who).getKit() instanceof NakedKit)) { - return; - } - ClickType clickType = event.getClick(); - if(clickType == ClickType.DROP || clickType == ClickType.CONTROL_DROP) { - return; - } - Inventory inventory = event.getClickedInventory(); - if(inventory == null || inventory.getType() != InventoryType.PLAYER) { - return; - } - - boolean hasArmor = false; - ItemStack itemStack = event.getCurrentItem(); - if(itemStack != null && armorTypes.contains(itemStack.getType())) { - hasArmor = true; - } else if(clickType == ClickType.NUMBER_KEY) { - ItemStack hotbarItem = who.getInventory().getItem(event.getHotbarButton()); - if(hotbarItem != null && armorTypes.contains(hotbarItem.getType())) { - hasArmor = true; - } - } - if(hasArmor) { - new MessageBuilder("KIT_CONTENT_WILD_NAKED_CANNOT_WEAR_ARMOR").asKey().send(who); - event.setCancelled(true); - } - } - - @EventHandler - public void onArmorClick(PlugilyPlayerInteractEvent event) { - if(!getPlugin().getArenaRegistry().isInArena(event.getPlayer())) { - return; - } - if(!(getPlugin().getUserManager().getUser(event.getPlayer()).getKit() instanceof NakedKit) || !event.hasItem()) { - return; - } - if(armorTypes.contains(event.getItem().getType())) { - event.setCancelled(true); - new MessageBuilder("KIT_CONTENT_WILD_NAKED_CANNOT_WEAR_ARMOR").asKey().player(event.getPlayer()).sendPlayer(); - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/PremiumHardcoreKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/PremiumHardcoreKit.java deleted file mode 100644 index b2fc89699..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/PremiumHardcoreKit.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; - -import java.util.List; - -/** - * Created by Tom on 28/07/2015. - */ -public class PremiumHardcoreKit extends PremiumKit { - - public PremiumHardcoreKit() { - setName(new MessageBuilder("KIT_CONTENT_PREMIUM_HARDCORE_NAME").asKey().build()); - setKey("PremiumHardcore"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_PREMIUM_HARDCORE_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.premiumhardcore"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getEnchanted(new ItemStack(getMaterial()), - new Enchantment[]{Enchantment.DAMAGE_ALL}, new int[]{11})); - VersionUtils.setMaxHealth(player, 6); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - } - - @Override - public Material getMaterial() { - return Material.DIAMOND_SWORD; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } - - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/ShotBowKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/ShotBowKit.java deleted file mode 100644 index e545a36f9..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/ShotBowKit.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Arrow; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.inventory.ItemStack; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; - -import java.util.List; - - -/** - * Created by Tom on 27/08/2014. - */ -public class ShotBowKit extends PremiumKit implements Listener { - - public ShotBowKit() { - setName(new MessageBuilder("KIT_CONTENT_SHOT_BOW_NAME").asKey().build()); - setKey("ShotBow"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_SHOT_BOW_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.shotbow"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(WeaponHelper.getEnchantedBow(new Enchantment[]{Enchantment.DURABILITY, Enchantment.ARROW_KNOCKBACK}, new int[]{10, 1})); - player.getInventory().addItem(new ItemStack(getMaterial(), 64)); - player.getInventory().addItem(new ItemStack(getMaterial(), 64)); - ArmorHelper.setColouredArmor(Color.YELLOW, player); - player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 8)); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - } - - @Override - public Material getMaterial() { - return Material.ARROW; - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(new ItemStack(getMaterial(), 64)); - } - - @EventHandler - public void onBowInteract(PlugilyPlayerInteractEvent e) { - if(!(e.getAction() == Action.LEFT_CLICK_AIR || e.getAction() == Action.LEFT_CLICK_BLOCK || e.getAction() == Action.PHYSICAL)) { - return; - } - - ItemStack stack = VersionUtils.getItemInHand(e.getPlayer()); - if(stack == null || stack.getType() != Material.BOW) - return; - - if(!e.getPlayer().getInventory().contains(getMaterial())) - return; - - User user = getPlugin().getUserManager().getUser(e.getPlayer()); - if(user.isSpectator() || !(user.getKit() instanceof ShotBowKit)) { - return; - } - if(!user.checkCanCastCooldownAndMessage("shotbow")) { - return; - } - for(int i = 0; i < 4; i++) { - Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { - Arrow pr = e.getPlayer().launchProjectile(Arrow.class); - pr.setVelocity(e.getPlayer().getLocation().getDirection().multiply(3)); - pr.setBounce(false); - pr.setShooter(e.getPlayer()); - pr.setCritical(true); - - org.bukkit.inventory.PlayerInventory inv = e.getPlayer().getInventory(); - - if(inv.contains(getMaterial())) { - inv.removeItem(new ItemStack(getMaterial(), 1)); - } - }, 2L * (2 * i)); - } - e.setCancelled(true); - user.setCooldown("shotbow", getKitsConfig().getInt("Kit-Cooldown.Shot-Bow", 5)); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/TeleporterKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/TeleporterKit.java deleted file mode 100644 index 4da48fe44..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/TeleporterKit.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.entity.Villager; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.SkullMeta; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.minigamesbox.inventory.normal.NormalFastInv; -import plugily.projects.villagedefense.arena.Arena; - -import java.util.Collections; -import java.util.List; - -/** - * Created by Tom on 18/08/2014. - */ -public class TeleporterKit extends PremiumKit implements Listener { - - public TeleporterKit() { - setName(new MessageBuilder("KIT_CONTENT_TELEPORTER_NAME").asKey().build()); - setKey("Teleporter"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_TELEPORTER_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.teleporter"); - } - - @Override - public void giveKitItems(Player player) { - ArmorHelper.setArmor(player, ArmorHelper.ArmorType.GOLD); - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - - player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 10)); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - player.getInventory().addItem(new ItemBuilder(Material.GHAST_TEAR) - .name(new MessageBuilder("KIT_CONTENT_TELEPORTER_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_TELEPORTER_GAME_ITEM_DESCRIPTION")) - .build()); - } - - @Override - public Material getMaterial() { - return Material.ENDER_PEARL; - } - - @Override - public void reStock(Player player) { - //no restock items for this kit - } - - @EventHandler - public void onRightClick(PlugilyPlayerInteractEvent e) { - if(!(e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK)) { - return; - } - Player player = e.getPlayer(); - Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); - if(arena == null) { - return; - } - - ItemStack stack = VersionUtils.getItemInHand(player); - if(!ItemUtils.isItemStackNamed(stack)) - return; - - if(!ChatColor.stripColor(ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta())).equalsIgnoreCase(ChatColor.stripColor(new MessageBuilder("KIT_CONTENT_TELEPORTER_GAME_ITEM_NAME").asKey().build()))) { - return; - } - if(!(getPlugin().getUserManager().getUser(player).getKit() instanceof TeleporterKit)) { - return; - } - int slots = arena.getVillagers().size(); - for(Player arenaPlayer : arena.getPlayers()) { - if(getPlugin().getUserManager().getUser(arenaPlayer).isSpectator()) { - continue; - } - slots++; - } - slots = getPlugin().getBukkitHelper().serializeInt(slots); - prepareTeleporterGui(player, arena, slots); - } - - private void prepareTeleporterGui(Player player, Arena arena, int slots) { - NormalFastInv gui = new NormalFastInv(slots, new MessageBuilder("KIT_CONTENT_TELEPORTER_GAME_ITEM_GUI").asKey().build()); - gui.addClickHandler(inventoryClickEvent -> inventoryClickEvent.setCancelled(true)); - for(Player arenaPlayer : arena.getPlayers()) { - if(getPlugin().getUserManager().getUser(arenaPlayer).isSpectator()) { - continue; - } - ItemStack skull = XMaterial.PLAYER_HEAD.parseItem(); - SkullMeta meta = (SkullMeta) skull.getItemMeta(); - meta = VersionUtils.setPlayerHead(player, meta); - ComplementAccessor.getComplement().setDisplayName(meta, arenaPlayer.getName()); - ComplementAccessor.getComplement().setLore(meta, Collections.singletonList("")); - skull.setItemMeta(meta); - gui.addItem(skull, onClick -> { - new MessageBuilder("KIT_CONTENT_TELEPORTER_TELEPORT_PLAYER").asKey().arena(arena).player(arenaPlayer).sendPlayer(); - VersionUtils.teleport(player, arenaPlayer.getLocation()); - VersionUtils.playSound(player.getLocation(), "ENTITY_ENDERMAN_TELEPORT"); - VersionUtils.sendParticles("PORTAL", arena.getPlayers(), player.getLocation(), 30); - player.closeInventory(); - }); - } - for(Villager villager : arena.getVillagers()) { - gui.addItem(new ItemBuilder(new ItemStack(Material.EMERALD)) - .name(villager.getCustomName()) - .lore(villager.getUniqueId().toString()) - .build(), onClick -> { - VersionUtils.teleport(player, villager.getLocation()); - VersionUtils.playSound(player.getLocation(), "ENTITY_ENDERMAN_TELEPORT"); - VersionUtils.sendParticles("PORTAL", arena.getPlayers(), player.getLocation(), 30); - new MessageBuilder("KIT_CONTENT_TELEPORTER_TELEPORT_VILLAGER").asKey().player(player).sendPlayer(); - }); - } - gui.open(player); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/TornadoKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/TornadoKit.java deleted file mode 100644 index 2cd6341da..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/TornadoKit.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Location; -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.block.Action; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.helper.WeaponHelper; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -import java.util.List; - -/** - * Created by Tom on 30/12/2015. - */ -public class TornadoKit extends PremiumKit implements Listener { - - private final int maxHeight = 5; - private final double maxRadius = 4; - private final double radiusIncrement = maxRadius / maxHeight; - private int active = 0; - - public TornadoKit() { - setName(new MessageBuilder("KIT_CONTENT_TORNADO_NAME").asKey().build()); - setKey("Tornado"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_TORNADO_DESCRIPTION"); - setDescription(description); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - getPlugin().getKitRegistry().registerKit(this); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return player.hasPermission("villagedefense.kit.tornado") || getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player); - } - - @Override - public void giveKitItems(Player player) { - ArmorHelper.setArmor(player, ArmorHelper.ArmorType.GOLD); - player.getInventory().addItem(WeaponHelper.getUnBreakingSword(WeaponHelper.ResourceType.STONE, 10)); - - player.getInventory().addItem(new ItemStack(Material.COOKED_BEEF, 10)); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - player.getInventory().addItem(new ItemBuilder(new ItemStack(getMaterial(), 5)) - .name(new MessageBuilder("KIT_CONTENT_TORNADO_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_TORNADO_GAME_ITEM_DESCRIPTION")) - .build()); - } - - @Override - public Material getMaterial() { - return XMaterial.COBWEB.parseMaterial(); - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(new ItemBuilder(new ItemStack(getMaterial(), 5)) - .name(new MessageBuilder("KIT_CONTENT_TORNADO_GAME_ITEM_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_TORNADO_GAME_ITEM_DESCRIPTION")) - .build()); - } - - @EventHandler - public void onTornadoSpawn(PlugilyPlayerInteractEvent e) { - if(e.getAction() != Action.RIGHT_CLICK_AIR && e.getAction() != Action.RIGHT_CLICK_BLOCK) { - return; - } - - Player player = e.getPlayer(); - if(!getPlugin().getArenaRegistry().isInArena(player)) - return; - - ItemStack stack = VersionUtils.getItemInHand(player); - if(!ItemUtils.isItemStackNamed(stack) - || !ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()).equalsIgnoreCase(new MessageBuilder("KIT_CONTENT_TORNADO_GAME_ITEM_NAME").asKey().build())) { - return; - } - if(!(getPlugin().getUserManager().getUser(player).getKit() instanceof TornadoKit)) { - return; - } - if(active >= 2) { - return; - } - getPlugin().getBukkitHelper().takeOneItem(player, stack); - e.setCancelled(true); - prepareTornado(player.getLocation()); - } - - private void prepareTornado(Location location) { - Tornado tornado = new Tornado(location); - active++; - new BukkitRunnable() { - @Override - public void run() { - tornado.update(); - if(tornado.entities >= 7 || tornado.times > 55) { - cancel(); - active--; - } - } - }.runTaskTimer(getPlugin(), 1, 1); - } - - private class Tornado { - private Location location; - private final Vector vector; - private int angle; - private int times = 0; - private int entities = 0; - - Tornado(Location location) { - this.location = location; - vector = location.getDirection(); - } - - void setLocation(Location location) { - this.location = location; - } - - void update() { - times++; - int lines = 3; - for(int l = 0; l < lines; l++) { - for(double y = 0; y < maxHeight; y += 0.5) { - double radius = y * radiusIncrement, - radians = Math.toRadians(360.0 / lines * l + y * 25 - angle), - x = Math.cos(radians) * radius, - z = Math.sin(radians) * radius; - VersionUtils.sendParticles("CLOUD", null, location.clone().add(x, y, z), 1, 0, 0, 0); - } - } - pushNearbyEnemies(); - setLocation(location.add(vector.getX() / (3 + Math.random() / 2), 0, vector.getZ() / (3 + Math.random() / 2))); - - angle += 50; - } - - private void pushNearbyEnemies() { - for(Entity entity : location.getWorld().getNearbyEntities(location, 2, 2, 2)) { - if(CreatureUtils.isEnemy(entity)) { - entities++; - - Vector velocityVec = vector.multiply(2).setY(0).add(new Vector(0, 1, 0)); - if(VersionUtils.isPaper() && (vector.getX() > 4.0 || vector.getZ() > 4.0)) { - velocityVec = vector.setX(2.0).setZ(1.0); // Paper's sh*t - } - - entity.setVelocity(velocityVec); - } - } - } - } -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/premium/WizardKit.java b/src/main/java/plugily/projects/villagedefense/kits/premium/WizardKit.java deleted file mode 100644 index 55fb0cc30..000000000 --- a/src/main/java/plugily/projects/villagedefense/kits/premium/WizardKit.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package plugily.projects.villagedefense.kits.premium; - -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; -import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; -import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; -import plugily.projects.minigamesbox.classic.user.User; -import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; -import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; -import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; -import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; -import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; -import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; -import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; -import plugily.projects.villagedefense.creatures.CreatureUtils; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Plajer - *

- * Created at 01.03.2018 - */ -public class WizardKit extends PremiumKit implements Listener { - - private final List wizardsOnDuty = new ArrayList<>(); - - public WizardKit() { - setName(new MessageBuilder("KIT_CONTENT_WIZARD_NAME").asKey().build()); - setKey("Wizard"); - List description = getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_WIZARD_DESCRIPTION"); - setDescription(description); - getPlugin().getKitRegistry().registerKit(this); - getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); - } - - @Override - public boolean isUnlockedByPlayer(Player player) { - return getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player) || player.hasPermission("villagedefense.kit.wizard"); - } - - @Override - public void giveKitItems(Player player) { - player.getInventory().addItem(new ItemBuilder(getMaterial()) - .name(new MessageBuilder("KIT_CONTENT_WIZARD_GAME_ITEM_WAND_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_WIZARD_GAME_ITEM_WAND_DESCRIPTION")) - .build()); - player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.INK_SAC.parseMaterial(), 4)) - .name(new MessageBuilder("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_DESCRIPTION")) - .build()); - - ArmorHelper.setColouredArmor(Color.GRAY, player); - player.getInventory().addItem(new ItemStack(Material.SADDLE)); - - } - - @Override - public Material getMaterial() { - return Material.BLAZE_ROD; - } - - @Override - public void reStock(Player player) { - player.getInventory().addItem(new ItemBuilder(new ItemStack(XMaterial.INK_SAC.parseMaterial())) - .name(new MessageBuilder("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_NAME").asKey().build()) - .lore(getPlugin().getLanguageManager().getLanguageListFromKey("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_DESCRIPTION")) - .build()); - } - - @EventHandler - public void onQuit(PlayerQuitEvent e) { - wizardsOnDuty.remove(e.getPlayer()); - } - - @EventHandler - public void onWizardDamage(EntityDamageByEntityEvent event) { - if(!(event.getDamager() instanceof Creature && event.getEntity() instanceof Player)) { - return; - } - if(!wizardsOnDuty.contains(event.getEntity()) || getPlugin().getArenaRegistry().getArena((Player) event.getEntity()) == null) { - return; - } - ((Creature) event.getDamager()).damage(2.0, event.getEntity()); - } - - @EventHandler - public void onStaffUse(PlugilyPlayerInteractEvent event) { - if(getPlugin().getArenaRegistry().getArena(event.getPlayer()) == null) { - return; - } - - User user = getPlugin().getUserManager().getUser(event.getPlayer()); - if(user.isSpectator() || !(user.getKit() instanceof WizardKit)) { - return; - } - - ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); - if(!ItemUtils.isItemStackNamed(stack)) { - return; - } - Player player = event.getPlayer(); - if(ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()).equals(new MessageBuilder("KIT_CONTENT_WIZARD_GAME_ITEM_ESSENCE_NAME").asKey().build())) { - if(!user.checkCanCastCooldownAndMessage("essence")) { - return; - } - wizardsOnDuty.add(player); - if(VersionUtils.getMaxHealth(player) > (player.getHealth() + 3)) { - player.setHealth(player.getHealth() + 3); - } else { - player.setHealth(VersionUtils.getMaxHealth(player)); - } - getPlugin().getBukkitHelper().takeOneItem(player, stack); - VersionUtils.setGlowing(player, true); - applyRageParticles(player); - for(Entity entity : player.getNearbyEntities(2, 2, 2)) { - if(CreatureUtils.isEnemy(entity)) { - ((Creature) entity).damage(9.0, player); - } - } - Bukkit.getScheduler().runTaskLater(getPlugin(), () -> { - VersionUtils.setGlowing(player, false); - wizardsOnDuty.remove(player); - }, 20L * 15); - user.setCooldown("essence", getKitsConfig().getInt("Kit-Cooldown.Wizard.Essence", 15)); - } else if(ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()).equals(new MessageBuilder("KIT_CONTENT_WIZARD_GAME_ITEM_WAND_NAME").asKey().build())) { - if(!user.checkCanCastCooldownAndMessage("wizard_staff")) { - return; - } - applyMagicAttack(player); - user.setCooldown("wizard_staff", getKitsConfig().getInt("Kit-Cooldown.Wizard.Staff", 1)); - } - } - - private void applyRageParticles(Player player) { - new BukkitRunnable() { - @Override - public void run() { - Location loc = player.getLocation(); - loc.add(0, 0.8, 0); - VersionUtils.sendParticles("VILLAGER_ANGRY", null, loc, 5, 0, 0, 0); - if(!wizardsOnDuty.contains(player) || !getPlugin().getArenaRegistry().isInArena(player)) { - cancel(); - } - } - }.runTaskTimer(getPlugin(), 0, 2); - } - - private void applyMagicAttack(Player player) { - new BukkitRunnable() { - double positionModifier = 0; - final Location loc = player.getLocation(); - final Vector direction = loc.getDirection().normalize(); - - @Override - public void run() { - positionModifier += 0.5; - double x = direction.getX() * positionModifier, - y = direction.getY() * positionModifier + 1.5, - z = direction.getZ() * positionModifier; - loc.add(x, y, z); - VersionUtils.sendParticles("TOWN_AURA", null, loc, 5, 0, 0, 0); - for(Entity en : loc.getChunk().getEntities()) { - if(!(CreatureUtils.isEnemy(en)) || en.getLocation().distance(loc) >= 1.5 || en.equals(player)) { - continue; - } - ((LivingEntity) en).damage(6.0, player); - VersionUtils.sendParticles("FIREWORKS_SPARK", null, en.getLocation(), 2, 0.5, 0.5, 0.5); - } - loc.subtract(x, y, z); - if(positionModifier > 40) { - cancel(); - } - } - }.runTaskTimer(getPlugin(), 0, 1); - } - -} diff --git a/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugment.java b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugment.java new file mode 100644 index 000000000..f15e60379 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugment.java @@ -0,0 +1,48 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.terminator; + +import org.bukkit.inventory.ItemStack; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public record TerminatorAugment(String id, ItemStack icon, String name, List lore, AugmentType type, KitSpecifications.GameTimeState appliesFrom, + Function synergyApplies, Consumer onApply) { + + public static final String AUGMENTS_COUNT_METADATA_KEY = "VD_TERMINATOR_AUGMENTS_COUNT"; + public static final String METADATA_KEY = "VD_TERMINATOR_AUGMENT_"; + /** + * Augment is always applicable no matter the environment + */ + public static final Function CONSTANT_SYNERGY = (arena) -> true; + + public String getMetadataKey() { + return METADATA_KEY + id; + } + + public enum AugmentType { + BLADE, SYSTEM, SYNERGY + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugmentRegistry.java b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugmentRegistry.java new file mode 100644 index 000000000..6f126fe43 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugmentRegistry.java @@ -0,0 +1,245 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.terminator; + +import lombok.Getter; +import org.bukkit.ChatColor; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.metadata.FixedMetadataValue; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.kits.CleanerKit; +import plugily.projects.villagedefense.kits.CrusaderKit; +import plugily.projects.villagedefense.kits.MedicKit; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.List; + +public class TerminatorAugmentRegistry { + + private static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_TERMINATOR_"; + private final static @Getter List augments = new ArrayList<>(); + private static Main plugin; + + public static void init(Main plugin) { + TerminatorAugmentRegistry.plugin = plugin; + registerAugments(); + } + + private static void registerAugments() { + augments.add(new TerminatorAugment( + "SHARPNESS", + new ItemBuilder(XMaterial.IRON_SWORD.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&6&lBLADE AUGMENT: &e&lSHARPNESS"), + colorLore("&6&lBLADE OF TERMINUS&7 receives", "&7Sharpness I enchantment"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.EARLY, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "SHARPNESS", new FixedMetadataValue(plugin, true)); + for (ItemStack itemStack : user.getPlayer().getInventory()) { + if (itemStack == null || !itemStack.hasItemMeta()) { + continue; + } + if (!itemStack.getItemMeta().getDisplayName().equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_NAME").asKey().build())) { + continue; + } + ItemMeta meta = itemStack.getItemMeta(); + meta.addEnchant(Enchantment.DAMAGE_ALL, 1, true); + itemStack.setItemMeta(meta); + } + } + )); + augments.add(new TerminatorAugment( + "VITALITY", + new ItemBuilder(XMaterial.LEATHER_BOOTS.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&c&lSYSTEM AUGMENT: &e&lVITALITY"), + colorLore("&7Earn brief burst of speed", "&7every 5/4/3 zombies killed"), + TerminatorAugment.AugmentType.SYSTEM, + KitSpecifications.GameTimeState.EARLY, + TerminatorAugment.CONSTANT_SYNERGY, + user -> user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "VITALITY", new FixedMetadataValue(plugin, 0)) + )); + augments.add(new TerminatorAugment( + "ADAPTIVE_SHIELDS", + new ItemBuilder(XMaterial.TNT_MINECART.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&c&lSYSTEM AUGMENT: &e&lADAPTIVE SHIELDS"), + colorLore("&7Receive permanent 25/30/35% blast resistance"), + TerminatorAugment.AugmentType.SYSTEM, + KitSpecifications.GameTimeState.EARLY, + TerminatorAugment.CONSTANT_SYNERGY, + user -> user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "ADAPTIVE_SHIELDS", new FixedMetadataValue(plugin, true)) + )); + augments.add(new TerminatorAugment( + "STEADY_SCALING", + new ItemBuilder(XMaterial.GOLDEN_SWORD.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&6&lBLADE AUGMENT: &e&lSTEADY SCALING"), + colorLore("&7Increase &6&lBLADE OF TERMINUS&7 damage", "&7 by 1% every 50 enemies killed", "&7capped at 30%"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.EARLY, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "STEADY_SCALING", new FixedMetadataValue(plugin, 0)); + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "STEADY_SCALING_COUNT", new FixedMetadataValue(plugin, 0)); + } + )); + augments.add(new TerminatorAugment( + "EXPANDED_AID", + new ItemBuilder(XMaterial.HONEY_BOTTLE.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&b&lSYNERGY AUGMENT: &e&lEXPANDED AID"), + colorLore("&7Redirect healing effects from", "&e&lMEDIC&7 additionally to 1/2/3 nearby", "&7wounded allies"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.EARLY, + (arena) -> arena.getPlayers() + .stream() + .anyMatch(player -> plugin.getUserManager().getUser(player).getKit() instanceof MedicKit), + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "EXPANDED_AID", new FixedMetadataValue(plugin, true)); + } + )); + + augments.add(new TerminatorAugment( + "DECAPITATION", + new ItemBuilder(XMaterial.ZOMBIE_HEAD.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&6&lBLADE AUGMENT: &e&lDECAPITATION"), + colorLore("&7Have -/5/8% chance of enemy dropping", "&7their head on death, picking", "&7the head reduces all ability", "&7cooldowns by 10%"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.MID, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "DECAPITATION", new FixedMetadataValue(plugin, true)); + } + )); + augments.add(new TerminatorAugment( + "SAFETY_PROTOCOLS", + new ItemBuilder(XMaterial.IRON_DOOR.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&c&lSYSTEM AUGMENT: &e&lSAFETY PROTOCOLS DISABLED"), + colorLore("&7Receive -/20/25% increased damage", "&7while being low on health"), + TerminatorAugment.AugmentType.SYSTEM, + KitSpecifications.GameTimeState.MID, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "SAFETY_PROTOCOLS", new FixedMetadataValue(plugin, true)); + } + )); + augments.add(new TerminatorAugment( + "REINFORCED_LEARNING", + new ItemBuilder(XMaterial.PLAYER_HEAD.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&c&lSYSTEM AUGMENT: &e&lREINFORCED LEARNING"), + colorLore("&7Earn permanent +2% &8(&730% cap&8) damage", "&7increase every time you die"), + TerminatorAugment.AugmentType.SYSTEM, + KitSpecifications.GameTimeState.MID, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "REINFORCED_LEARNING", new FixedMetadataValue(plugin, 0)); + } + )); + augments.add(new TerminatorAugment( + "BLEEDING_VITALS", + new ItemBuilder(XMaterial.NETHERITE_SWORD.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&6&lBLADE AUGMENT: &e&lBLEEDING VITALS"), + colorLore("&7Critical hits deal", "&7-/15/20% increased damage"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.MID, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "BLEEDING_VITALS", new FixedMetadataValue(plugin, true)); + } + )); + augments.add(new TerminatorAugment( + "POPLUST_COPYCAT", + new ItemBuilder(XMaterial.MAGMA_CREAM.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&b&lSYNERGY AUGMENT: &e&lPOPLUST COPYCAT"), + colorLore("&7You can oneshot enemies", "&7as well when &e&lCleaner's POPLUST", "&7ultimate is active"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.MID, + (arena) -> arena.getPlayers() + .stream() + .anyMatch(player -> plugin.getUserManager().getUser(player).getKit() instanceof CleanerKit), + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "POPLUST_COPYCAT", new FixedMetadataValue(plugin, true)); + } + )); + augments.add(new TerminatorAugment( + "WILL_OF_STEEL", + new ItemBuilder(XMaterial.SHIELD.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&b&lSYNERGY AUGMENT: &e&lWILL OF STEEL"), + colorLore("&7You deal -/20/25% increased damage", "&7to stunned enemies"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.MID, + (arena) -> arena.getPlayers() + .stream() + .anyMatch(player -> plugin.getUserManager().getUser(player).getKit() instanceof CrusaderKit), + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "WILL_OF_STEEL", new FixedMetadataValue(plugin, true)); + } + )); + + augments.add(new TerminatorAugment( + "NEURONAL_REPURPOSE", + new ItemBuilder(XMaterial.MUSIC_DISC_11.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&6&lBLADE AUGMENT: &e&lNEURONAL REPURPOSE"), + colorLore("&7Have 5% chance to force weak", "&7enemies to enter &b&lFRENZY&7 and", "&7attack their allies for 5 seconds"), + TerminatorAugment.AugmentType.BLADE, + KitSpecifications.GameTimeState.LATE, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "NEURONAL_REPURPOSE", new FixedMetadataValue(plugin, true)); + } + )); + augments.add(new TerminatorAugment( + "PSIONIC_BLOW", + new ItemBuilder(XMaterial.FEATHER.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&c&lSYSTEM AUGMENT: &e&lPSIONIC BLOW"), + colorLore("&7If you are to receive", "&c&lLETHAL DAMAGE&7 you explode and", "&7push all enemies away", "&8(&720 seconds cooldown&8)"), + TerminatorAugment.AugmentType.SYSTEM, + KitSpecifications.GameTimeState.LATE, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "PSIONIC_BLOW", new FixedMetadataValue(plugin, true)); + } + )); + augments.add(new TerminatorAugment( + "ULTRAVISION", + new ItemBuilder(XMaterial.IRON_BARS.parseItem()).build(), + ChatColor.translateAlternateColorCodes('&', "&c&lSYSTEM AUGMENT: &e&lULTRAVISION"), + colorLore("&7Make every &3&lINVISIBLE", "&7enemy visible for yourself"), + TerminatorAugment.AugmentType.SYSTEM, + KitSpecifications.GameTimeState.LATE, + TerminatorAugment.CONSTANT_SYNERGY, + user -> { + user.getPlayer().setMetadata(TerminatorAugment.METADATA_KEY + "ULTRAVISION", new FixedMetadataValue(plugin, true)); + } + )); + } + + private static List colorLore(String... strings) { + List list = new ArrayList<>(); + for (String string : strings) { + list.add(ChatColor.translateAlternateColorCodes('&', string)); + } + return list; + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugmentsGui.java b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugmentsGui.java new file mode 100644 index 000000000..789981167 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorAugmentsGui.java @@ -0,0 +1,138 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.terminator; + +import com.github.stefvanschie.inventoryframework.gui.GuiItem; +import com.github.stefvanschie.inventoryframework.gui.type.ChestGui; +import com.github.stefvanschie.inventoryframework.pane.StaticPane; +import net.md_5.bungee.api.ChatColor; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.metadata.FixedMetadataValue; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class TerminatorAugmentsGui { + + private static final String AUGMENT_SELECT0R_TEMP = "VD_AUGMENT_SELECTOR_TEMP"; + private final Main plugin; + + public TerminatorAugmentsGui(Main plugin) { + this.plugin = plugin; + } + + public void openGui(Player player) { + openGui(player, null); + } + + private void openGui(Player player, List chosenAugments) { + User user = plugin.getUserManager().getUser(player); + List augments = chosenAugments == null ? doRollRandomAugments(user) : chosenAugments; + int augmentsAmount = 0; + if (player.hasMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY)) { + augmentsAmount = player.getMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY).get(0).asInt(); + } + String message = "&a&lCHOOSE AUGMENT &8(&7%amount%/&73 unlocked&8)".replace("%amount%", String.valueOf(augmentsAmount)); + ChestGui gui = new ChestGui(3, ChatColor.translateAlternateColorCodes('&', message)); + gui.setOnGlobalClick(e -> e.setCancelled(true)); + gui.setOnClose(e -> { + if (player.hasMetadata(AUGMENT_SELECT0R_TEMP)) { + player.removeMetadata(AUGMENT_SELECT0R_TEMP, plugin); + new MessageBuilder("KIT_CONTENT_TERMINATOR_GAME_ITEM_TERMINUS_AUGMENT_GUI_AUGMENT_APPLIED").asKey().send(player); + return; + } + new MessageBuilder("KIT_CONTENT_TERMINATOR_GAME_ITEM_TERMINUS_AUGMENT_GUI_CHOOSE_AN_AUGMENT").asKey().send(player); + player.playSound(player, Sound.ENTITY_VILLAGER_NO, 1f, 1f); + Bukkit.getScheduler().runTaskLater(plugin, () -> openGui(player, augments), 5); + }); + StaticPane pane = new StaticPane(0, 0, 9, 3); + TerminatorAugment first = augments.get(0); + pane.addItem(new GuiItem( + new ItemBuilder(first.icon().clone()) + .name(first.name()) + .lore(first.lore()) + .lore("") + .lore(org.bukkit.ChatColor.translateAlternateColorCodes('&', "&8(Click to upgrade)")) + .build(), + e -> doApplyAugment(user, first) + ), 2, 1); + TerminatorAugment second = augments.get(1); + pane.addItem(new GuiItem( + new ItemBuilder(second.icon().clone()) + .name(second.name()) + .lore(second.lore()) + .lore("") + .lore(org.bukkit.ChatColor.translateAlternateColorCodes('&', "&8(Click to upgrade)")) + .build(), + e -> doApplyAugment(user, second) + ), 4, 1); + TerminatorAugment third = augments.get(2); + pane.addItem(new GuiItem( + new ItemBuilder(third.icon().clone()) + .name(third.name()) + .lore(third.lore()) + .lore("") + .lore(org.bukkit.ChatColor.translateAlternateColorCodes('&', "&8(Click to upgrade)")) + .build(), + e -> doApplyAugment(user, third) + ), 6, 1); + gui.addPane(pane); + gui.show(player); + } + + private List doRollRandomAugments(User user) { + List augments = TerminatorAugmentRegistry.getAugments() + .stream() + .filter(a -> a.appliesFrom() == KitSpecifications.getTimeState((Arena) user.getArena()) && a.synergyApplies().apply((Arena) user.getArena())) + .filter(a -> !user.getPlayer().hasMetadata(a.getMetadataKey())) + .collect(Collectors.toList()); + Collections.shuffle(augments); + List rolledAugments = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + if (augments.size() <= i) { + break; + } + rolledAugments.add(augments.get(i)); + } + return rolledAugments; + } + + private void doApplyAugment(User user, TerminatorAugment augment) { + user.getPlayer().setMetadata(AUGMENT_SELECT0R_TEMP, new FixedMetadataValue(plugin, true)); + int totalAugments = 0; + if (user.getPlayer().hasMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY)) { + totalAugments = user.getPlayer().getMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY).get(0).asInt(); + } + totalAugments++; + user.getPlayer().setMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY, new FixedMetadataValue(plugin, totalAugments)); + augment.onApply().accept(user); + user.getPlayer().closeInventory(); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorEvents.java b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorEvents.java new file mode 100644 index 000000000..a685d9f0e --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorEvents.java @@ -0,0 +1,416 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.terminator; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.EntityEffect; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XSound; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.handlers.hologram.ArmorStandHologram; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; + +import java.util.Optional; +import java.util.concurrent.ThreadLocalRandom; + +public class TerminatorEvents implements Listener { + + private final Main plugin; + + public TerminatorEvents(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + //todo random waves roll + @EventHandler + public void onAugmentDrop(EntityDeathEvent event) { + if (!NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + Player player = event.getEntity().getKiller(); + User user = plugin.getUserManager().getUser(player); + if (player == null || user.getArena() == null || ((Arena) user.getArena()).getZombiesLeft() > 0) { + return; + } + Optional terminatorPlayer = user.getArena() + .getPlayers() + .stream() + .filter(p -> plugin.getUserManager().getUser(p).getKit() instanceof TerminatorKit) + .findFirst(); + if (terminatorPlayer.isEmpty()) { + return; + } + int count = 0; + if (terminatorPlayer.get().hasMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY)) { + count = terminatorPlayer.get().getMetadata(TerminatorAugment.AUGMENTS_COUNT_METADATA_KEY).get(0).asInt(); + } + switch (KitSpecifications.getTimeState((Arena) user.getArena())) { + case LATE -> { + if (count < 3) { + doDropAugmentShard(user, event.getEntity().getLocation()); + } + } + case MID -> { + if (count < 2) { + doDropAugmentShard(user, event.getEntity().getLocation()); + } + } + case EARLY -> { + if (count < 1) { + doDropAugmentShard(user, event.getEntity().getLocation()); + } + } + } + } + + private void doDropAugmentShard(User user, Location location) { + Location targetLocation = location.clone().add(0, -0.75, 0); + ArmorStandHologram hologram = new ArmorStandHologram(targetLocation) + .appendItem(XMaterial.PRISMARINE_SHARD.parseItem()) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&6&lCORE COMPONENT &e&lAUGMENT")) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&7Can be picked by &6&lTerminator&7 only")); + hologram.setPickupHandler(target -> { + if (!user.getArena().equals(plugin.getArenaRegistry().getArena(target))) { + return; + } + XSound.ENTITY_PLAYER_LEVELUP.play(target, 1, 0); + XSound.ENTITY_VILLAGER_YES.play(target); + hologram.delete(); + new TerminatorAugmentsGui(plugin).openGui(target); + }); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!hologram.isDeleted()) { + hologram.delete(); + } + }, 20 * 25); + } + + @EventHandler + public void onVitalityTrigger(EntityDeathEvent event) { + if (!NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + Player player = event.getEntity().getKiller(); + User user = plugin.getUserManager().getUser(player); + if (player == null || user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + String key = TerminatorAugment.METADATA_KEY + "VITALITY"; + if (!player.hasMetadata(key)) { + return; + } + int count = player.getMetadata(key).get(0).asInt() + 1; + player.setMetadata(key, new FixedMetadataValue(plugin, count)); + if (count >= TerminatorKit.Settings.AUGMENT_VITALITY_TRIGGER_COUNT.getForArenaState((Arena) user.getArena())) { + player.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, 30, 0)); + player.setMetadata(key, new FixedMetadataValue(plugin, 0)); + } + } + + @EventHandler + public void onAdaptiveShieldsTrigger(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + if (!(event.getDamager() instanceof TNTPrimed primed)) { + return; + } + if (!primed.hasMetadata("VD_PRIMED_TNT")) { + return; + } + if (!player.hasMetadata(TerminatorAugment.METADATA_KEY + "ADAPTIVE_SHIELDS")) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + event.setDamage(event.getDamage() - (event.getDamage() * TerminatorKit.Settings.AUGMENT_ADAPTIVE_SHIELDS_REDUCE_PERCENT.getForArenaState((Arena) user.getArena()))); + } + + @EventHandler + public void onSteadyScalingDamage(EntityDamageEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + if (!player.hasMetadata(TerminatorAugment.METADATA_KEY + "STEADY_SCALING")) { + return; + } + User user = plugin.getUserManager().getUser(player); + int count = player.getMetadata(TerminatorAugment.METADATA_KEY + "STEADY_SCALING").get(0).asInt(); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit) || count == 0) { + return; + } + event.setDamage(event.getDamage() + (event.getDamage() * (count / 100.0))); + } + + @EventHandler + public void onSteadyScalingIncrease(EntityDeathEvent event) { + if (!NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + Player player = event.getEntity().getKiller(); + User user = plugin.getUserManager().getUser(player); + if (player == null || user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + String key = TerminatorAugment.METADATA_KEY + "STEADY_SCALING_COUNT"; + if (!player.hasMetadata(key)) { + return; + } + int count = player.getMetadata(key).get(0).asInt() + 1; + player.setMetadata(key, new FixedMetadataValue(plugin, count)); + if (count >= 50) { + int steadyScaling = 0; + String scalingKey = TerminatorAugment.METADATA_KEY + "STEADY_SCALING"; + if (player.hasMetadata(scalingKey)) { + steadyScaling = Math.min(player.getMetadata(scalingKey).get(0).asInt() + 1, 30); + } + if (steadyScaling <= 30) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&e&lSTEADY SCALING &7has increased to &e" + steadyScaling + " stacks")); + } + player.setMetadata(key, new FixedMetadataValue(plugin, 0)); + player.setMetadata(scalingKey, new FixedMetadataValue(plugin, steadyScaling)); + } + } + + //todo synergy - expanded aid + + @EventHandler + public void onDecapitationTrigger(EntityDeathEvent event) { + if (!NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + Player player = event.getEntity().getKiller(); + User user = plugin.getUserManager().getUser(player); + if (player == null || user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + String key = TerminatorAugment.METADATA_KEY + "DECAPITATION"; + if (!player.hasMetadata(key)) { + return; + } + double chance = TerminatorKit.Settings.AUGMENT_DECAPITATION_TRIGGER_CHANCE.getForArenaState((Arena) user.getArena()); + if (chance > ThreadLocalRandom.current().nextInt(0, 100)) { + return; + } + Location location = event.getEntity().getLocation().add(0, 0.5, 0); + ArmorStandHologram hologram = new ArmorStandHologram(location) + .appendItem(XMaterial.ZOMBIE_HEAD.parseItem()) + .appendLine(ChatColor.translateAlternateColorCodes('&', "&e&l-10% COOLDOWN")); + hologram.setPickupHandler(target -> { + if (!user.getArena().equals(plugin.getArenaRegistry().getArena(target))) { + return; + } + XSound.ENTITY_PLAYER_LEVELUP.play(target, 1, 0); + XSound.ENTITY_VILLAGER_YES.play(target); + hologram.delete(); + double neverdeathCd = user.getCooldown("terminator_neverdeath"); + user.setCooldown("terminator_neverdeath", Math.max(neverdeathCd - (neverdeathCd * 0.1), 0)); + VersionUtils.setMaterialCooldown(user.getPlayer(), XMaterial.CHARCOAL.parseMaterial(), (int) user.getCooldown("terminator_neverdeath")); + double overchargeCd = user.getCooldown("terminator_overcharge"); + user.setCooldown("terminator_overcharge", Math.max(overchargeCd - (overchargeCd * 0.1), 0)); + VersionUtils.setMaterialCooldown(user.getPlayer(), XMaterial.TRIPWIRE_HOOK.parseMaterial(), (int) user.getCooldown("terminator_overcharge")); + }); + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (!hologram.isDeleted()) { + hologram.delete(); + } + }, 20 * 10); + } + + @EventHandler + public void onSafetyProtocolsTrigger(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + if (!player.hasMetadata(TerminatorAugment.METADATA_KEY + "SAFETY_PROTOCOLS")) { + return; + } + if (player.getHealth() > 6) { + return; + } + event.setDamage(event.getDamage() + (event.getDamage() * TerminatorKit.Settings.AUGMENT_SAFETY_PROTOCOLS_DAMAGE_MULTIPLIER.getForArenaState((Arena) user.getArena()))); + } + + @EventHandler + public void onReinforcedLearningTrigger(EntityDeathEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + String key = TerminatorAugment.METADATA_KEY + "REINFORCED_LEARNING"; + if (!player.hasMetadata(key)) { + player.setMetadata(key, new FixedMetadataValue(plugin, 1)); + return; + } + int count = Math.min(player.getMetadata(key).get(0).asInt() + 1, 15); + player.setMetadata(key, new FixedMetadataValue(plugin, count)); + } + + @EventHandler + public void onReinforcedLearningDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + String key = TerminatorAugment.METADATA_KEY + "REINFORCED_LEARNING"; + if (!player.hasMetadata(key)) { + return; + } + int count = player.getMetadata(key).get(0).asInt(); + event.setDamage(event.getDamage() + (event.getDamage() * (count / 100.0))); + } + + @EventHandler + public void onBleedingVitalsDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + if (!player.hasMetadata(TerminatorAugment.METADATA_KEY + "BLEEDING_VITALS")) { + return; + } + if (!isCritical(player)) { + return; + } + event.setDamage(event.getDamage() + (event.getDamage() * TerminatorKit.Settings.AUGMENT_BLEEDING_VITALS_MULTIPLIER.getForArenaState((Arena) user.getArena()))); + } + + private boolean isCritical(Player player) { + return player.getFallDistance() > 0.0F && + !player.isOnGround() && + !player.isInsideVehicle() && + !player.hasPotionEffect(PotionEffectType.BLINDNESS) && + player.getLocation().getBlock().getType() != Material.LADDER && + player.getLocation().getBlock().getType() != Material.VINE; + } + + //todo poplust copycat + + @EventHandler + public void onWillOfSteelDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + if (!player.hasMetadata(TerminatorAugment.METADATA_KEY + "WILL_OF_STEEL")) { + return; + } + if (!NewCreatureUtils.isEnemy(event.getEntity()) || !event.getEntity().hasMetadata("VD_STUNNED")) { + return; + } + event.setDamage(event.getDamage() + (event.getDamage() * TerminatorKit.Settings.AUGMENT_WILL_OF_STEEL_MULTIPLIER.getForArenaState((Arena) user.getArena()))); + } + + @EventHandler + public void onNeuronalRepurposeTrigger(EntityDeathEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user.getArena() == null || !(user.getKit() instanceof TerminatorKit)) { + return; + } + if (!player.hasMetadata(TerminatorAugment.METADATA_KEY + "NEURONAL_REPURPOSE")) { + return; + } + if (!NewCreatureUtils.isEnemy(event.getEntity()) || ThreadLocalRandom.current().nextInt() > 5) { + return; + } + NewCreatureUtils.doFrenzyEnemy((Creature) event.getEntity(), 5); + } + + @EventHandler + public void onPsionicBlowTrigger(EntityDamageByEntityEvent event) { + if (!(event.getEntity() instanceof Player player)) { + return; + } + User user = plugin.getUserManager().getUser(player); + if (user == null || user.getArena() == null || user.isSpectator() || !(user.getKit() instanceof TerminatorKit)) { + return; + } + if (user.getCooldown("terminator_psionic_blow") > 0) { + return; + } + if (player.getHealth() - event.getDamage() <= 0) { + new MessageBuilder("&aPsionic blow has saved you!").send(player); + user.setCooldown("terminator_psionic_blow", 20); + event.setDamage(0); + player.setHealth(1.5); + player.playEffect(EntityEffect.valueOf("TOTEM_RESURRECT")); + for (Entity entity : player.getNearbyEntities(6, 6, 6)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + if (!entity.hasMetadata("VD_UNSTUNNABLE")) { + Vector vector = entity.getLocation().toVector().subtract(player.getLocation().toVector()).normalize(); + vector.add(new Vector(0, 0.1, 0)); + entity.setVelocity(vector.multiply(1.6)); + } + } + } + } + + /* + todo + EXPANDED_AID + POPLUST_COPYCAT + ULTRAVISION + */ + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorKit.java b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorKit.java new file mode 100644 index 000000000..1c055d82b --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/terminator/TerminatorKit.java @@ -0,0 +1,437 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.terminator; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import plugily.projects.minigamesbox.classic.handlers.language.Message; +import plugily.projects.minigamesbox.classic.handlers.language.MessageBuilder; +import plugily.projects.minigamesbox.classic.handlers.language.MessageManager; +import plugily.projects.minigamesbox.classic.kits.basekits.PremiumKit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ArmorHelper; +import plugily.projects.minigamesbox.classic.utils.helper.ItemBuilder; +import plugily.projects.minigamesbox.classic.utils.misc.complement.ComplementAccessor; +import plugily.projects.minigamesbox.classic.utils.version.ServerVersion; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.minigamesbox.classic.utils.version.events.api.PlugilyPlayerInteractEvent; +import plugily.projects.minigamesbox.classic.utils.version.xseries.ParticleDisplay; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XMaterial; +import plugily.projects.minigamesbox.classic.utils.version.xseries.XParticle; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.ChatDisplayable; +import plugily.projects.villagedefense.kits.KitsMenu; +import plugily.projects.villagedefense.kits.ScoreboardModifiable; +import plugily.projects.villagedefense.kits.ability.AbilitySource; +import plugily.projects.villagedefense.kits.utils.KitHelper; +import plugily.projects.villagedefense.kits.utils.KitSpecifications; +import plugily.projects.villagedefense.utils.NumberUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; + +/** + * Created by Tom on 18/07/2015. + */ +public class TerminatorKit extends PremiumKit implements Listener, AbilitySource, ChatDisplayable, ScoreboardModifiable { + + public static final String LANGUAGE_ACCESSOR = "KIT_CONTENT_TERMINATOR_"; + private final Random random = new Random(); + + public TerminatorKit() { + registerMessages(); + setName(new MessageBuilder(LANGUAGE_ACCESSOR + "NAME").asKey().build()); + setKey("Terminator"); + List description = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "DESCRIPTION"); + setDescription(description); + getPlugin().getKitRegistry().registerKit(this); + getPlugin().getServer().getPluginManager().registerEvents(this, getPlugin()); + ((Main) getPlugin()).getKitsMenu().registerKit(KitsMenu.KitCategory.DAMAGE_DEALER, this); + new TerminatorEvents((Main) getPlugin()); + } + + @Override + @SuppressWarnings("UnnecessaryUnicodeEscape") + public String getChatPrefix() { + return "\u0048"; + } + + private void registerMessages() { + MessageManager manager = getPlugin().getMessageManager(); + manager.registerMessage(LANGUAGE_ACCESSOR + "NAME", new Message("Kit.Content.Terminator.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "DESCRIPTION", new Message("Kit.Content.Terminator.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_NAME", new Message("Kit.Content.Terminator.Game-Item.Terminus.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_DESCRIPTION", new Message("Kit.Content.Terminator.Game-Item.Terminus.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_NAME", new Message("Kit.Content.Terminator.Game-Item.Neverdeath.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_DESCRIPTION", new Message("Kit.Content.Terminator.Game-Item.Neverdeath.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_ACTIVATE", new Message("Kit.Content.Terminator.Game-Item.Neverdeath.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_NAME", new Message("Kit.Content.Terminator.Game-Item.Motors-Overcharge.Name", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_DESCRIPTION", new Message("Kit.Content.Terminator.Game-Item.Motors-Overcharge.Description", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_ACTIVATE", new Message("Kit.Content.Terminator.Game-Item.Motors-Overcharge.Activate", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_ACTIVE_ACTION_BAR", new Message("Kit.Content.Terminator.Game-Item.Motors-Overcharge.Active-Action-Bar", "")); + + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_AUGMENT_GUI_AUGMENT_APPLIED", new Message("Kit.Content.Terminator.Game-Item.Terminus-Augment.Gui.Augment-Applied", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_AUGMENT_GUI_CHOOSE_AN_AUGMENT", new Message("Kit.Content.Terminator.Game-Item.Terminus-Augment.Gui.Choose-An-Augment", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AUGMENT_FIRST_LOCKED_NAME", new Message("Kit.Content.Terminator.Game-Item.Terminus-Augment.First-Locked", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AUGMENT_SECOND_LOCKED_NAME", new Message("Kit.Content.Terminator.Game-Item.Terminus-Augment.Second-Locked", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AUGMENT_THIRD_LOCKED_NAME", new Message("Kit.Content.Terminator.Game-Item.Terminus-Augment.Third-Locked", "")); + manager.registerMessage(LANGUAGE_ACCESSOR + "GAME_ITEM_AUGMENT_LOCKED_DESCRIPTION", new Message("Kit.Content.Terminator.Game-Item.Terminus-Augment.Locked-Lore", "")); + + } + + @Override + public boolean isUnlockedByPlayer(Player player) { + return player.hasPermission("villagedefense.kit.terminator") || getPlugin().getPermissionsManager().hasPermissionString("KIT_PREMIUM_UNLOCK", player); + } + + @Override + public List getScoreboardLines(User user) { + Arena arena = (Arena) user.getArena(); + int wave = arena.getWave(); + List lines = new ArrayList<>( + Arrays.asList( + "", + "&fVillagers: &a" + arena.getVillagers().size(), + "&fZombies: &a" + arena.getEnemies().size(), + "&fOrbs: &a" + user.getStatistic("orbs"), + "", + "&e&lABILITIES:", + ScoreboardModifiable.renderAbilityCooldown(user, "terminator_neverdeath", "Neverdeath", wave, KitSpecifications.GameTimeState.MID), + ScoreboardModifiable.renderAbilityCooldown(user, "terminator_overcharge", "Motors Overcharge", wave, KitSpecifications.GameTimeState.MID), + "", + "&e&lAUGMENTS:", + renderAugment(user, 1), + renderAugment(user, 2), + renderAugment(user, 3), + "" + ) + ); + if (!arena.isFighting()) { + lines.add(1, "&fNext Wave in &a" + arena.getTimer() + "s"); + } + return lines; + } + + private String renderAugment(User user, int index) { + for (TerminatorAugment augment : TerminatorAugmentRegistry.getAugments()) { + if (!user.getPlayer().hasMetadata(augment.getMetadataKey())) { + continue; + } + //replacing AUGMENT to shorten scoreboard size + if (index == 1 && augment.appliesFrom() == KitSpecifications.GameTimeState.EARLY) { + return "&a" + index + ". &e" + ChatColor.stripColor(augment.name().replace(" AUGMENT", "")); + } else if (index == 2 && augment.appliesFrom() == KitSpecifications.GameTimeState.MID) { + return "&a" + index + ". &e" + ChatColor.stripColor(augment.name().replace(" AUGMENT", "")); + } else if (index == 3 && augment.appliesFrom() == KitSpecifications.GameTimeState.LATE) { + return "&a" + index + ". &e" + ChatColor.stripColor(augment.name().replace(" AUGMENT", "")); + } + } + return "&a" + index + ". &7-------------"; + } + + @Override + public void giveKitItems(Player player) { + player.getInventory().setItem(0, new ItemBuilder(XMaterial.DIAMOND_SWORD.parseItem()) + .enchantment(Enchantment.DURABILITY, 100) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_DESCRIPTION")) + .build()); + player.getInventory().setItem(3, new ItemBuilder(new ItemStack(XMaterial.CHARCOAL.parseMaterial(), 1)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_DESCRIPTION")) + .build()); + player.getInventory().setItem(5, new ItemBuilder(new ItemStack(XMaterial.TRIPWIRE_HOOK.parseMaterial(), 1)) + .name(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_NAME").asKey().build()) + .lore(getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_DESCRIPTION")) + .build()); + + player.getInventory().setItem(8, new ItemStack(XMaterial.COOKED_PORKCHOP.parseMaterial(), 8)); + ArmorHelper.setArmor(player, ArmorHelper.ArmorType.IRON); + } + + @Override + public Material getMaterial() { + return Material.ANVIL; + } + + @Override + public void reStock(Player player) { + Arena arena = (Arena) getPlugin().getArenaRegistry().getArena(player); + if (arena.getWave() > 1 && arena.getWave() <= 30 && arena.getWave() % 5 == 0) { + new MessageBuilder("KIT_ABILITY_POWER_INCREASED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_NAME").asKey().build()).send(player); + } + if (arena.getWave() == KitSpecifications.GameTimeState.MID.getStartWave()) { + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_NAME").asKey().build()).send(player); + new MessageBuilder("KIT_ABILITY_UNLOCKED").asKey().value(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_NAME").asKey().build()).send(player); + } + } + + @EventHandler + public void onPreSwordDamage(EntityDamageByEntityEvent event) { + if (!(event.getDamager() instanceof Player damager) || !NewCreatureUtils.isEnemy(event.getEntity())) { + return; + } + if (event.isCancelled()) { + return; + } + if (!KitHelper.isInGameWithKitAndItemInHand(damager, TerminatorKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(damager); + User user = getPlugin().getUserManager().getUser(damager); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_TERMINUS_NAME").asKey().build())) { + onSwordDamage(event, user); + } + } + + private void onSwordDamage(EntityDamageByEntityEvent event, User user) { + Arena arena = (Arena) user.getArena(); + double onHitBurnChance = getOnHitBurnChance(arena.getWave()); + double onHitInstakillChance = arena.getWave() >= 10 ? 0.05 : 0; + double onHitSharedCombustChance = arena.getWave() >= 20 ? 0.2 : 0; + double onHitLargeKnockbackChance = arena.getWave() >= 25 ? 0.35 : 0; + double onHitLifestealPercent = arena.getWave() >= 15 ? 0.06 : 0; + double maxHealthBonusDamage = getMaxHealthBonusDamage(arena.getWave()); + double chance = random.nextDouble(); + LivingEntity entity = (LivingEntity) event.getEntity(); + if (chance <= onHitBurnChance) { + entity.setFireTicks(20 * 3); + } + double steal = event.getDamage() * onHitLifestealPercent; + //filter out large lifesteals from insta kills or such + if (steal > 0 && steal < 100) { + KitHelper.healPlayer(user.getPlayer(), steal); + } + if (chance <= onHitInstakillChance) { + KitHelper.executeEnemy(entity, user.getPlayer()); + return; + } + if (chance <= onHitSharedCombustChance) { + List enemies = entity.getNearbyEntities(1.5, 1.5, 1.5) + .stream() + .filter(e -> !entity.equals(e)) + .filter(NewCreatureUtils::isEnemy) + .map(e -> (LivingEntity) e) + .collect(Collectors.toList()); + int limit = 4; + for (LivingEntity enemy : enemies) { + if (limit == 0) { + break; + } + enemy.setFireTicks(20 * 3); + enemy.damage(0, user.getPlayer()); + limit--; + } + } + if (chance <= onHitLargeKnockbackChance && !entity.hasMetadata("VD_UNSTUNNABLE")) { + entity.setVelocity(user.getPlayer().getLocation().getDirection().multiply(2.5)); + } + double bonusDamage = VersionUtils.getMaxHealth(entity) * maxHealthBonusDamage; + event.setDamage(event.getDamage() + bonusDamage); + } + + private double getOnHitBurnChance(int wave) { + if (wave >= 15) { + return 0.4; + } else if (wave >= 5) { + return 0.2; + } + return 0; + } + + private double getMaxHealthBonusDamage(int wave) { + if (wave < 30) { + return 0; + } + int val = wave - 29; + return NumberUtils.clamp(val, 1, 40) / 100.0; + } + + @EventHandler + public void onEntityDamage(EntityDamageByEntityEvent event) { + if (!event.getDamager().hasMetadata("VD_TERMINATOR_NO_DAMAGE")) { + return; + } + event.setCancelled(true); + } + + @Override + @EventHandler + public void onAbilityCast(PlugilyPlayerInteractEvent event) { + if (!KitHelper.isInGameWithKitAndItemInHand(event.getPlayer(), TerminatorKit.class)) { + return; + } + ItemStack stack = VersionUtils.getItemInHand(event.getPlayer()); + User user = getPlugin().getUserManager().getUser(event.getPlayer()); + String displayName = ComplementAccessor.getComplement().getDisplayName(stack.getItemMeta()); + if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_NAME").asKey().build())) { + onNeverdeathCast(stack, user); + } else if (displayName.equals(new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_NAME").asKey().build())) { + onMotorsOverchargePreCast(stack, user); + } + } + + private void onNeverdeathCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("terminator_neverdeath")) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = getKitsConfig().getInt("Kit-Cooldown.Terminator.Neverdeath", 20); + user.setCooldown("terminator_neverdeath", cooldown); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_NEVERDEATH_ACTIVATE").asKey().send(user.getPlayer()); + + VersionUtils.setMaterialCooldown(user.getPlayer(), stack.getType(), cooldown * 20); + + double missingHealthPercent = 1.0 - (user.getPlayer().getHealth() / VersionUtils.getMaxHealth(user.getPlayer())); + user.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.ABSORPTION, 20 * 15, (int) Math.floor(missingHealthPercent * 10.0))); + } + + private void onMotorsOverchargePreCast(ItemStack stack, User user) { + if (!user.checkCanCastCooldownAndMessage("terminator_overcharge")) { + return; + } + if (KitSpecifications.getTimeState((Arena) user.getArena()) == KitSpecifications.GameTimeState.EARLY) { + new MessageBuilder("KIT_LOCKED_TILL").asKey().integer(16).send(user.getPlayer()); + return; + } + int cooldown = getKitsConfig().getInt("Kit-Cooldown.Terminator.Motors-Overcharge", 60); + user.setCooldown("terminator_overcharge", cooldown); + int castTime = 10; + user.setCooldown("terminator_overcharge_running", castTime); + new MessageBuilder(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_ACTIVATE").asKey().send(user.getPlayer()); + + KitHelper.scheduleAbilityCooldown(stack, user.getPlayer(), castTime, cooldown); + onMotorsOverchargeCast(user); + } + + private void onMotorsOverchargeCast(User user) { + int castTime = 10; + Player player = user.getPlayer(); + player.addPotionEffect(new PotionEffect(PotionEffectType.SLOW, 20 * castTime, 3)); + + List messages = getPlugin().getLanguageManager().getLanguageListFromKey(LANGUAGE_ACCESSOR + "GAME_ITEM_MOTORS_OVERCHARGE_ACTIVE_ACTION_BAR"); + new BukkitRunnable() { + int tick = 0; + int messageIndex = 0; + + @Override + public void run() { + if (ServerVersion.Version.isCurrentEqualOrHigher(ServerVersion.Version.v1_9_R1)) { + XParticle.circle(3, 26, ParticleDisplay.simple(player.getLocation().add(0, 0.35, 0), XParticle.getParticle("SMOKE_NORMAL"))); + } + List enemies = player.getNearbyEntities(2.5, 2.5, 2.5) + .stream() + .filter(NewCreatureUtils::isEnemy) + .collect(Collectors.toList()); + for (Entity enemy : enemies) { + LivingEntity livingEntity = (LivingEntity) enemy; + if (tick >= 20 * castTime) { + Vector oppositeDirection = enemy.getLocation().subtract(player.getLocation()).toVector(); + enemy.setVelocity(oppositeDirection.normalize().multiply(2.0)); + KitHelper.executeEnemy(livingEntity, player); + continue; + } + Vector direction = player.getLocation().subtract(enemy.getLocation()).toVector(); + if (enemy instanceof Ageable ageable) { + ageable.setBaby(); + } + if (!enemy.hasMetadata("VD_TERMINATOR_NO_DAMAGE")) { + ((LivingEntity) enemy).setCollidable(false); + enemy.setMetadata("VD_TERMINATOR_NO_DAMAGE", new FixedMetadataValue(getPlugin(), true)); + } + enemy.setVelocity(direction.normalize().multiply(1.0)); + if (tick % 20 == 0) { + KitHelper.maxHealthPercentDamage(livingEntity, player, 35.0); + } + } + if (tick % 10 == 0) { + VersionUtils.sendActionBar(player, messages.get(messageIndex) + .replace("%number%", String.valueOf(user.getCooldown("terminator_overcharge_running")))); + messageIndex++; + if (messageIndex > messages.size() - 1) { + messageIndex = 0; + } + } + if (user.isSpectator() || user.getArena() == null || !player.isOnline()) { + cancel(); + return; + } + if (tick >= 20 * castTime) { + VersionUtils.sendActionBar(player, ""); + player.getWorld().spawnParticle(XParticle.getParticle("EXPLOSION_LARGE"), player.getLocation(), 3); + cancel(); + return; + } + tick++; + } + }.runTaskTimer(getPlugin(), 0, 1); + } + + public enum Settings { + AUGMENT_VITALITY_TRIGGER_COUNT(5, 4, 3), AUGMENT_ADAPTIVE_SHIELDS_REDUCE_PERCENT(0.25, 0.3, 0.35), + AUGMENT_DECAPITATION_TRIGGER_CHANCE(0, 5, 8), AUGMENT_SAFETY_PROTOCOLS_DAMAGE_MULTIPLIER(0, 0.2, 0.25), + AUGMENT_BLEEDING_VITALS_MULTIPLIER(0, 0.15, 0.2), AUGMENT_WILL_OF_STEEL_MULTIPLIER(0, 0.15, 0.2); + + private final double earlyValue; + private final double midValue; + private final double lateValue; + + Settings(double earlyValue, double midValue, double lateValue) { + this.earlyValue = earlyValue; + this.midValue = midValue; + this.lateValue = lateValue; + } + + public double getForArenaState(Arena arena) { + switch (KitSpecifications.getTimeState(arena)) { + case LATE: + return lateValue; + case MID: + return midValue; + case EARLY: + default: + return earlyValue; + } + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/utils/ActionBarPriority.java b/src/main/java/plugily/projects/villagedefense/kits/utils/ActionBarPriority.java new file mode 100644 index 000000000..b6033b6a8 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/utils/ActionBarPriority.java @@ -0,0 +1,38 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.utils; + +/** + * @author Plajer + *

+ * Created at 29.09.2023 + */ +public class ActionBarPriority { + + public static final int DAMAGE_EFFECT = 0; + public static final int BUFFS = 1; + public static final int HEALING = 2; + public static final int HEALING_AND_BUFFS = 3; + public static final int PASSIVE = 4; + public static final int ULTIMATE = 5; + public static final int LOW_PRIORITY = 1; + public static final int MEDIUM_PRIORITY = 4; + public static final int HIGH_PRIORITY = 6; + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/utils/KitHelper.java b/src/main/java/plugily/projects/villagedefense/kits/utils/KitHelper.java new file mode 100644 index 000000000..2605aec50 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/utils/KitHelper.java @@ -0,0 +1,138 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.utils; + +import org.bukkit.Bukkit; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import plugily.projects.minigamesbox.classic.kits.basekits.Kit; +import plugily.projects.minigamesbox.classic.user.User; +import plugily.projects.minigamesbox.classic.utils.helper.ItemUtils; +import plugily.projects.minigamesbox.classic.utils.version.VersionUtils; +import plugily.projects.villagedefense.Main; +import plugily.projects.villagedefense.arena.Arena; +import plugily.projects.villagedefense.arena.managers.spawner.gold.NewCreatureUtils; +import plugily.projects.villagedefense.kits.terminator.TerminatorAugmentRegistry; + +/** + * @author Plajer + *

+ * Created at 01.08.2023 + */ +public class KitHelper { + + private static Main plugin; + + private KitHelper() { + } + + public static void init(Main plugin) { + KitHelper.plugin = plugin; + TerminatorAugmentRegistry.init(plugin); + } + + public static boolean isInGameWithKitAndItemInHand(Player player, Class instance) { + if(plugin.getArenaRegistry().getArena(player) == null) { + return false; + } + + User user = plugin.getUserManager().getUser(player); + if(user.isSpectator() || !instance.isInstance(user.getKit())) { + return false; + } + ItemStack stack = VersionUtils.getItemInHand(player); + return ItemUtils.isItemStackNamed(stack); + } + + public static void scheduleAbilityCooldown(ItemStack item, Player player, int castTime, int cooldown) { + ItemMeta meta = item.getItemMeta(); + meta.addEnchant(Enchantment.DURABILITY, 1, true); + item.setItemMeta(meta); + Bukkit.getScheduler().runTaskLater(KitHelper.plugin, () -> { + ItemMeta newMeta = item.getItemMeta(); + newMeta.removeEnchant(Enchantment.DURABILITY); + item.setItemMeta(newMeta); + + VersionUtils.setMaterialCooldown(player, item.getType(), (cooldown - castTime) * 20); + }, castTime * 20L); + } + + public static void healPlayer(Player target, double healAmount) { + healPlayer(target, target, healAmount); + } + + public static void healPlayer(Player source, Player target, double healAmount) { + target.setHealth(Math.min(target.getHealth() + healAmount, VersionUtils.getMaxHealth(target))); + VersionUtils.sendParticles("HEART", target, target.getLocation(), 3); + if(!source.equals(target)) { + Arena arena = plugin.getArenaRegistry().getArena(target); + arena.getAssistHandler().doRegisterBuffOnAlly(source, target); + } + } + + public static boolean canExecuteEnemy(LivingEntity entity, LivingEntity damager) { + //todo implement execution immunity here (for bosses) + return true; + } + + public static boolean executeEnemy(LivingEntity entity, LivingEntity damager) { + //todo implement execution immunity here (for bosses) + entity.damage(KitSpecifications.LETHAL_DAMAGE, damager); + return true; + } + + public static double maxHealthPercentDamage(LivingEntity entity, double percent) { + double damageDone = (VersionUtils.getMaxHealth(entity) / 100.0) * percent; + entity.setHealth(Math.max(0, entity.getHealth() - damageDone)); + //todo implement max health percentage immunity here (for bosses) + entity.damage(0); + return damageDone; + } + + public static double maxHealthPercentDamage(LivingEntity entity, LivingEntity damager, double percent) { + double damageDone = (VersionUtils.getMaxHealth(entity) / 100.0) * percent; + entity.setHealth(Math.max(0, entity.getHealth() - damageDone)); + //todo implement max health percentage immunity here (for bosses) + entity.damage(0, damager); + return damageDone; + } + + public static void damageNearbyFlat(LivingEntity damager, double damage, double radius) { + for (Entity entity : damager.getNearbyEntities(radius, radius, radius)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + ((LivingEntity) entity).damage(damage, damager); + } + } + + public static void damageNearbyPercent(LivingEntity damager, double damage, double radius) { + for (Entity entity : damager.getNearbyEntities(radius, radius, radius)) { + if (!NewCreatureUtils.isEnemy(entity)) { + continue; + } + maxHealthPercentDamage((LivingEntity) entity, damager, damage); + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/kits/utils/KitSpecifications.java b/src/main/java/plugily/projects/villagedefense/kits/utils/KitSpecifications.java new file mode 100644 index 000000000..1e2ea54e0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/kits/utils/KitSpecifications.java @@ -0,0 +1,56 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.kits.utils; + +import plugily.projects.villagedefense.arena.Arena; + +/** + * @author Plajer + *

+ * Created at 01.09.2022 + */ +public class KitSpecifications { + + public static final double LETHAL_DAMAGE = 10000000.0; + + public static GameTimeState getTimeState(Arena arena) { + if(arena.getWave() <= 15) { + return GameTimeState.EARLY; + } else if(arena.getWave() <= 30) { + return GameTimeState.MID; + } else { + return GameTimeState.LATE; + } + } + + public enum GameTimeState { + LATE(31), MID(16), EARLY(0); + + private int startWave; + + GameTimeState(int startWave) { + this.startWave = startWave; + } + + public int getStartWave() { + return startWave; + } + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/user/VDUser.java b/src/main/java/plugily/projects/villagedefense/user/VDUser.java new file mode 100644 index 000000000..0389b6db2 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/user/VDUser.java @@ -0,0 +1,46 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2024 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.user; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@Data +@AllArgsConstructor +public class VDUser { + + private UUID uuid; + private Map> gameplayRecords = new HashMap<>(); + + @Data + @AllArgsConstructor + public static class GameplayRecord { + + private String mapId; + private String kitName; + private int wave; + + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/user/VDUserManager.java b/src/main/java/plugily/projects/villagedefense/user/VDUserManager.java new file mode 100644 index 000000000..e67fd1f20 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/user/VDUserManager.java @@ -0,0 +1,116 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.user; + +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import plugily.projects.minigamesbox.classic.utils.configuration.ConfigUtils; +import plugily.projects.villagedefense.Main; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +public class VDUserManager implements Listener { + + private final Main plugin; + private final List users = new ArrayList<>(); + private final FileConfiguration usersFile; + + public VDUserManager(Main plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + this.usersFile = ConfigUtils.getConfig(plugin, "vd_user_data"); + for (Player player : Bukkit.getOnlinePlayers()) { + users.add(load(player)); + } + } + + @EventHandler + public void onJoin(PlayerJoinEvent event) { + users.add(load(event.getPlayer())); + event.getPlayer().setResourcePack( + "https://static.plajer.xyz/villagedefense/lookandfeelv1_1.zip", + "f221d030f380026ffef1202c7a2f538c", + true, + Component.text("We kindly ask to download required Village Defense resource pack for better game experience.") + ); + } + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + VDUser target = users.stream() + .filter(user -> user.getUuid().equals(event.getPlayer().getUniqueId())) + .findFirst() + .orElse(null); + persist(target); + users.remove(target); + } + + public VDUser getUser(Player player) { + return users.stream() + .filter(user -> user.getUuid().equals(player.getUniqueId())) + .findFirst() + .orElse(null); + } + + public List getRegisteredUsers() { + return users; + } + + public VDUser load(OfflinePlayer player) { + UUID uuid = player.getUniqueId(); + if (!usersFile.isSet(uuid.toString())) { + return new VDUser(uuid, new HashMap<>()); + } + Map> records = new HashMap<>(); + ConfigurationSection section = usersFile.getConfigurationSection(uuid + ".records"); + for (String key : section.getKeys(false)) { + List localRecords = new ArrayList<>(); + for (String value : usersFile.getStringList(uuid + ".records." + key)) { + String[] data = value.split(";"); + localRecords.add(new VDUser.GameplayRecord(key, data[0], Integer.parseInt(data[1]))); + } + records.put(key, localRecords); + } + return new VDUser(uuid, records); + } + + public void persist(VDUser user) { + for (Map.Entry> entry : user.getGameplayRecords().entrySet()) { + List flatData = entry.getValue().stream() + .map(record -> record.getKitName() + ";" + record.getWave()) + .collect(Collectors.toList()); + usersFile.set(user.getUuid() + ".records." + entry.getKey(), flatData); + } + ConfigUtils.saveConfig(plugin, usersFile, "vd_user_data"); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/utils/ItemBuilder.java b/src/main/java/plugily/projects/villagedefense/utils/ItemBuilder.java new file mode 100644 index 000000000..90f44be1d --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/ItemBuilder.java @@ -0,0 +1,158 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataType; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class ItemBuilder { + + public static final String NAMESPACE = "noheej"; + private final ItemStack itemStack; + + public ItemBuilder(ItemStack itemStack) { + this.itemStack = itemStack.clone(); + } + + public ItemBuilder(Material material) { + this.itemStack = new ItemStack(material); + } + + public ItemBuilder setAmount(int amount) { + this.itemStack.setAmount(amount); + return this; + } + + public ItemBuilder setDisplayName(String text) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.setDisplayName(text); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder setDisplayNamePlaceholder(String pattern, String value) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.setDisplayName(meta.getDisplayName().replace(pattern, value)); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder setLore(List lore) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.setLore(lore); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder appendLore(List lines, int number) { + ItemMeta meta = this.itemStack.getItemMeta(); + List newLore = meta.getLore(); + if (newLore == null) { + newLore = new ArrayList<>(); + } + newLore.addAll(number, lines); + meta.setLore(newLore); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder appendLore(List lines) { + ItemMeta meta = this.itemStack.getItemMeta(); + List newLore = meta.getLore(); + if (newLore == null) { + newLore = new ArrayList<>(); + } + newLore.addAll(lines); + meta.setLore(newLore); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder setLorePlaceholder(String pattern, String value) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.setLore( + meta.getLore() + .stream() + .map(lore -> lore.replace(pattern, value)) + .collect(Collectors.toList()) + ); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder setEnchantment(Enchantment enchantment, int level) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.addEnchant(enchantment, level, true); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder addFlag(ItemFlag flag) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.addItemFlags(flag); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder addPersistingMetadata(String key, int value) { + ItemMeta meta = this.itemStack.getItemMeta(); + NamespacedKey namespacedKey = new NamespacedKey(NAMESPACE, key); + meta.getPersistentDataContainer().set(namespacedKey, PersistentDataType.INTEGER, value); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder addPersistingMetadata(String key, double value) { + ItemMeta meta = this.itemStack.getItemMeta(); + NamespacedKey namespacedKey = new NamespacedKey(NAMESPACE, key); + meta.getPersistentDataContainer().set(namespacedKey, PersistentDataType.DOUBLE, value); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder addPersistingMetadata(String key, String value) { + ItemMeta meta = this.itemStack.getItemMeta(); + NamespacedKey namespacedKey = new NamespacedKey(NAMESPACE, key); + meta.getPersistentDataContainer().set(namespacedKey, PersistentDataType.STRING, value); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemBuilder setCustomModelData(int data) { + ItemMeta meta = this.itemStack.getItemMeta(); + meta.setCustomModelData(data); + this.itemStack.setItemMeta(meta); + return this; + } + + public ItemStack build() { + return this.itemStack; + } + +} + diff --git a/src/main/java/plugily/projects/villagedefense/utils/LimitedQueue.java b/src/main/java/plugily/projects/villagedefense/utils/LimitedQueue.java new file mode 100644 index 000000000..ef1215650 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/LimitedQueue.java @@ -0,0 +1,39 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils; + +import java.util.LinkedList; + +public class LimitedQueue extends LinkedList { + + private int limit; + + public LimitedQueue(int limit) { + this.limit = limit; + } + + @Override + public boolean add(E o) { + boolean added = super.add(o); + while (added && size() > limit) { + super.remove(); + } + return added; + } +} diff --git a/src/main/java/plugily/projects/villagedefense/utils/NearbyUtils.java b/src/main/java/plugily/projects/villagedefense/utils/NearbyUtils.java new file mode 100644 index 000000000..d175ebe51 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/NearbyUtils.java @@ -0,0 +1,51 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils; + +import org.bukkit.Location; +import org.bukkit.block.Block; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class NearbyUtils { + + private static final Random random = new Random(); + + public static Location getRandomNearbyLocation(Location location, double maxRadius) { + double randomX = location.getX() + (random.nextDouble() * 2 - 1) * maxRadius; + double randomZ = location.getZ() + (random.nextDouble() * 2 - 1) * maxRadius; + double randomY = location.getY(); + return new Location(location.getWorld(), randomX, randomY, randomZ); + } + + public static List getNearbyBlocks(Location location, int radius) { + List blocks = new ArrayList<>(); + for (int x = location.getBlockX() - radius; x <= location.getBlockX() + radius; x++) { + for (int y = location.getBlockY() - radius; y <= location.getBlockY() + radius; y++) { + for (int z = location.getBlockZ() - radius; z <= location.getBlockZ() + radius; z++) { + blocks.add(location.getWorld().getBlockAt(x, y, z)); + } + } + } + return blocks; + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/utils/NumberUtils.java b/src/main/java/plugily/projects/villagedefense/utils/NumberUtils.java new file mode 100644 index 000000000..d20d32dd3 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/NumberUtils.java @@ -0,0 +1,43 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils; + +/** + * @author Plajer + *

+ * Created at 04.08.2023 + */ +public class NumberUtils { + + private NumberUtils() { + } + + /** + * Fit the requested value between minimum and maximum + * + * @param value the value to clamp + * @param min absolute minimum to return + * @param max absolute maximum to return + * @return value clamped between min and max + */ + public static double clamp(double value, double min, double max) { + return Math.max(min, Math.min(max, value)); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/utils/ProtocolUtils.java b/src/main/java/plugily/projects/villagedefense/utils/ProtocolUtils.java new file mode 100644 index 000000000..0baa9d030 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/ProtocolUtils.java @@ -0,0 +1,62 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils; + +import com.comphenix.protocol.PacketType; +import com.comphenix.protocol.ProtocolLibrary; +import com.comphenix.protocol.ProtocolManager; +import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.wrappers.BlockPosition; +import org.bukkit.block.Block; +import plugily.projects.villagedefense.Main; + +/** + * @author Plajer + *

+ * Created at 28.08.2023 + */ +public class ProtocolUtils { + + private static boolean enabled = false; + + private ProtocolUtils() { + } + + public static void init(Main plugin) { + ProtocolUtils.enabled = plugin.getServer().getPluginManager().getPlugin("ProtocolLib") != null; + } + + public static void removeBlockBreakAnimation(Block block) { + sendBlockBreakAnimation(block, 10); + } + + //https://wiki.vg/Protocol#Set_Block_Destroy_Stage + public static void sendBlockBreakAnimation(Block block, int stage) { + if(!enabled) { + return; + } + ProtocolManager manager = ProtocolLibrary.getProtocolManager(); + PacketContainer packet = manager.createPacket(PacketType.Play.Server.BLOCK_BREAK_ANIMATION); + packet.getBlockPositionModifier().write(0, new BlockPosition(block.getX(), block.getY(), block.getZ())); + packet.getIntegers().write(0, block.hashCode()); + packet.getIntegers().write(1, stage); + manager.broadcastServerPacket(packet); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/utils/Utils.java b/src/main/java/plugily/projects/villagedefense/utils/Utils.java index f237886d9..889e1f369 100644 --- a/src/main/java/plugily/projects/villagedefense/utils/Utils.java +++ b/src/main/java/plugily/projects/villagedefense/utils/Utils.java @@ -1,19 +1,19 @@ /* - * Village Defense - Protect villagers from hordes of zombies - * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2023 Plugily Projects - maintained by Tigerpanzer_02 and contributors * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package plugily.projects.villagedefense.utils; @@ -31,6 +31,7 @@ public class Utils { private Utils() { } + @Deprecated public static Material getCachedDoor(Block block) { //material can not be cached as we allow other door types if(block == null) { @@ -38,4 +39,5 @@ public static Material getCachedDoor(Block block) { } return (MaterialUtils.isDoor(block.getType()) ? block.getType() : Material.AIR); } + } diff --git a/src/main/java/plugily/projects/villagedefense/utils/avatars/AvatarCreator.java b/src/main/java/plugily/projects/villagedefense/utils/avatars/AvatarCreator.java new file mode 100644 index 000000000..032340681 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/avatars/AvatarCreator.java @@ -0,0 +1,75 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils.avatars; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class AvatarCreator { + + public List getHeadColors(UUID uuid) { + List colors = new ArrayList<>(); + try { + BufferedImage img = ImageIO.read(new URL("https://crafatar.com/avatars/" + uuid + "?size=8&overlay")); + + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 8; ++j) { + colors.add(String.format("#%06X", 16777215 & img.getRGB(i, j))); + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + + return colors; + } + + public Component[] getHead(UUID uuid, AvatarSize avatarSize) { + Component[][] textComponents = new Component[8][8]; + List headColors = this.getHeadColors(uuid); + + for (int i = 0; i < 64; ++i) { + net.kyori.adventure.text.Component component; + int var7 = i / 8; + int var8 = i % 8; + char unicodeChar = (char) (avatarSize.getUnicodeChar() + var8 + 1); + if (i % 8 == 7) { + component = Component.text(unicodeChar + Character.toString(avatarSize.getSpaces()[0])); + } else { + component = Component.text(unicodeChar + Character.toString(avatarSize.getSpaces()[1])); + } + + component = component.color(TextColor.fromHexString(headColors.get(i))); + component = component.font(Key.key("villagedefense")); + textComponents[var7][var8] = component; + } + return Arrays.stream(textComponents).flatMap(Arrays::stream).toArray(Component[]::new); + } + +} diff --git a/src/main/java/plugily/projects/villagedefense/utils/avatars/AvatarSize.java b/src/main/java/plugily/projects/villagedefense/utils/avatars/AvatarSize.java new file mode 100644 index 000000000..b7f67c2a0 --- /dev/null +++ b/src/main/java/plugily/projects/villagedefense/utils/avatars/AvatarSize.java @@ -0,0 +1,41 @@ +/* + * Village Defense - Protect villagers from hordes of zombies + * Copyright (c) 2025 Plugily Projects - maintained by Tigerpanzer_02 and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package plugily.projects.villagedefense.utils.avatars; + +import lombok.Getter; + +@Getter +public enum AvatarSize { + SMALL('\uf000', 8, '\uf803', '\uf804'), + MEDIUM('\uf200', 16, '\uf803', '\uf805'), + NORMAL('\uf300', 32, '\uf803', '\uf807'), + LARGE('\uf400', 64, '\uf803', '\uf811'), + GIANT('\uf500', 128, '\uf803', '\uf819'); + + private final char unicodeChar; + private final int size; + private final char[] spaces; + + AvatarSize(char unicodeChar, int size, char... spaces) { + this.unicodeChar = unicodeChar; + this.spaces = spaces; + this.size = size; + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index f7500ec97..706d823ba 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -119,14 +119,6 @@ Sign-Block-States: true Holidays: true -# Should the plugin enable special powerups which can be found in powerups.yml -Powerups: false - - -# Should the plugin enable kits which can be found in kits.yml -Kits: true - - # Should we create leaderboards out of the stats? Leaderboard: true @@ -170,11 +162,6 @@ Time-Manager: Restarting: 5 -# Should we add support for upgradeable Wolves and Golems in game? -# Configure upgrades pricing in entity_upgrades.yml after enabling it. -Entity-Upgrades: false - - Respawn: # Respawn players when wave ends/starts? After-Wave: true @@ -185,61 +172,31 @@ Respawn: Limit: Wave: # Should game have finite amount of waves - Unlimited: true + Unlimited: false # Limit of waves, if this wave ends game will end - Game-End: 200 + Game-End: 50 Spawn: - # Limit of mobs can be spawned globally in-game - # Will affect only buying them in in-game shop - Wolves: 20 - Golems: 15 # How many villagers will be spawned in an arena? Villagers: 10 # After how many Creatures should we limit them? # Once limit is reached Creatures get more health so it's still harder each wave - Creatures: 75 + Creatures: 85 # Can the players buy again iron golems or wolves if these # entities died? The config limit and permission will be ignored. Entity-Buy-After-Death: false - -Creatures: - # Active after Creatures limit is reached - # Higher value means weaker Creatures - Multiplier-Divider: 18 - # Enable very simple health bar for Creatures? - # They will have health instead of their names - # It will show percentage of health left. - Health-Bar: true - - Orbs: Start: # Amount of orbs given to player when game starts Amount: 20 - Death: - # PERCENTAGE, calculates the percentage of orbs left from the value - # AMOUNT, adjusts the orbs to the value (negative value removes orbs, positive value adds orbs) - # SET, sets the orbs to the value - # KEEP, will leave the orbs like they are - Type: PERCENTAGE - Value: 50 - - -# Should the name tag of these mobs always visible? -Name-Visibility: - Golem: true - Wolf: true - Villager: true - # Zombie glow to make it visible to players. Glowing-Status: # From which wave should the glowing be activated? - Starting-Wave: 6 + Starting-Wave: 1 # How many creatures should the glow be activated from? # Set to 0 to disable - Creatures-Left: 0 + Creatures-Left: 2 Update-Notifier: diff --git a/src/main/resources/creatures.yml b/src/main/resources/creatures.yml deleted file mode 100644 index d5ae223ba..000000000 --- a/src/main/resources/creatures.yml +++ /dev/null @@ -1,698 +0,0 @@ -Creatures: - Village: - RIDEABLE_VILLAGER: - holiday_effects: true - attributes: - GENERIC_MOVEMENT_SPEED: 0.3 - GENERIC_MAX_HEALTH: 25.0 - GENERIC_FOLLOW_RANGE: 200.0 - drop_item: null - RIDEABLE_IRON_GOLEM: - holiday_effects: true - attributes: - GENERIC_MOVEMENT_SPEED: 0.1 - GENERIC_MAX_HEALTH: 100.0 - GENERIC_FOLLOW_RANGE: 200.0 - drop_item: null - RIDEABLE_WOLF: - holiday_effects: true - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_MAX_HEALTH: 30.0 - GENERIC_FOLLOW_RANGE: 200.0 - drop_item: null - Content: - BABY_ZOMBIE: - enabled: true - wave: - min: 3 - max: 0 - priority_type: ANY - explosive_hit: false - entity_type: ZOMBIE - baby: true - breed: false - age: 0 - age_lock: false - exp: 10 - holiday_effects: true - rates: - spawn: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 3 - '2': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 0 - division: 1 - amount: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 0 - division: 1 - reduce: 0 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.3 - GENERIC_MAX_HEALTH: 2.0 - GENERIC_KNOCKBACK_RESISTANCE: 2.0 - GENERIC_ATTACK_DAMAGE: 5.0 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: null - drop_chance: 0 - chestplate: - item: null - drop_chance: 0 - leggings: - item: null - drop_chance: 0 - boots: - item: null - drop_chance: 0 - hand: - item: null - drop_chance: 0 - drop_item: null - FAST_ZOMBIE: - enabled: true - wave: - min: 0 - max: 0 - priority_type: ANY - explosive_hit: false - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 10 - holiday_effects: true - rates: - spawn: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 5 - rate: 1 - division: 1 - '2': - phase: 5 - wave_higher: 0 - wave_lower: 7 - spawn_lower: 0 - rate: 2 - division: 3 - amount: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 5 - rate: 1 - division: 1 - reduce: 0 - '2': - phase: 5 - wave_higher: 0 - wave_lower: 7 - spawn_lower: 5 - rate: 1 - division: 1 - reduce: 0 - check: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 5 - '2': - phase: 5 - wave_higher: 0 - wave_lower: 7 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: null - drop_chance: 0 - chestplate: - item: null - drop_chance: 0 - leggings: - item: null - drop_chance: 0 - boots: - item: null - drop_chance: 0 - hand: - item: null - drop_chance: 0 - drop_item: null - GOLEM_BUSTER: - enabled: true - wave: - min: 8 - max: 0 - priority_type: IRON_GOLEM - explosive_hit: true - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 15 - holiday_effects: true - rates: - spawn: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 3 - '2': - phase: 0 - wave_higher: 6 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 8 - amount: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 4 - reduce: 0 - '2': - phase: 0 - wave_higher: 6 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 4 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - '2': - phase: 0 - wave_higher: 6 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: TNT - drop_chance: 0 - chestplate: - item: IRON_CHESTPLATE - drop_chance: 0.1 - leggings: - item: IRON_LEGGINGS - drop_chance: 0.3 - boots: - item: IRON_BOOTS - drop_chance: 0.2 - hand: - item: TNT - drop_chance: 0 - drop_item: null - HARD_ZOMBIE: - enabled: true - wave: - min: 4 - max: 0 - priority_type: ANY - explosive_hit: false - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 20 - holiday_effects: true - rates: - spawn: - '1': - phase: 5 - wave_higher: 14 - wave_lower: 20 - spawn_lower: 0 - rate: 1 - division: 3 - '2': - phase: 15 - wave_higher: 8 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - amount: - '1': - phase: 5 - wave_higher: 14 - wave_lower: 20 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 0 - '2': - phase: 15 - wave_higher: 8 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 7 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - '2': - phase: 15 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: DIAMOND_HELMET - drop_chance: 0.01 - chestplate: - item: DIAMOND_CHESTPLATE - drop_chance: 0 - leggings: - item: DIAMOND_LEGGINGS - drop_chance: 0 - boots: - item: DIAMOND_BOOTS - drop_chance: 0 - hand: - item: null - drop_chance: 0 - drop_item: null - PLAYER_BUSTER: - enabled: true - wave: - min: 4 - max: 0 - priority_type: PLAYER - explosive_hit: true - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 15 - holiday_effects: true - rates: - spawn: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 3 - '2': - phase: 0 - wave_higher: 10 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 8 - amount: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 4 - reduce: 0 - '2': - phase: 0 - wave_higher: 10 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 8 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - '2': - phase: 0 - wave_higher: 10 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_MAX_HEALTH: 1.0 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: TNT - drop_chance: 0 - chestplate: - item: GOLDEN_CHESTPLATE - drop_chance: 0 - leggings: - item: GOLDEN_LEGGINGS - drop_chance: 0 - boots: - item: GOLDEN_BOOTS - drop_chance: 0 - hand: - item: TNT - drop_chance: 0 - drop_item: null - TANKER_ZOMBIE: - enabled: true - wave: - min: 20 - max: 0 - priority_type: ANY - explosive_hit: false - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 20 - holiday_effects: true - rates: - spawn: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 2 - division: 9 - amount: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 0 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_MAX_HEALTH: 35.0 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: DIAMOND_HELMET - drop_chance: 0 - chestplate: - item: DIAMOND_CHESTPLATE - drop_chance: 0.3 - leggings: - item: DIAMOND_LEGGINGS - drop_chance: 0.4 - boots: - item: DIAMOND_BOOTS - drop_chance: 0 - hand: - item: GOLDEN_AXE - drop_chance: 0 - drop_item: null - SOFT_HARD_ZOMBIE: - enabled: true - wave: - min: 4 - max: 0 - priority_type: ANY - explosive_hit: false - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 15 - holiday_effects: true - rates: - spawn: - '1': - phase: 5 - wave_higher: 7 - wave_lower: 15 - spawn_lower: 0 - rate: 1 - division: 3 - '2': - phase: 15 - wave_higher: 4 - wave_lower: 9 - spawn_lower: 0 - rate: 1 - division: 1 - amount: - '1': - phase: 5 - wave_higher: 7 - wave_lower: 15 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 0 - '2': - phase: 15 - wave_higher: 4 - wave_lower: 9 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 3 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - '2': - phase: 15 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_MAX_HEALTH: 15.0 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: IRON_HELMET - drop_chance: 0.1 - chestplate: - item: IRON_CHESTPLATE - drop_chance: 0.1 - leggings: - item: IRON_LEGGINGS - drop_chance: 0.1 - boots: - item: IRON_BOOTS - drop_chance: 0.2 - hand: - item: null - drop_chance: 0 - drop_item: null - VILLAGER_BUSTER: - enabled: true - wave: - min: 10 - max: 0 - priority_type: VILLAGER - explosive_hit: true - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 5 - holiday_effects: true - rates: - spawn: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 3 - '2': - phase: 0 - wave_higher: 15 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 8 - amount: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 4 - reduce: 0 - '2': - phase: 0 - wave_higher: 15 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 13 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - '2': - phase: 0 - wave_higher: 15 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.2 - GENERIC_MAX_HEALTH: 10.0 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: TNT - drop_chance: 0 - chestplate: - item: LEATHER_CHESTPLATE - drop_chance: 0.5 - leggings: - item: LEATHER_LEGGINGS - drop_chance: 0.5 - boots: - item: LEATHER_BOOTS - drop_chance: 0.5 - hand: - item: TNT - drop_chance: 0 - drop_item: null - VILLAGER_SLAYER: - enabled: true - wave: - min: 23 - max: 0 - priority_type: VILLAGER - explosive_hit: true - entity_type: ZOMBIE - baby: false - breed: false - age: 0 - age_lock: false - exp: 5 - holiday_effects: true - rates: - spawn: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 6 - amount: - '1': - phase: 0 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - rate: 1 - division: 1 - reduce: 0 - check: - '1': - phase: 5 - wave_higher: 0 - wave_lower: 0 - spawn_lower: 0 - # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/attribute/Attribute.html - attributes: - GENERIC_MOVEMENT_SPEED: 0.25 - GENERIC_MAX_HEALTH: 70.0 - GENERIC_FOLLOW_RANGE: 200.0 - equipment: - helmet: - item: CHAINMAIL_HELMET - drop_chance: 0 - chestplate: - item: CHAINMAIL_CHESTPLATE - drop_chance: 0.1 - leggings: - item: CHAINMAIL_LEGGINGS - drop_chance: 0.2 - boots: - item: CHAINMAIL_BOOTS - drop_chance: 0.4 - hand: - item: EMERALD - drop_chance: 0 - drop_item: null - - -# Don't edit it. But who's stopping you? It's your server! -# Really, don't edit ;p -# You edited it, huh? Next time hurt yourself! -Do-Not-Edit: - File-Version: 1 - Core-Version: 1 \ No newline at end of file diff --git a/src/main/resources/entity_upgrades.yml b/src/main/resources/entity_upgrades.yml deleted file mode 100644 index 89a15f72b..000000000 --- a/src/main/resources/entity_upgrades.yml +++ /dev/null @@ -1,32 +0,0 @@ -# Entity upgrades section from Entities Upgrades Module -Entity-Upgrades: - # Cost of x tier (in orbs), ex 1: 100 means 1st tier cost 100 orbs to upgrade - Health-Tiers: - '1': 100 - '2': 200 - '3': 350 - '4': 500 - Damage-Tiers: - '1': 150 - '2': 300 - '3': 450 - '4': 600 - Speed-Tiers: - '1': 50 - '2': 100 - '3': 150 - '4': 250 - Final-Defense-Tiers: - '1': 200 - '2': 350 - Swarm-Awareness-Tiers: - '1': 200 - '2': 350 - - -# Don't edit it. But who's stopping you? It's your server! -# Really, don't edit ;p -# You edited it, huh? Next time hurt yourself! -Do-Not-Edit: - File-Version: 1 - Core-Version: 1 \ No newline at end of file diff --git a/src/main/resources/internal/enemies_map.yml b/src/main/resources/internal/enemies_map.yml new file mode 100644 index 000000000..18d089029 --- /dev/null +++ b/src/main/resources/internal/enemies_map.yml @@ -0,0 +1,640 @@ +# mode_type: +# wave_number: +# stage_number: +# - entity_id;amount + +classic_gold: + 1: + 1: + - VD_ZOMBIE;2 + 2: + 1: + - VD_ZOMBIE;4 + 3: + 1: + - VD_ZOMBIE;4 + - VD_BABY_ZOMBIE;1 + 4: + 1: + - VD_ZOMBIE;5 + - VD_BABY_ZOMBIE;1 + 2: + - VD_ZOMBIE;3 + - VD_BABY_ZOMBIE;1 + 5: + 1: + - VD_MEDIUM_ZOMBIE;1 + - VD_BABY_ZOMBIE;1 + - VD_ZOMBIE;4 + 2: + - VD_ZOMBIE;6 + 6: + 1: + - VD_MEDIUM_ZOMBIE;2 + - VD_ZOMBIE;5 + 2: + - VD_BABY_ZOMBIE;3 + - VD_ZOMBIE;4 + - VD_PLAYER_BUSTER;1 + 7: + 1: + - VD_MEDIUM_ZOMBIE;2 + - VD_BABY_ZOMBIE;2 + - VD_ZOMBIE;6 + - VD_PLAYER_BUSTER;1 + 2: + - VD_ZOMBIE;6 + 8: + 1: + - VD_MEDIUM_ZOMBIE;3 + - VD_BABY_ZOMBIE;1 + - VD_ZOMBIE;7 + 2: + - VD_BABY_ZOMBIE;4 + - VD_MEDIUM_ZOMBIE;1 + - VD_PLAYER_BUSTER;1 + - VD_ZOMBIE;3 + 9: + 1: + - VD_MEDIUM_ZOMBIE;3 + - VD_BABY_ZOMBIE;2 + - VD_ZOMBIE;8 + 2: + - VD_PLAYER_BUSTER;2 + - VD_ZOMBIE;6 + 10: + 1: + - VD_HORDE_ZOMBIE;15 + - VD_RUNNER_ZOMBIE;2 + 2: + - VD_HORDE_ZOMBIE;10 + - VD_BABY_ZOMBIE;5 + - VD_MEDIUM_ZOMBIE;2 + 11: + 1: + - VD_MEDIUM_ZOMBIE;2 + - VD_ZOMBIE;10 + - VD_RUNNER_ZOMBIE;2 + - VD_BABY_ZOMBIE;3 + 2: + - VD_PLAYER_BUSTER;3 + - VD_ZOMBIE;6 + - VD_MEDIUM_ZOMBIE;2 + 12: + 1: + - VD_MEDIUM_ZOMBIE;5 + - VD_BABY_ZOMBIE;4 + - VD_ZOMBIE;10 + 2: + - VD_ZOMBIE;6 + - VD_MEDIUM_ZOMBIE;5 + - VD_RUNNER_ZOMBIE;3 + - VD_PLAYER_BUSTER;2 + 13: + 1: + - VD_MEDIUM_ZOMBIE;5 + - VD_BABY_ZOMBIE;4 + - VD_ZOMBIE;10 + - VD_PLAYER_BUSTER;2 + 2: + - VD_MEDIUM_ZOMBIE;10 + - VD_ZOMBIE;5 + - VD_BABY_ZOMBIE;2 + 14: + 1: + - VD_MEDIUM_ZOMBIE;5 + - VD_PLAYER_BUSTER;2 + - VD_HORDE_ZOMBIE;20 + 2: + - VD_HORDE_ZOMBIE;15 + - VD_RUNNER_ZOMBIE;3 + - VD_BABY_ZOMBIE;2 + 3: + - VD_MEDIUM_ZOMBIE;5 + 15: + 1: + - VD_HARD_ZOMBIE;2 + - VD_MEDIUM_ZOMBIE;6 + - VD_ZOMBIE;12 + 2: + - VD_BABY_ZOMBIE;6 + - VD_PLAYER_BUSTER;4 + - VD_RUNNER_ZOMBIE;6 + 3: + - VD_ZOMBIE;10 + 16: + 1: + - VD_HARD_ZOMBIE;3 + - VD_MEDIUM_ZOMBIE;8 + - VD_BABY_ZOMBIE;3 + - VD_ZOMBIE;10 + 2: + - VD_HARD_ZOMBIE;2 + - VD_MEDIUM_ZOMBIE;5 + - VD_RUNNER_ZOMBIE;4 + 3: + - VD_PLAYER_BUSTER;2 + - VD_ZOMBIE;8 + - VD_BABY_ZOMBIE;4 + 17: + 1: + - VD_HARD_ZOMBIE;3 + - VD_MEDIUM_ZOMBIE;10 + - VD_PLAYER_BUSTER;2 + - VD_ZOMBIE;12 + 2: + - VD_HORDE_ZOMBIE;20 + - VD_RUNNER_ZOMBIE;5 + 3: + - VD_HORDE_ZOMBIE;10 + - VD_BABY_ZOMBIE;4 + 18: + 1: + - VD_HARD_ZOMBIE;8 + - VD_BABY_ZOMBIE;8 + - VD_HORDE_ZOMBIE;20 + 2: + - VD_HORDE_ZOMBIE;15 + - VD_PLAYER_BUSTER;5 + - VD_MEDIUM_ZOMBIE;4 + 3: + - VD_HORDE_ZOMBIE;10 + - VD_RUNNER_ZOMBIE;5 + 19: + 1: + - VD_HARD_ZOMBIE;5 + - VD_MEDIUM_ZOMBIE;10 + - VD_BABY_ZOMBIE;3 + - VD_ZOMBIE;12 + 2: + - VD_MEDIUM_ZOMBIE;5 + - VD_RUNNER_ZOMBIE;10 + - VD_PLAYER_BUSTER;2 + 3: + - VD_ZOMBIE;10 + 20: + 1: + - VD_TANK_ZOMBIE;1 + - VD_HARD_ZOMBIE;6 + - VD_MEDIUM_ZOMBIE;12 + 2: + - VD_PLAYER_BUSTER;2 + - VD_BABY_ZOMBIE;5 + - VD_ZOMBIE;10 + - VD_MEDIUM_ZOMBIE;8 + 3: + - VD_RUNNER_ZOMBIE;5 + - VD_ZOMBIE;10 + 21: + 1: + - VD_TANK_ZOMBIE;2 + - VD_HARD_ZOMBIE;8 + - VD_MEDIUM_ZOMBIE;16 + 2: + - VD_ZOMBIE;20 + - VD_PLAYER_BUSTER;3 + 3: + - VD_RUNNER_ZOMBIE;8 + - VD_HARD_ZOMBIE;3 + 22: + 1: + - VD_TANK_ZOMBIE;2 + - VD_MEDIUM_ZOMBIE;7 + - VD_HORDE_ZOMBIE;20 + 2: + - VD_HORDE_ZOMBIE;15 + - VD_BABY_ZOMBIE;5 + - VD_RUNNER_ZOMBIE;5 + 3: + - VD_HORDE_ZOMBIE;10 + - VD_HARD_ZOMBIE;10 + - VD_ZOMBIE;5 + 23: + 1: + - VD_TANK_ZOMBIE;3 + - VD_HARD_ZOMBIE;5 + - VD_MEDIUM_ZOMBIE;10 + - VD_ZOMBIE;10 + 2: + - VD_TANK_ZOMBIE;1 + - VD_HARD_ZOMBIE;8 + - VD_MEDIUM_ZOMBIE;12 + 3: + - VD_RUNNER_ZOMBIE;5 + - VD_PLAYER_BUSTER;5 + - VD_BABY_ZOMBIE;3 + 24: + 1: + - VD_TANK_ZOMBIE;6 + - VD_HARD_ZOMBIE;10 + - VD_BABY_ZOMBIE;10 + 2: + - VD_BABY_ZOMBIE;10 + - VD_RUNNER_ZOMBIE;15 + 3: + - VD_PLAYER_BUSTER;5 + - VD_BABY_ZOMBIE;5 + - VD_ZOMBIE;5 + 25: + 1: + - VD_MEDIUM_ZOMBIE;10 + - VD_ZOMBIE;8 + - VD_KAMIKAZE_ZOMBIE;6 + 2: + - VD_TANK_ZOMBIE;4 + - VD_HARD_ZOMBIE;10 + - VD_MEDIUM_ZOMBIE;14 + 3: + - VD_BABY_ZOMBIE;5 + - VD_ZOMBIE;10 + - VD_KAMIKAZE_ZOMBIE;3 + 26: + 1: + - VD_TANK_ZOMBIE;5 + - VD_HARD_ZOMBIE;10 + - VD_MEDIUM_ZOMBIE;15 + 2: + - VD_KAMIKAZE_ZOMBIE;2 + - VD_MEDIUM_ZOMBIE;8 + - VD_BABY_ZOMBIE;5 + 3: + - VD_ZOMBIE;10 + - VD_PLAYER_BUSTER;3 + 4: + - VD_MEDIUM_ZOMBIE;5 + - VD_ZOMBIE;10 + 27: + 1: + - VD_HORDE_ZOMBIE;25 + - VD_KAMIKAZE_ZOMBIE;5 + 2: + - VD_TANK_ZOMBIE;5 + - VD_HORDE_ZOMBIE;10 + - VD_BABY_ZOMBIE;10 + 3: + - VD_BABY_ZOMBIE;5 + - VD_HORDE_ZOMBIE;15 + 4: + - VD_KAMIKAZE_ZOMBIE;5 + - VD_HORDE_ZOMBIE;10 + 28: + 1: + - VD_TANK_ZOMBIE;5 + - VD_HARD_ZOMBIE;15 + - VD_ZOMBIE;25 + 2: + - VD_KAMIKAZE_ZOMBIE;2 + - VD_PLAYER_BUSTER;2 + - VD_BABY_ZOMBIE;5 + - VD_ZOMBIE;5 + 3: + - VD_MEDIUM_ZOMBIE;10 + - VD_ZOMBIE;5 + 4: + - VD_TANK_ZOMBIE;2 + 29: + 1: + - VD_TANK_ZOMBIE;6 + - VD_HARD_ZOMBIE;10 + - VD_MEDIUM_ZOMBIE;20 + 2: + - VD_KAMIKAZE_ZOMBIE;1 + - VD_BABY_ZOMBIE;3 + - VD_HARD_ZOMBIE;10 + 3: + - VD_ZOMBIE;10 + - VD_PLAYER_BUSTER;10 + 4: + - VD_BABY_ZOMBIE;5 + - VD_MEDIUM_ZOMBIE;5 + 30: + 1: + - VD_MEDIUM_ZOMBIE;25 + - VD_ZOMBIE;10 + - VD_INVISIBLE_RUNNER_ZOMBIE;2 + 2: + - VD_TANK_ZOMBIE;5 + - VD_HARD_ZOMBIE;15 + 3: + - VD_HARD_ZOMBIE;10 + - VD_KAMIKAZE_ZOMBIE;2 + 4: + - VD_BABY_ZOMBIE;7 + - VD_PLAYER_BUSTER;5 + - VD_INVISIBLE_RUNNER_ZOMBIE;1 + 31: + 1: + - VD_TANK_ZOMBIE;7 + - VD_HARD_ZOMBIE;14 + - VD_BABY_ZOMBIE;10 + - VD_ZOMBIE;8 + 2: + - VD_INVISIBLE_RUNNER_ZOMBIE;2 + - VD_PLAYER_BUSTER;5 + - VD_ZOMBIE;10 + 3: + - VD_TANK_ZOMBIE;5 + - VD_HARD_ZOMBIE;8 + 4: + - VD_BABY_ZOMBIE;5 + - VD_KAMIKAZE_ZOMBIE;1 + - VD_ZOMBIE;10 + 32: + 1: + - VD_HORDE_ZOMBIE;25 + - VD_INVISIBLE_RUNNER_ZOMBIE;2 + 2: + - VD_HORDE_ZOMBIE;10 + - VD_BABY_ZOMBIE;10 + - VD_TANK_ZOMBIE;5 + 3: + - VD_HORDE_ZOMBIE;15 + - VD_TANK_ZOMBIE;5 + - VD_KAMIKAZE_ZOMBIE;2 + 4: + - VD_HORDE_ZOMBIE;10 + - VD_KAMIKAZE_ZOMBIE;5 + - VD_PLAYER_BUSTER;2 + 33: + 1: + - VD_TANK_ZOMBIE;15 + - VD_HARD_ZOMBIE;15 + - VD_BABY_ZOMBIE;5 + - VD_INVISIBLE_RUNNER_ZOMBIE;2 + 2: + - VD_PLAYER_BUSTER;5 + - VD_HARD_ZOMBIE;3 + - VD_ZOMBIE;15 + 3: + - VD_TANK_ZOMBIE;5 + - VD_KAMIKAZE_ZOMBIE;2 + - VD_HARD_ZOMBIE;8 + 4: + - VD_INVISIBLE_RUNNER_ZOMBIE;2 + - VD_BABY_ZOMBIE;5 + 34: + 1: + - VD_TANK_ZOMBIE;12 + - VD_HARD_ZOMBIE;8 + - VD_ZOMBIE;10 + - VD_KAMIKAZE_ZOMBIE;3 + 2: + - VD_BABY_ZOMBIE;10 + - VD_TANK_ZOMBIE;8 + - VD_KAMIKAZE_ZOMBIE;2 + - VD_PLAYER_BUSTER;3 + 3: + - VD_TANK_ZOMBIE;5 + - VD_HARD_ZOMBIE;10 + - VD_ZOMBIE;5 + 4: + - VD_INVISIBLE_RUNNER_ZOMBIE;3 + - VD_ZOMBIE;7 + 35: + 1: + - VD_TANK_ZOMBIE;10 + - VD_HARD_ZOMBIE;20 + - VD_INVISIBLE_RUNNER_ZOMBIE;3 + 2: + - VD_HARD_ZOMBIE;10 + - VD_ZOMBIE;10 + - VD_BABY_ZOMBIE;5 + 3: + - VD_TANK_ZOMBIE;10 + - VD_INVISIBLE_RUNNER_ZOMBIE;3 + 4: + - VD_KAMIKAZE_ZOMBIE;2 + - VD_PLAYER_BUSTER;2 + - VD_ZOMBIE;10 + 36: + 1: + - VD_CONQUEROR_ZOMBIE;3 + - VD_TANK_ZOMBIE;10 + - VD_ZOMBIE;20 + - VD_BABY_ZOMBIE;5 + 2: + - VD_CONQUEROR_ZOMBIE;2 + - VD_TANK_ZOMBIE;10 + - VD_KAMIKAZE_ZOMBIE;5 + 3: + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + - VD_CONQUEROR_ZOMBIE;2 + 4: + - VD_ZOMBIE;20 + - VD_CONQUEROR_BOSS_ZOMBIE;2 + 37: + 1: + - VD_CONQUEROR_BOSS_ZOMBIE;5 + - VD_HORDE_ZOMBIE;30 + - VD_TANK_ZOMBIE;5 + 2: + - VD_HORDE_ZOMBIE;15 + - VD_CONQUEROR_ZOMBIE;5 + - VD_BABY_ZOMBIE;5 + 3: + - VD_HORDE_ZOMBIE;10 + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + 4: + - VD_HORDE_ZOMBIE;10 + - VD_CONQUEROR_BOSS_ZOMBIE;2 + 38: + 1: + - VD_CONQUEROR_ZOMBIE;6 + - VD_TANK_ZOMBIE;12 + - VD_BABY_ZOMBIE;10 + 2: + - VD_CONQUEROR_BOSS_ZOMBIE;5 + - VD_TANK_ZOMBIE;10 + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + 3: + - VD_TANK_ZOMBIE;8 + - VD_CONQUEROR_ZOMBIE;10 + - VD_KAMIKAZE_ZOMBIE;5 + 4: + - VD_TANK_ZOMBIE;10 + - VD_BABY_ZOMBIE;5 + 39: + 1: + - VD_CONQUEROR_ZOMBIE;8 + - VD_TANK_ZOMBIE;15 + - VD_KAMIKAZE_ZOMBIE;2 + 2: + - VD_CONQUEROR_BOSS_ZOMBIE;10 + - VD_TANK_ZOMBIE;8 + - VD_ZOMBIE;10 + 3: + - VD_KAMIKAZE_ZOMBIE;5 + - VD_ZOMBIE;10 + 4: + - VD_TANK_ZOMBIE;10 + - VD_CONQUEROR_ZOMBIE;5 + 40: + 1: + - VD_CONQUEROR_ZOMBIE;10 + - VD_TANK_ZOMBIE;10 + - VD_INVISIBLE_BABY_ZOMBIE;3 + 2: + - VD_CONQUEROR_BOSS_ZOMBIE;10 + - VD_TANK_ZOMBIE;10 + 3: + - VD_ZOMBIE;10 + - VD_INVISIBLE_RUNNER_ZOMBIE;2 + 4: + - VD_TANK_ZOMBIE;10 + - VD_CONQUEROR_ZOMBIE;6 + 5: + - VD_INVISIBLE_BABY_ZOMBIE;5 + - VD_ZOMBIE;10 + 41: + 1: + - VD_CONQUEROR_ZOMBIE;15 + - VD_ZOMBIE;15 + - VD_INVISIBLE_BABY_ZOMBIE;5 + 2: + - VD_CONQUEROR_BOSS_ZOMBIE;10 + - VD_ZOMBIE;10 + 3: + - VD_KAMIKAZE_ZOMBIE;5 + - VD_ZOMBIE;10 + 4: + - VD_CONQUEROR_ZOMBIE;10 + 5: + - VD_INVISIBLE_BABY_ZOMBIE;10 + 42: + 1: + - VD_CONQUEROR_BOSS_ZOMBIE;10 + - VD_HORDE_ZOMBIE;25 + 2: + - VD_HORDE_ZOMBIE;20 + - VD_INVISIBLE_BABY_ZOMBIE;5 + 3: + - VD_HORDE_ZOMBIE;15 + - VD_ZOMBIE;8 + 4: + - VD_HORDE_ZOMBIE;10 + 5: + - VD_HORDE_ZOMBIE;5 + 43: + 1: + - VD_CONQUEROR_BOSS_ZOMBIE;15 + - VD_ZOMBIE;15 + 2: + - VD_CONQUEROR_ZOMBIE;15 + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + - VD_INVISIBLE_BABY_ZOMBIE;5 + 3: + - VD_ZOMBIE;20 + 4: + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + - VD_ZOMBIE;5 + 5: + - VD_CONQUEROR_ZOMBIE;5 + 44: + 1: + - VD_CONQUEROR_BOSS_ZOMBIE;10 + - VD_ZOMBIE;15 + 2: + - VD_CONQUEROR_BOSS_ZOMBIE;15 + - VD_INVISIBLE_RUNNER_ZOMBIE;10 + 3: + - VD_ZOMBIE;25 + 4: + - VD_CONQUEROR_ZOMBIE;10 + 5: + - VD_INVISIBLE_BABY_ZOMBIE;5 + 45: + 1: + - VD_VILLAGER_SLAYER;2 + - VD_HORDE_ZOMBIE;25 + 2: + - VD_VILLAGER_SLAYER;2 + - VD_HORDE_ZOMBIE;20 + 3: + - VD_HORDE_ZOMBIE;15 + - VD_INVISIBLE_RUNNER_ZOMBIE;10 + 4: + - VD_HORDE_ZOMBIE;15 + - VD_CONQUEROR_ZOMBIE;5 + 5: + - VD_VILLAGER_SLAYER;3 + 46: + 1: + - VD_VILLAGER_SLAYER;10 + - VD_ZOMBIE;10 + 2: + - VD_CONQUEROR_ZOMBIE;15 + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + - VD_VILLAGER_SLAYER;1 + 3: + - VD_VILLAGER_SLAYER;3 + - VD_ZOMBIE;15 + 4: + - VD_ZOMBIE;10 + - VD_CONQUEROR_ZOMBIE;5 + 5: + - VD_VILLAGER_SLAYER;3 + 47: + 1: + - VD_VILLAGER_SLAYER;10 + - VD_ZOMBIE;10 + 2: + - VD_VILLAGER_SLAYER;5 + - VD_CONQUEROR_BOSS_ZOMBIE;10 + 3: + - VD_VILLAGER_SLAYER;5 + - VD_ZOMBIE;15 + 4: + - VD_VILLAGER_SLAYER;5 + - VD_CONQUEROR_ZOMBIE;10 + 5: + - VD_VILLAGER_SLAYER;5 + 48: + 1: + - VD_VILLAGER_SLAYER;12 + - VD_ZOMBIE;10 + 2: + - VD_VILLAGER_SLAYER;5 + - VD_CONQUEROR_BOSS_ZOMBIE;12 + 3: + - VD_VILLAGER_SLAYER;5 + - VD_INVISIBLE_BABY_ZOMBIE;3 + 4: + - VD_VILLAGER_SLAYER;5 + - VD_KAMIKAZE_ZOMBIE;5 + 5: + - VD_ZOMBIE;25 + 49: + 1: + - VD_VILLAGER_SLAYER;14 + - VD_ZOMBIE;10 + - VD_INVISIBLE_BABY_ZOMBIE;1 + 2: + - VD_VILLAGER_SLAYER;5 + - VD_CONQUEROR_BOSS_ZOMBIE;14 + 3: + - VD_VILLAGER_SLAYER;5 + - VD_INVISIBLE_RUNNER_ZOMBIE;5 + 4: + - VD_VILLAGER_SLAYER;5 + - VD_CONQUEROR_ZOMBIE;15 + 5: + - VD_ZOMBIE;20 + - VD_VILLAGER_SLAYER;5 + 50: + 1: + - VD_VILLAGER_SLAYER;15 + - VD_ZOMBIE;15 + 2: + - VD_VILLAGER_SLAYER;8 + - VD_CONQUEROR_BOSS_ZOMBIE;15 + 3: + - VD_VILLAGER_SLAYER;5 + - VD_CONQUEROR_ZOMBIE;10 + 4: + - VD_VILLAGER_SLAYER;5 + - VD_KAMIKAZE_ZOMBIE;10 + 5: + - VD_ZOMBIE;15 + - VD_VILLAGER_SLAYER;2 + 6: + - VD_INVISIBLE_VILLAGER_SLAYER;1 \ No newline at end of file diff --git a/src/main/resources/kits.yml b/src/main/resources/kits.yml index 11c06e355..d8719b3a2 100644 --- a/src/main/resources/kits.yml +++ b/src/main/resources/kits.yml @@ -4,73 +4,58 @@ # https://www.spigotmc.org/resources/55010/ # -# Only kits that inherits level kit feature will be available to modify here. -# Filling here other kits won't change anything as they inherits premium or free kit. -Required-Level: - ZombieFinder: 1 - Archer: 2 - Puncher: 4 - Healer: 6 - Looter: 8 - Runner: 10 - MediumTank: 12 - Worker: 15 - GolemFriend: 18 - Terminator: 20 - Hardcore: 100 +# When integration with Vault is available players can purchase kits for one game via economy plugin +Kit-One-Time-Prices: + Knight: 0 #free because default + Builder: 60 + Tornado: 60 + Shot-Bow: 80 + Medic: 80 + Cleaner: 100 + Pets-Friend: 100 + Terminator: 120 + Crusader: 140 + Wizard: 160 # Here you can disable plugily projects preconfigured kits. # Set 'false' to disable. Enabled-Game-Kits: # Knight is default kit, it cannot be disabled #Knight: true - LightTank: true - Archer: true - GolemFriend: true - Hardcore: true - Healer: true - Looter: true - MediumTank: true - Puncher: true - Runner: true Terminator: true - Worker: true - ZombieFinder: true - Blocker: true Cleaner: true - DogFriend: true - HeavyTank: true Medic: true - Naked: true - PremiumHardcore: true ShotBow: true - Teleporter: true Tornado: true Wizard: true + PetsFriend: true + Builder: true + Crusader: true # The cooldown in seconds for some kit items Kit-Cooldown: - Cleaner: 60 + Cleaner: + Cleansing-Wand: + I: 45 + II: 40 + III: 35 + Poplust: 75 Shot-Bow: 5 Wizard: - Essence: 15 - Staff: 1 + Flower: 15 + Bloodlust: 70 Zombie-Finder: 30 - -# The settings for some kits -Kit-Settings: - Cleaner: - # The maximum health for the enemies to be removed - Max-Health: 2048 - # The maximum amount of enemies that this kit can remove - Max-Amount: 50 - # From the start, how many enemies can this kit remove? - Base-Amount: 10 - # The amount of the removed enemies will be increased after how many waves? - Increase-After-Wave: 5 - # How many amount will be added to the base amount? - # Set to 0 to disable - Increase-Amount: 5 + Medic: + Aura: + I: 30 + II: 15 + Homecoming: 60 + Tornado: + Monsoon: 20 + Final-Flight: 45 + Terminator: + Neverdeath: 20 + Motors-Overcharge: 60 # Don't edit it. But who's stopping you? It's your server! diff --git a/src/main/resources/language.yml b/src/main/resources/language.yml index 2cec32762..e6df14447 100644 --- a/src/main/resources/language.yml +++ b/src/main/resources/language.yml @@ -9,6 +9,32 @@ # Some messages support their own placeholders # like %player%, %kit% etc. +# Applied in Village Defense Gold update +Gold-Messages: + New-Record-Reached: "%plugin_prefix% You've reached new record on this map with kit %value%!" + Kit-Selector: + Support-Section: + Name: "&a&lSUPPORT KITS" + Lore: + - "&7Kits specialized in either" + - "&7assisting allies or controlling" + - "&7the flow of the battle" + - "&7with their unique abilities!" + Damage-Section: + Name: "&a&lDAMAGE DEALER KITS" + Lore: + - "&7Kits focused on dealing" + - "&7huge amount of damage to" + - "&7swiftly kill hordes of" + - "&7undead enemies!" + Tank-Section: + Name: "&a&lTANK KITS" + Lore: + - "&7Kits centered around" + - "&7capturing most of enemies" + - "&7damage on themselves giving" + - "&7safe space to other players!" + # # Color scheme # @@ -217,17 +243,17 @@ In-Game: Not-Enough-Space-For-Party: "%color_chat_issue%%plugin_prefix% Your party is bigger than free places on the arena %arena_name%" Game-End: Summary: - - "&a&m--------------------------------------------------" - - "%plugin_name%" - "" - - "%arena_summary%" - - "%arena_summary_player%" + - "&e&lVillage Defense" + - " %arena_summary% - %arena_summary_player%" + - "" + - " &a&lSURVIVORS:" + - " {player_count_summary}" - "" - - "&e&lReached wave | %arena_option_wave% (best %user_statistic_highest_wave%)" - - "&6&lTotal zombies killed | %arena_option_total_killed_zombies%" - - "&c&lTotal coins spent | %arena_option_total_orbs_spent%" + - " &a&lWave:&7 %arena_option_wave% (record %user_statistic_highest_wave%)" + - " &c&lZombies Killed:&7 %arena_option_total_killed_zombies% (%zombies_killed_record%)" + - " &e&lCoins Spent:&7 %arena_option_total_orbs_spent% (%coins_spent_record%)" - "" - - "&a&m--------------------------------------------------" Placeholders: Win: "&aYou won the game" Lose: "%color_chat_issue%You lost the game" @@ -237,6 +263,7 @@ In-Game: Villagers: "%color_chat_issue%All villagers died!" Survived: "&aYou survived all the waves" Admin: + Nothing-To-Clean: "%color_chat_issue%%plugin_prefix% No entities to clean!" Set-Starting-In-To-0: "%plugin_prefix% An admin set waiting time to 0. The game starts now!" Removed: Villagers: "%plugin_prefix% %player% has removed all the villagers!" @@ -247,11 +274,15 @@ In-Game: Wave: "%color_chat_issue%%plugin_prefix% Admin changed the wave to %number%" Village: Rotten-Flesh-Level-Up: "%plugin_prefix% The gods were happy with the rotten flesh! Therefor they gave you an &aextra heart!" - You-Feel-Refreshed: "%plugin_prefix% You feel refreshed!" # Do not use spaces between villager names. No limit in names size and amount :) Villager: Died: "%color_chat_issue%%plugin_prefix% A villager has died!" Names: "Jagger,Kelsey,Kelton,Haylie,Harlow,Howard,Wulffric,Winfred,Ashley,Bailey,Beckett,Alfredo,Alfred,Adair,Edgar,ED,Eadwig,Edgaras,Buckley,Stanley,Nuffley,Mary,Jeffry,Rosaly,Elliot,Harry,Sam,Rosaline,Tom,Ivan,Kevin,Adam" + Special-Offer: "&e&l-10% SHOP OFFER" + Offering-Sale: "%plugin_prefix% Before wave starts, villager %value% offers &e&l-10% SHOP DEAL" + Rotten-Offer: "&c&lSELL ME ROTTEN FLESH" + Rotten-Sale: "%plugin_prefix% A wandering traded has arrived, trade your %value% for bonus hearts and orbs before wave starts!" + Pinata-Event: "%plugin_prefix% A wild Pinata has appeared! Punch it to earn some loot!" Wave: Stuck-Zombies: "%color_chat_issue%%plugin_prefix% It seems like the last zombie got stuck somewhere. No worries! The gods killed him for you!" Spectator-Warning: "%color_chat_issue%%plugin_prefix% You are a spectator! You can't do anything until you'd respawned at the start of the next wave!" @@ -262,17 +293,22 @@ In-Game: Title: Start: "20,30,20;Wave %number%;" End: "20,30,20;Wave %number% ended;" - Orbs: - Pickup: "+ %number% orbs" + Start-3: "10,20,10;;&a&l3" + Start-2: "10,20,10;;&e&l2" + Start-1: "10,20,10;;&c&l1" Entities: + Cant-Ride-Other: "%color_chat_issue%%plugin_prefix% You can't ride pet you don't own!" + Cant-Upgrade-This: "%color_chat_issue%%plugin_prefix% You can't upgrade this pet!" + Cant-Upgrade-Baby: "%color_chat_issue%%plugin_prefix% You can't upgrade growing baby pets!" + Cant-Upgrade-Other: "%color_chat_issue%%plugin_prefix% You can't upgrade pet you don't own!" Wolf: - Spawn: "%plugin_prefix% Wolf spawned in the village!" - Name: "%player%'s Wolf" - Death: "%color_chat_issue%%plugin_prefix% One of your wolves were killed!" + Name: "%player%'s Wolf &8(&7LVL %number%&8) %value%" + Baby-Name: "%player%'s Wolf &8(&7Growing&8) %value%" Golem: - Spawn: "%plugin_prefix% Golem spawned in the village!" - Name: "%player%'s Golem" - Cant-Ride-Other: "%color_chat_issue%%plugin_prefix% You can't ride the golem of somebody else!" + Name: "%player%'s Golem &8(&7LVL %number%&8) %value%" + Zombie: + Stunned-Name: "&c&lSTUNNED" + Frenzy-Name: "&b&lIN FRENZY" Shop: GUI: "&lShop" Golem-Item-Name: "Spawn Golem" @@ -280,7 +316,13 @@ In-Game: Mob-Limit-Reached: "%color_chat_issue%%plugin_prefix% You can't buy mobs! You've reached the limit of %number% mobs!" Not-Enough-Currency: "%color_chat_issue%%plugin_prefix% You need more orbs to buy this item!" Currency: "orbs" + Wave-Lock: "&6Locked till wave %number%" + Item-Locked-Name: "&c&lITEM LOCKED" + Wave-Still-Locked: "%color_chat_issue%%plugin_prefix% This item will be unlocked at wave %number%!" Not-Defined: "%color_chat_issue%%plugin_prefix% Shop wasn't set up! Contact staff!" + Special-Offer: "&e&l-10% SPECIAL OFFER" + New-Shop-Offers: "%plugin_prefix% New offers are now available in Villager Shop!" + Auto-Armor-Equipped: "%plugin_prefix% Armor piece was equipped automatically!" # # Sign messages @@ -350,6 +392,10 @@ Kit: Not-Unlocked: "%color_chat_issue%%plugin_prefix% You haven't unlocked %value% yet!" Choose: "%plugin_prefix% You have chosen: %value%!" Cooldown: "%color_chat_issue%%plugin_prefix% Kit ability still on cooldown (%number%)!" + Locked-Till: "%color_chat_issue%%plugin_prefix% This ability is locked until wave %number%!" + Ability-Unlocked: "%color_chat_issue%%plugin_prefix% &7Ability %value% &7is now unlocked!" + Ability-Power-Increased: "%color_chat_issue%%plugin_prefix% %value% &7ability power has increased!" + Passive-Power-Increased: "%color_chat_issue%%plugin_prefix% &7Your passive power has increased!" Menu: Title: "Kit Menu" Lore: @@ -358,229 +404,490 @@ Kit: Unlock-At-Level: "Unlocks at level %number%" Unlock-In-Store: "&bUnlock this in the store!" Content: - Cleaner: - Name: "&bCleaner" - Description: - - "The cleaner has a special ability." - - "With this ability, he can make all the" - - "zombies disappear. However, it takes" - - "a lot of effort to do this!" - Game-Item: - Name: "&6Cleaner Wand!" - Description: - - "Right click to kill all zombies!" - - "Cooldown: 60 seconds" - Cleaned: - Map: "&b%player% has cleaned the map!" - Nothing: "&aThe map is already empty!" #WARNING: used for admin clean commands too!!! - Zombie-Teleporter: - Name: "&2Zombie Teleporter" - Description: - - "Teleport those zombies to you!" - - "Many people think this is the worst kit!" - - "I must admit they are totally wrong!" - Game-Item: - GUI: "Zombie Teleporter" - Name: "Zombie Teleporter" - Description: - - "Teleport zombies to you!" - Teleport: - Zombie: "&aTeleported weakened zombie to you!" - Not-Found: "&cThere are no zombies to teleport!" Knight: Name: "&2Knight" Description: - "This is the one and only knight kit!" - "Many people think this is the worst kit!" - "I must admit they are totally wrong!" - Light-Tank: - Name: "&2Light Tank" - Description: - - "You are Junior tank!" - Archer: - Name: "&6Archer" - Description: - - "Start with a bow, leather armor and a wooden sword." - - "Archers are loved by the villagers, know that!" - Puncher: - Name: "&6Puncher" - Description: - - "Punch those zombies back with your epic shovel!" - - "Knockback V is not unknown to you!" - Healer: - Name: "&6Healer" - Description: - - "Being a healer is the same as being loved." - - "You are able to heal your teammates and villagers!" - - "Gets a restock every wave!" - Looter: - Name: "&6Looter" - Description: - - "Get one additional rotten flesh" - - "on every zombie kill!" - Runner: - Name: "&6Runner" - Description: - - "Parkour is your passion!" - - "You are able to run faster than everybody else." - - "You have also the ability to jump higher." - Medium-Tank: - Name: "&6Medium Tank" - Description: - - "Start off with 6 more hearts!" - - "Don't be afraid!" - - "You have plenty hearts left to lose!" - Worker: - Name: "&6Worker" + Cleaner: + Name: "&bCleaner" Description: - - "Get each round a door and start off" - - "with 2 additional doors. This way you" - - "can replace the doors!" + - "&6&lGAME POWER: &7poor/&7strong/&7mediocre" + - "&6&lCLASS: &7mixed, damage dealer" + - "" + - "&6&lABILITIES:" + - "&a&l• POP AWE (PASSIVE):" + - " &7Every 5 seconds pop random" + - " &71/2/3 alive zombies" + - "&a&l• CLEANSING STICK:" + - " &7On use pop random 10/15/20" + - " &7alive zombies with a delay" + - " &7of 0.5s every 5 pops" + - " &7(&c&lCOOLDOWN 45/&c&l35/&c&l30s&7)" + - "&e&l• POPLUST (ULTIMATE)" + - " &7On use every enemy can be" + - " &7oneshot and popped by yourself" + - " &7Unpoppable (&4&l☄&7) units receive 15%" + - " &7maximum health damage instead" + - " &7(&c&lCAST TIME -/&c&l7&7/&c&l11s&7, &c&lCOOLDOWN 75s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" Game-Item: - Chat: "&aDoor placed!" - Dog-Friend: - Name: "&bDog Friend" - Description: - - "Start off with three dogs and" - - "get one extra dog every wave!" - Hardcore: - Name: "&6Hardcore" - Description: - - "You'll see yourself" - - "why this is hardcore" - Golem-Friend: - Name: "&6Golem Friend" - Description: - - "Start with a golem and" - - "get new every 5 waves!" + Cleansing-Stick: + Name: "&6&lCLEANSING STICK" + Description: + - "On use pop random 10/20/25" + - "alive zombies with a delay" + - "of 0.5s every 5 pops" + - "&c&lCOOLDOWN: &745/&735/&730s" + Activate: "&7Lets wipe them up!" + Poplust: + Name: "&e&lPOPLUST &7(Ultimate)" + Description: + - "On use every enemy can be" + - "oneshot and popped by yourself" + - "Unpoppable (☄) units receive 15%" + - "maximum health damage instead" + - "&c&lCAST TIME: &7-/&77/&711s, &c&lCOOLDOWN &775s" + Activate: "&7Poplust incoming!" + Active-Title: "0,20,0;;&e&lONESHOT ENEMIES NOW!" + Active-Action-Bar: + - "&e&lPOPLUST ACTIVE &7(%number%s)" + - "&c&lPOPLUST ACTIVE &7(%number%s)" Tornado: Name: "&bTornado" Description: - - "Spawn in an awesome tornado!" + - "&6&lGAME POWER: &7?/&7?/&7?" + - "&6&lCLASS: &7mixed, support" + - "" + - "&6&lABILITIES:" + - "&a&l• CALL OF THE WIND (PASSIVE):" + - " &7Each turn you receive 2/3/5 tornadoes," + - " &7which push back and damage enemies" + - "&a&l• MONSOON:" + - " &7Creates wind sphere that knocks back" + - " &7and permanently slows all enemies" + - " &7(&c&lCAST TIME 6/&c&l9/&c&l12s&7, &c&lCOOLDOWN 20s&7)" + - "&e&l• FINAL FLIGHT (ULTIMATE):" + - " &7On cast your attacks cause enemies" + - " &7to levitate and receive 25% max health" + - " &7damage per second that lasts for 4s" + - " &7(&c&lCAST TIME 10s&7, &c&lCOOLDOWN 45s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" + Game-Item: + Tornado: + Name: "&6&lTORNADO TIME" + Description: + - "Right click to spawn a" + - "tornado at your location!" + Monsoon: + Name: "&6&lMONSOON" + Description: + - "On cast creates wind sphere that knocks back" + - "and permanently slows enemies" + - "&c&lCOOLDOWN: &720s" + Active-Action-Bar: + - "&e&lMONSOON ACTIVE &7(%number%s)" + - "&c&lMONSOON ACTIVE &7(%number%s)" + Final-Flight: + Name: "&e&lFINAL FLIGHT &7(Ultimate)" + Description: + - "On cast your attacks cause enemies" + - "to levitate and receive 25% max health" + - "damage per second that lasts for 4s" + - "&c&lCAST TIME: &710s, &c&lCOOLDOWN &740s" + Active-Action-Bar: + - "&e&lFINAL FLIGHT ACTIVE &7(%number%s)" + - "&c&lFINAL FLIGHT ACTIVE &7(%number%s)" + Builder: + Name: "&6Builder" + Description: + - "&6&lGAME POWER: &7poor/&7mediocre/&7mediocre" + - "&6&lCLASS: &7mixed, support" + - "" + - "&6&lABILITIES:" + - "&a&l• RESTOCK (PASSIVE):" + - " &7Receive 1 door every 5/&73/&72 waves" + - " &7to replace broken ones and receive" + - " &71/&72/&73 fences every wave to block" + - " &7enemies that last 10/&712/&714s" + - "&a&l• EARTHED:" + - " &7On use every ally cannot be knocked" + - " &7back by any non explosion damage" + - " &7(&c&lCAST TIME 10s&7, &c&lCOOLDOWN 20s&7)" + - "&e&l• BLOCKAGE (ULTIMATE)" + - " &7On use enemies cannot damage nor" + - " &7destroy any door on the map" + - " &7(&c&lCAST TIME 15s&7, &c&lCOOLDOWN -/&c&l40/&c&l30s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" Game-Item: - Name: "Tornado Time" - Description: - - "Right click to spawn a" - - "tornado at your location!" + Fence: + Name: "&6&lBLOCKING FENCE" + Description: + - "On use block path for enemies" + - "that last 10/&712/&714s" + Door: + Name: "&6&lREPLACEABLE DOOR" + Description: + - "Replace a broken door with this one!" + Earthed: + Name: "&6&lEARTHED" + Description: + - "On use every ally cannot be knocked" + - "back by any non explosion damage" + - "&7(&c&lCAST TIME 10s&7, &c&lCOOLDOWN 20s&7)" + Activate: "&7Everyone is now unshaken!" + Active-Action-Bar: + - "&e&lEARTHED ACTIVE &7(%number%s)" + - "&c&lEARTHED ACTIVE &7(%number%s)" + Knock-Protected-By-Action-Bar: + - "&e&lYOU'RE KNOCKBACK PROTECTED BY &7%player%" + - "&c&lYOU'RE KNOCKBACK PROTECTED BY &7%player%" + Blockage: + Name: "&e&lBLOCKAGE &7(Ultimate)" + Description: + - "On use enemies cannot damage nor" + - "destroy any door on the map" + - "&c&lCAST TIME 15s&7, &c&lCOOLDOWN -/&c&l40/&c&l30s&7)" + Activate: "&7Hardened every door on the map!" Terminator: Name: "&6Terminator" Description: - - "Easily kill those zombies" - - "with your strength powers!" - Teleporter: - Name: "&bTeleporter" - Description: - - "Everybody is astonished about your teleportation." - - "Nobody knows how to do it except you! Due to this," - - "you are able to teleport to villagers" - - "that need help in no time!" + - "&6&lGAME POWER: &7mediocre/&7strong/&7strong" + - "&6&lCLASS: &7melee, damage dealer" + - "" + - "&6&lABILITIES:" + - "&a&l• CONTINUOUS ADAPTATION (PASSIVE):" + - " &7Receive augment in early/&7mid/&7late" + - " &7dropped by last alive enemy on map" + - " &7to choose random character upgrade" + - "&a&l• BLADE OF TERMINUS (PASSIVE):" + - " &7Receive sword that scales with waves:" + - " &e&lWAVE 5: &720% on-hit burn chance" + - " &e&lWAVE 10: &75% instakill chance" + - " &e&lWAVE 15: &76% lifesteal, 40% on-hit burn" + - " &e&lWAVE 20: &720% shared combust chance" + - " &e&lWAVE 25: &735% large knockback chance" + - " &e&lWAVE 30+: &7+1% dmg each wave" + - "&7(&c&lBELOW ARE UNLOCKED IN MID GAME&7)" + - "&a&l• NEVERDEATH &7(&c&lCOOLDOWN 20s&7):" + - " &7On use receive absorption for 15s" + - "&e&l• MOTORS OVERCHARGE (ULTIMATE)" + - " &7On use pull enemies to you, damage" + - " &7them for 35% of max health per sec, on" + - " &7end knock them away and instakill them" + - " &7(&c&lCAST TIME 10s&7, &c&lCOOLDOWN 50s&7)" Game-Item: - Name: "&rTeleportation Menu" - Description: - - "Right click to open teleportation menu!" - GUI: "Teleporter Menu" - Teleport: - Villager: "&aTeleported to the villager!" - Warning: "&4Village defense didn't found that villager! That villager is probably already dead!" - Player: "&aTeleported to %player%" - Not-Found: "&cPlayer not found! Try again!" - Heavy-Tank: - Name: "&bHeavy Tank" - Description: - - "Start off with iron armor and a double" - - "amount of hearts! Yup, that's right," - - "you'll be the last man standing!" + Terminus: + Name: "&6&lBLADE OF TERMINUS" + Description: + - "&7Terminus blade scales as game progresses:" + - " &e&lWAVE 5: &720% on-hit burn chance" + - " &e&lWAVE 10: &75% instakill chance" + - " &e&lWAVE 15: &76% lifesteal, 40% on-hit burn" + - " &e&lWAVE 20: &720% shared combust chance" + - " &e&lWAVE 25: &735% large knockback chance" + - " &e&lWAVE 30+: &7+1% dmg each wave" + Terminus-Augment: + Gui: + Augment-Applied: "&7Augment successfully applied!" + Choose-An-Augment: "&cChoose an augment first!" + First-Locked: "&c&lAUGMENT I LOCKED" + Second-Locked: "&c&lAUGMENT II LOCKED" + Third-Locked: "&c&lAUGMENT III LOCKED" + Locked-Lore: + - "&7This augment will unlock" + - "&7as the game progresses" + Neverdeath: + Name: "&6&lNEVERDEATH" + Description: + - "On use receive absorption for 15s," + - "the lower your health the higher" + - "the absorption effect" + - "&c&lCOOLDOWN &720s" + Activate: "&7Protocol &6&lNEVERDEATH &7active!" + Motors-Overcharge: + Name: "&e&lMOTORS OVERCHARGE &7(Ultimate)" + Description: + - "On use pull enemies to you, damage" + - "them for 35% of max health per sec, on" + - "end knock them away and instakill them" + - "&c&lCAST TIME &710s, &c&lCOOLDOWN &760s" + Activate: "&7Engaging kinematic motors, full power reached!" + Active-Action-Bar: + - "&e&lMOTORS OVERCHARGE ACTIVE &7(%number%s)" + - "&c&lMOTORS OVERCHARGE ACTIVE &7(%number%s)" Shot-Bow: - Name: "&bShotbow Master" + Name: "&6Shotbow Master" Description: - - "You invented a crazy shotbow!" - Blocker: - Name: "&bBlocker" - Description: - - "Hold the zombies back with" - - "your special barriers. These" - - "barriers last for 10 seconds" + - "&6&lGAME POWER: &7poor/strong/mediocre" + - "&6&lCLASS: &7ranged, support/&7damage dealer" + - "" + - "&6&lABILITIES:" + - "&a&l• BOW OF ATREUS (PASSIVE):" + - " &7Receive bow that scales with waves:" + - " &e&lWAVE 5: &7Knockback arrows" + - " &e&lWAVE 10: &7Igniting arrows" + - " &e&lWAVE 15: &710% weakness chance" + - " &e&lWAVE 20: &710% slowness chance" + - " &e&lWAVE 25: &710% AOE lightning on-hit" + - " &e&lWAVE 30: &75% oneshot chance" + - " &e&lWAVE 35+: &7+1% dmg each wave" + - "&a&l• PATH OF DESTINY (PASSIVE):" + - " &7Choose either to keep &e&lBow of Atreus" + - " &7or receive &6&lCrossbow of Power" + - " &7once you reach &c&lMID GAME &7state" + - "&a&l• CROSSBOW OF POWER (PASSIVE):" + - " &7Receive crossbow that scales with waves:" + - " &e&lWAVE 20: &7Piercing I enchant" + - " &e&lWAVE 25: &7Quickcharge II enchant" + - " &e&lWAVE 30: &7Piercing II enchant" + - " &e&lWAVE 35: &720% AOE lightning on-hit" + - " &e&lWAVE 40+: &7+1% dmg each wave" + - "&e&l• ARROW RAIN (ULTIMATE)" + - " &7On use launch -/&78/&712 arrows that" + - " &7knock enemies and oneshot them" + - " &7(&c&lCOOLDOWN 20s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" Game-Item: - Name: "Fence" - Description: - - "Place this barrier to hold back" - - "zombies! These barriers last for 10 seconds" - Place: - Success: "&aBarrier placed!" - Fail: "&cUnable to place barrier here" - Premium-Hardcore: - Name: "&bPremium Hardcore Master" - Description: - - "One hit most zombies with your OP sword!" - - "However be careful. this kit is only for" - - "the pros! Do not use it if you aren't a pro!" + Arrow-Rain: + Name: "&6&lARROW RAIN" + Description: + - "&7On use launch -/&78/&712 arrows that" + - "&7knock enemies and oneshot them" + - "&c&lCOOLDOWN &720s" Medic: Name: "&6Medic" Description: - - "This kit activates your passive powers." - - "Every time you hit a zombie, you have" - - "a 1/10 chance to heal the players" - - "in a 5 block radius around you." - Wild-Naked: - Name: "&bWild Naked" + - "&6&lGAME POWER: &7poor/mediocre/strong" + - "&6&lCLASS: &7mixed, support" + - "" + - "&6&lABILITIES:" + - "&a&l• FIRST AID (PASSIVE):" + - " &7Each zombie hit you have 10% chance to" + - " &7heal nearby allies by 0.5 heart and" + - " &7you heal allies and villagers on wave" + - " &7start for 1/2/3 hearts" + - "&a&l• HEALER AURA:" + - " &7Creates healing aura that heals" + - " &7allies and pets by -/2/4 hearts per sec" + - " &7(&c&lCAST TIME 10s&7, &c&lCOOLDOWN -/&c&l30/&c&l15s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" + - "&e&l• HOMECOMING (ULTIMATE):" + - " &7On cast all spectators are respawned" + - " &7and are given Speed Boost -/I/II and" + - " &7Damage Boost -/I/II for 30 seconds" + - " &7(&c&lCOOLDOWN 60s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" + Game-Item: + Aura: + Name: "&6&lHEALING AURA" + Description: + - "On cast creates healing aura" + - "that heals allies, wolves and golems" + - "2/4 hearts per second" + - "&c&lCAST TIME &710s, &c&lCOOLDOWN &7-/&730/&715s" + Active-Action-Bar: + - "&e&lHEALING AURA ACTIVE &7(%number%s)" + - "&c&lHEALING AURA ACTIVE &7(%number%s)" + Healed-By-Action-Bar: + - "&e&lYOU'RE BEING HEALED BY &7%player%" + - "&c&lYOU'RE BEING HEALED BY &7%player%" + Homecoming: + Name: "&e&lHOMECOMING &7(Ultimate)" + Description: + - "On cast all spectators are" + - "respawned and given Speed Boost -/I/II" + - "and Damage Boost -/I/II for 30s" + - "&c&lCOOLDOWN &760s" + Activate: "&7Come back my allies! We will not fall!" + Respawned-By-Title: "&eIt's not your time yet" + Respawned-By-Subtitle: "&7Respawned by %player%" + Crusader: + Name: "&bCrusader" + Description: + - "&6&lGAME POWER: &7mediocre/strong/strong" + - "&6&lCLASS: &7melee, tank" + - "" + - "&6&lABILITIES:" + - "&a&l• IRON WILL (PASSIVE):" + - " &7Every 3 hits you stun the enemy for" + - " &72/&73/&74s and receive 1/&72/&73 &b&lCOURAGE" + - " &7stacks, capped at 75. Receive blast" + - " &7resistance in mid game. Unstunnable" + - " &7(&7&l✶&7) enemies cannot be stunned" + - "&a&l• COURAGEOUS &7(&c&lCOOLDOWN 5s&7):" + - " &7Use &b&lCOURAGE &7stacks that apply:" + - " &e&l0 STACKS: &7absorption 1 for 5s" + - " &e&l10 STACKS: &7speed boost 1 for 5s" + - " &e&l20 STACKS: &725% instant heal" + - " &e&l30 STACKS: &750% instant heal" + - " &e&l40 STACKS: &7regen 1 for 8s" + - " &e&l50 STACKS: &7burn aura for 8s" + - " &e&l75 STACKS: &7stun shots for 8s" + - "&e&l• GLORY TO THE KING (ULTIMATE):" + - " &7On cast use all &b&lCOURAGE" + - " &7stacks to receive immortality" + - " &7for 10s and be healed after" + - " &7(&c&lCOOLDOWN -/&c&l40/&c&l25s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" + Game-Item: + Courageous: + Name: "&6&lCOURAGEOUS" + Description: + - "Use &b&lCOURAGE &7stacks that apply:" + - " &e&l0 STACKS: &7absorption 1 for 5s" + - " &e&l10 STACKS: &7speed boost 1 for 5s" + - " &e&l20 STACKS: &725% instant heal" + - " &e&l30 STACKS: &750% instant heal" + - " &e&l40 STACKS: &7regen 1 for 8s" + - " &e&l50 STACKS: &7burn aura for 8s" + - " &e&l75 STACKS: &7stun shots for 8s" + - "&c&lCOOLDOWN 5s" + Stacks: + Base: "&7%number%/&775 &b&lCOURAGE" + Max: "&7&lMAX &b&lCOURAGE" + Activate: "&7To the end, and then beyond, I fight on!" + Aura-Action-Bar: + - "&e&lBURN AURA ACTIVE &7(%number%s)" + - "&c&lBURN AURA ACTIVE &7(%number%s)" + Glory-To-The-King: + Name: "&e&lGLORY TO THE KING &7(Ultimate)" + Description: + - "On cast receive heal -/4/5 and" + - "absorption 3 for 20s and use all" + - "&b&lCOURAGE &7stacks, you cannot" + - "be killed for 10s" + - "&c&lCOOLDOWN -/&c&l40/&c&l25s" + Activate: "&7Death's scythe hesitates before my might!" + Active-Action-Bar: + - "&e&lGLORY TO THE KING ACTIVE &7(%number%s)" + - "&c&lGLORY TO THE KING ACTIVE &7(%number%s)" + Pets-Friend: + Name: "&bPets Friend" Description: - - "You are the ultimate master!" - - "You start off with a iron Sharpness" - - "VI and Smite II sword!" - Cannot-Wear-Armor: "&cYou can't wear armor with the Wild Naked kit!" + - "&6&lGAME POWER: &7strong/mediocre/mediocre" + - "&6&lCLASS: &7mixed, support" + - "" + - "&6&lABILITIES:" + - "&a&l• TRUE FRIEND (PASSIVE):" + - " &7Have 1/&72/&73 Wolves and &7-/&71/&71" + - " &7Iron Golem in game that respawn" + - " &7on next wave after death" + - "&a&l• RECALL:" + - " &7On use recall every Wolf and" + - " &7Iron Golem back to your location" + - " &7(&c&lCOOLDOWN 10s&7)" + - "&e&l• GRAVE DANGER (ULTIMATE):" + - " &7On use clone every alive" + - " &7Wolf and Iron Golem to fight" + - " &7with your pack for -/&710/&715s" + - " &7(&c&lCOOLDOWN 140s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" + Game-Item: + Passive: + Wolf-Spawned: "&7New Wolf came to our pack!" + Wolf-Aged: "&7Your Wolf has reached the adulthood and can be upgraded now!" + Golem-Spawned: "&7Welcome Iron Golem, aid us in our adventure!" + Wolf-Died: "%color_chat_issue%%plugin_prefix% Your Wolf was killed, it will respawn next wave!" + Golem-Died: "%color_chat_issue%%plugin_prefix% Your Iron Golem was killed, it will respawn next wave!" + Recall: + Name: "&6&lRECALL" + Description: + - "On use recall every Wolf and" + - "Iron Golem back to your location" + - "&c&lCOOLDOWN 10s" + Activate: "&7Come back to me my pets!" + No-Alive-Pets: "&cYou don't have any alive pets!" + Grave-Danger: + Name: "&e&lGRAVE DANGER &7(Ultimate)" + Description: + - "On use clone every alive" + - "Wolf and Iron Golem to fight" + - "with your pack for -/10/15s" + Activate: "&7Who let the dogs out?!" Wizard: Name: "&bWizard" Description: - - "You're half blood." - - "You've come to the village to protect" - - "villagers from hordes of undead." - - "Use your dark powers to kill them all!" + - "&6&lGAME POWER: &7mediocre/strong/strong" + - "&6&lCLASS: &7ranged, damage dealer" + - "" + - "&6&lABILITIES:" + - "&a&l• WIZARD WAND:" + - " &7Flat 20/&725/&730% max health damage and" + - " &7projectile pierce 3/&74/&75 per shot" + - " &7Left click applies &b&lOVERCHARGE" + - " &7once it's ready that deals burn" + - " &7and give slows on hit" + - "&e&l• ASCENSION (ULTIMATE):" + - " &7Ascend and push away nearby enemies," + - " &7spawn 4 homing Wand Projectiles that" + - " &7deal -/&725/&730% max health damage" + - " &7to target enemies, on cast end burn" + - " &7nearby enemies for 4 seconds" + - " &7(&c&lCAST TIME 12s&7, &c&lCOOLDOWN 70s&7)" + - " &7(&c&lUNLOCKED IN MID GAME&7)" Game-Item: - Essence: - Name: "Dark essence" - Description: - - "Click to absorb surrounded matter" - - "and use it as your personal thorn shield!" - - "Lasts for 5 seconds" Wand: - Name: "Magic wand" - Description: "Right click to cast dark matter" + Name: "&6&lWIZARD WAND" + Description: + - "Right click to shoot projectile" + - "dealing 20/25/30% max health damage" + - "and 3/4/5 pierce per shot" + - "Left click to use &b&lOVERCHARGE" + - "that deals burn and slows on hit" + Name-Overcharge-Ready: "&6&lWIZARD WAND &7(&bOVERCHARGE READY&7)" + Name-Overcharged: "&6&lWIZARD WAND &7(&b&lOVERCHARGE&7)" + Name-Overcharged-2: "&6&lWIZARD WAND &7(&9&lOVERCHARGE&7)" + Overcharge-Not-Ready: "&b&lOvercharge &cnot ready yet!" + Ascension: + Name: "&e&lASCENSION &7(Ultimate)" + Description: + - "Ascend and push away nearby enemies," + - "spawn 4 homing Wand Projectiles that" + - "deal -/25/30% max health damage" + - "to target enemies, on cast end burn" + - "nearby enemies for 4 seconds" + - "&c&lCAST TIME &712s, &c&lCOOLDOWN &770s" + Activate: "&7Sacrifice your souls to me!" + Active-Action-Bar: + - "&e&lASCENSION ACTIVE &7(%number%s)" + - "&c&lASCENSION ACTIVE &7(%number%s)" # # Upgrade-Menu messages # # Upgrade-Menu function need to be enabled on config.yml Upgrade-Menu: - Title: "&3&lUpgrade entity" + Title: "&6&lUPGRADE ENTITY" Upgraded-Entity: "%plugin_prefix% &3Upgraded entity to tier &8%tier%&3!" Cannot-Afford: "%plugin_prefix% &3You don't have enough orbs to apply that upgrade!" Max-Tier: "%plugin_prefix% &3Entity is at max tier of this upgrade!" Stats-Item: - Name: "&3&lCurrent Stats" - Description: "&3Movement speed: &8%speed%; &3Attack Damage: &8%damage%; &3Health: - &8%current_hp%/%max_hp%" + Name: "&6&lCURRENT STATS" + Description: " &a&lSPEED: &7%speed%; &7&lDAMAGE: &7%damage%; &a&lHEALTH: &7%current_hp%/%max_hp%" Upgrades: Health: - Name: "&3&lUpgrade Health" - Description: "&3Upgrade max health to tier &8%tier%&3!;&3From &8%from% &3to + Name: "&c&lUPGRADE: &aHealth" + Description: "&3Upgrade max health to tier &8%tier% ▲&3!;&3From &8%from% &3to &8%to%;&3Cost of upgrade: &8%cost%;;&3Click to purchase" Damage: - Name: "&3&lUpgrade Damage" - Description: "&3Upgrade entity damage to tier &8%tier%&3!;&3From &8%from% &3to + Name: "&c&lUPGRADE: &7Damage" + Description: "&3Upgrade entity damage to tier &8%tier% ▲&3!;&3From &8%from% &3to &8%to%;&3Cost of upgrade: &8%cost%;;&8Click to purchase" Speed: - Name: "&3&lUpgrade Speed" - Description: "&3Upgrade movement speed to tier &8%tier%&3!;&3From &8%from% &3to + Name: "&c&lUPGRADE: &6Speed" + Description: "&3Upgrade movement speed to tier &8%tier% ▲&3!;&3From &8%from% &3to &8%to%;&3Cost of upgrade: &8%cost%;;&8Click to purchase" Swarm-Awareness: - Name: "&3&lSwarm Awareness" - Description: "&3Upgrade swarm awareness to tier &8%tier%&3!;&3From &8%from% + Name: "&3&lSWARM AWARENESS" + Description: "&3Upgrade swarm awareness to tier &8%tier% ▲&3!;&3From &8%from% &8damage multiplier per wolf in radius;&8of 3 blocks &3to %to%;&3The more wolves near attacking wolf;&3the more damage wolf deal;&3Cost of upgrade: &8%cost%;;&8Click to purchase" Final-Defense: - Name: "&3&lFinal Defense" - Description: "&3Upgrade final defense to tier &8%tier%&3!;&3From &8%from% explosion + Name: "&3&lFINAL DEFENSE" + Description: "&3Upgrade final defense to tier &8%tier% ▲&3!;&3From &8%from% explosion radius &3to &8%to%;&3Golem will explode after death killing nearby;&3zombies and stun all alive ones;&3Cost of upgrade: &8%cost%;;&8Click to purchase" # diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c6fd6b679..660c05a44 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -2,17 +2,18 @@ name: ${description} main: plugily.projects.villagedefense.Main authors: [ PlugilyProjects, Tigerpanzer_02, TomTheDeveloper, Plajer, montlikadani ] version: ${version} +depend: [ Citizens, ProtocolLib ] softdepend: [ PlaceholderAPI, Parties, Spigot-Party-API-PAF, PartyAndFriends, ViaVersion, ProtocolSupport ] api-version: 1.13 commands: villagedefense: description: VillageDefense Commands - usage: "\u00A76Correct usage: /vd [option]" + usage: "Correct usage: /vd [option]" aliases: [ vd, villaged ] villagedefenseadmin: description: VillageDefense Admin Commands - usage: "\u00A76Correct usage: /vda [option]" + usage: "Correct usage: /vda [option]" aliases: [ vda, villageadmin ] permissions: diff --git a/src/main/resources/powerups.yml b/src/main/resources/powerups.yml deleted file mode 100644 index 46ee3e203..000000000 --- a/src/main/resources/powerups.yml +++ /dev/null @@ -1,99 +0,0 @@ -## Plugily Projects powerups.yml -#Example -Powerups: - Pickup: - Chat: "&a%player% picked the &4Powerup %value% up" - Ended: - Title: "&4Powerup %value% from %player%" - Subtitle: "&chas ended" - Chat: "&4Powerup %value% from %player% has ended%" - Drop: - Chance: 1 - Content: - Map-Clean: - name: "&e&lMAP CLEANER" - description: "&7Map has been cleaned!" - material: BLAZE_POWDER - # Add as many potion effects as you want - # Format: PotionName, Duration, Amplifier - potion-effect: - - "" - # PLAYER for pickup player | ALL for all arena players - potion-type: PLAYER - # like rewards - #ArenaUtils.removeSpawnedEnemies(pickup.getArena()); - execute: - - "" - Double-Damage: - name: "&c&lDOUBLE DAMAGE" - description: "&7Double damage for %number% seconds!" - material: REDSTONE - # Add as many potion effects as you want - # Format: PotionName, Duration, Amplifier - potion-effect: - - "INCREASE_DAMAGE, 20, 1" - # PLAYER for pickup player | ALL for all arena players - potion-type: ALL - # like rewards - execute: - - "" - Healing: - name: "&6&lREJUVENATION" - description: "&7Healing for %number% seconds!" - material: GOLDEN_APPLE - # Add as many potion effects as you want - # Format: PotionName, Duration, Amplifier - potion-effect: - - "REGENERATION, 10, 1" - # PLAYER for pickup player | ALL for all arena players - potion-type: ALL - # like rewards - execute: - - "" - Golem-Raid: - name: "&a&lIRONBOUND RAID" - description: "&7Golems have invaded this village!" - material: IRON_INGOT - # Add as many potion effects as you want - # Format: PotionName, Duration, Amplifier - potion-effect: - - "REGENERATION, 3, 1" - # PLAYER for pickup player | ALL for all arena players - potion-type: PLAYER - # like rewards - execute: - - "" - One-Shot-One-Kill: - name: "&b&lFRENZY" - description: "&7Every zombie for 1 hit!" - material: DIAMOND_SWORD - # Add as many potion effects as you want - # Format: PotionName, Duration, Amplifier - potion-effect: - - "INCREASE_DAMAGE, 15, 1000" - # PLAYER for pickup player | ALL for all arena players - potion-type: ALL - # like rewards - execute: - - "" - Speed: - active: true - name: "&a&lSPEED BOOSTER" - description: "&7Double speed for %number% seconds!" - material: FEATHER - # Add as many potion effects as you want - # Format: PotionName, Duration, Amplifier - potion-effect: - - "SPEED, 15, 1" - # PLAYER for pickup player | ALL for all arena players - potion-type: PLAYER - # like rewards - execute: - - "" - -# Don't edit it. But who's stopping you? It's your server! -# Really, don't edit ;p -# You edited it, huh? Next time hurt yourself! -Do-Not-Edit: - File-Version: 1 - Core-Version: 1 \ No newline at end of file diff --git a/src/main/resources/vd_user_data.yml b/src/main/resources/vd_user_data.yml new file mode 100644 index 000000000..d52756f99 --- /dev/null +++ b/src/main/resources/vd_user_data.yml @@ -0,0 +1,4 @@ +# uuid: +# records: +# mapname: +# - kit_id;wave \ No newline at end of file