├── .gitattributes ├── .gitignore ├── .idea ├── .gitignore ├── compiler.xml ├── dictionaries │ └── Simon.xml ├── gradle.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── kotlinc.xml ├── misc.xml ├── modules │ ├── WynnLab.main.iml │ ├── WynnLab.test.iml │ └── WynnLab_main.iml ├── uiDesigner.xml └── vcs.xml ├── LICENSE ├── README.md ├── build.gradle ├── crowdin.yml ├── desktop.ini ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs ├── WynnScript2-1.0-all.jar └── craftbukkit-1.16.5.jar ├── settings.gradle └── src ├── main ├── java │ └── com │ │ └── wynnlab │ │ └── java │ │ └── AddItemFlags.java ├── kotlin │ └── com │ │ └── wynnlab │ │ ├── Main.kt │ │ ├── MainThread.kt │ │ ├── Players.kt │ │ ├── WynnClass.kt │ │ ├── api │ │ ├── item api.kt │ │ ├── nms api.kt │ │ ├── persistent data api.kt │ │ └── player api.kt │ │ ├── commands │ │ ├── BaseCommand.kt │ │ ├── BuildCommand.kt │ │ ├── CastCommand.kt │ │ ├── ClassCommand.kt │ │ ├── DevCommands.kt │ │ ├── DummyCommand.kt │ │ ├── EssentialsCommands.kt │ │ ├── GMCommands.kt │ │ ├── ItemCommand.kt │ │ ├── MobCommand.kt │ │ ├── PVPCommands.kt │ │ ├── RankCommand.kt │ │ └── tab_completers │ │ │ ├── BaseTabCompleter.kt │ │ │ ├── BuildTabCompleter.kt │ │ │ ├── CastTabCompleter.kt │ │ │ ├── ClassTabCompleter.kt │ │ │ ├── EssentialsTabCompleters.kt │ │ │ ├── GMTabCompleters.kt │ │ │ ├── ItemTabCompleter.kt │ │ │ ├── MobTabCompleter.kt │ │ │ ├── NoTabCompleter.kt │ │ │ └── RankTabCompleter.kt │ │ ├── entities │ │ ├── CustomEntity.kt │ │ ├── Dummy.kt │ │ ├── Hologram.kt │ │ ├── WynnMob.kt │ │ ├── class stubs.txt │ │ └── pathfinder │ │ │ ├── PathfinderGoalCastSpell.kt │ │ │ ├── PathfinderGoalMeleeAttack.kt │ │ │ └── PathfinderGoalRangedAttack.kt │ │ ├── essentials │ │ ├── Party.kt │ │ └── Rank.kt │ │ ├── events │ │ ├── SpellCastEvent.kt │ │ └── WorldInstanceEvents.kt │ │ ├── gui │ │ ├── ClassGUI.kt │ │ ├── CompassGUI.kt │ │ ├── GUI.kt │ │ └── PVPGUI.kt │ │ ├── guilds │ │ └── Guild.kt │ │ ├── items │ │ ├── Build.kt │ │ ├── Identifications.kt │ │ ├── SpecialItems.kt │ │ ├── WynnItem.kt │ │ └── api access.kt │ │ ├── listeners │ │ ├── BaseListener.kt │ │ ├── CastListener.kt │ │ ├── CommandListener.kt │ │ ├── DamageListener.kt │ │ ├── FallingBlockListener.kt │ │ ├── GUIListener.kt │ │ ├── PlayerClickListener.kt │ │ ├── PlayerEventsListener.kt │ │ ├── ProjectileHitListener.kt │ │ └── ScriptAPIListeners.kt │ │ ├── localization │ │ └── Language.kt │ │ ├── locations │ │ ├── Location.kt │ │ └── locations.kt │ │ ├── pvp │ │ ├── Duels.kt │ │ └── FFA.kt │ │ ├── scoreboard │ │ ├── ConfiguredSidebar.kt │ │ ├── PartySidebar.kt │ │ ├── Sidebar.kt │ │ ├── StandardSidebar.kt │ │ └── elements.kt │ │ ├── spells │ │ ├── MobSpell.kt │ │ ├── PlayerSpell.kt │ │ ├── PySpell.kt │ │ ├── Spell.kt │ │ ├── SpellPlayer.kt │ │ └── spell utils.kt │ │ └── util │ │ ├── BaseSerializable.kt │ │ ├── Deferred.kt │ │ ├── LocationIterator.kt │ │ ├── OnlyAsync.kt │ │ ├── Optional.kt │ │ ├── RefreshRunnable.kt │ │ ├── TickRunnable.kt │ │ ├── WynnScript utils.kt │ │ ├── adventure utils.kt │ │ ├── bukkit utils.kt │ │ ├── operators.kt │ │ ├── resources.kt │ │ ├── task utils.kt │ │ ├── worlds.kt │ │ └── wynncraft api.kt └── resources │ ├── classes │ ├── assassin │ │ ├── assassin.yml │ │ ├── assassin_main.py │ │ ├── multihit.py │ │ ├── smoke_bomb.py │ │ ├── smoke_bomb_tick.py │ │ ├── spin_attack.py │ │ ├── vanish.py │ │ └── vanish_end.py │ ├── monk │ │ ├── control.py │ │ ├── monk.yml │ │ ├── monk_main.py │ │ ├── shield.py │ │ ├── silence.py │ │ └── step.py │ ├── shaman │ │ ├── aura.py │ │ ├── haul.py │ │ ├── shaman.yml │ │ ├── shaman_main.py │ │ ├── totem.py │ │ ├── totem_tick.py │ │ └── uproot.py │ └── warrior │ │ ├── bash.py │ │ ├── charge.py │ │ ├── uppercut.py │ │ ├── uppercut_throw.py │ │ ├── war_scream.py │ │ ├── warrior.yml │ │ └── warrior_main.py │ ├── lang │ ├── ar_SA.yml │ ├── de_DE.yml │ └── en_us.yml │ ├── locations.yml │ ├── mobs │ ├── dummy.yml │ └── scripts │ │ └── pull.ws2 │ └── plugin.yml └── test └── kotlin ├── Optional performance.kt ├── Optional test.kt ├── api test.kt ├── jstest.kt ├── p └── IC.kt └── scripting.kt /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ws2 linguist-language=WynnScript -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project exclude paths 2 | /.gradle/ 3 | /build/ 4 | /bin/ 5 | /old_builds/ 6 | /libs/ 7 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/dictionaries/Simon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | multihit 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 68 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | 34 | 35 | -------------------------------------------------------------------------------- /.idea/kotlinc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/modules/WynnLab.main.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | PAPER 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/modules/WynnLab.test.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | PAPER 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules/WynnLab_main.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | PAPER 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Siinus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## This Repository is archived! You can compile it and try it out anywanys though. 2 | [New Repository](https://github.com/wynnlab/wynnlab-minestom) 3 | 4 | # WynnLab 5 | [![discord](https://img.shields.io/discord/826897491185893428)](https://discord.gg/7ktHKn2nZG) 6 | [![website](https://img.shields.io/website?up_message=wynnlab.tk&url=https%3A%2F%2Fwww.wynnlab.tk)](https://www.wynnlab.tk) 7 | ![Codacy](https://img.shields.io/codacy/grade/7679f5049036406c9c213b22a8de2bcd) 8 | [![Crowdin](https://badges.crowdin.net/wynnlab/localized.svg)](https://crowdin.com/project/wynnlab) 9 | 10 | Wynncraft Recreation as Minecraft 1.17 plugin 11 | 12 | This is my recreation of the popular MMORPG in Minecraft: Wynncraft. 13 | 14 | ### Join our Minecraft server: play.wynnlab.tk 15 | 16 | --- 17 | ### Usage 18 | 19 | Clone the project in IntelliJ and execute the task ShadowJar (terminal >> gradlew shadowJar). 20 | 21 | --- 22 | Credits to Wynncraft for the combat system. I'm not part of the Wynncraft team. 23 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.jetbrains.kotlin.jvm' version '1.5.10' 4 | } 5 | 6 | group = 'com.wynnlab' 7 | version = '1.1.0' // "git describe --tags".execute().text 8 | 9 | ext { 10 | kotlinVersion = '1.5.10' 11 | apiVersion = '1.17' 12 | paperRelease = '0.1-SNAPSHOT' 13 | } 14 | 15 | repositories { 16 | mavenCentral() 17 | maven { url 'https://papermc.io/repo/repository/maven-public/' } 18 | 19 | flatDir { dirs './libs/' } 20 | flatDir { dirs 'D:/Libraries/Java/' } 21 | flatDir { dirs 'D:/IdeaProjects/WynnLabScriptAPI/build/libs/' } 22 | flatDir { dirs 'D:/IdeaProjects/WynnLabAPI/build/libs/' } 23 | } 24 | 25 | dependencies { 26 | // Paper (Spigot) API 27 | compileOnly "io.papermc.paper:paper-api:$apiVersion-R$paperRelease" 28 | 29 | // Craftbukkit & NMS 30 | compileOnly name: "craftbukkit-$apiVersion" 31 | 32 | // WynnScript (deprecated) 33 | compileOnly name: 'WynnScript2-1.0-all' 34 | 35 | // API 36 | compileOnly name: "WynnLabAPI-$version" 37 | 38 | // Kotlin 39 | compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" 40 | 41 | // Jython 42 | compileOnly "org.python:jython-standalone:2.7.1" 43 | testImplementation "org.python:jython-standalone:2.7.1" 44 | 45 | //testCompile group: 'junit', name: 'junit', version: '4.12' 46 | } 47 | 48 | //sourceCompatibility = 16 49 | //targetCompatibility = 16 50 | 51 | compileKotlin { 52 | kotlinOptions.jvmTarget = '16' 53 | kotlinOptions.freeCompilerArgs = [ '-Xopt-in=kotlin.RequiresOptIn' ] 54 | } 55 | 56 | compileTestKotlin { 57 | kotlinOptions.jvmTarget = '16' 58 | } 59 | 60 | processResources { 61 | duplicatesStrategy = 'include' 62 | from(sourceSets.main.resources.srcDirs) { 63 | filter org.apache.tools.ant.filters.ReplaceTokens, tokens: [VERSION: version, API: apiVersion] 64 | } 65 | } 66 | 67 | java { 68 | toolchain { 69 | languageVersion = JavaLanguageVersion.of(16) 70 | } 71 | } 72 | 73 | /*task buildAndCopy { 74 | dependsOn 'shadowJar' 75 | doLast { 76 | copy { 77 | from file("D:\\IdeaProjects\\WynnLab\\build\\libs\\WynnLab-$version-all.jar") 78 | into file("M:\\plugins") 79 | } 80 | } 81 | }*/ -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | files: 2 | - source: /src/main/resources/lang 3 | ignore: 4 | - ar_sa.yml 5 | - de_de.yml 6 | - en_us.yml 7 | translation: /src/main/resources/lang/%locale_with_underscore%.yml 8 | -------------------------------------------------------------------------------- /desktop.ini: -------------------------------------------------------------------------------- 1 | [.ShellClassInfo] 2 | IconResource=D:\Pictures\WynnLab.ico,0 3 | [ViewState] 4 | Mode= 5 | Vid= 6 | FolderType=Generic 7 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WynnLab/WynnLab-Core/9950bc1485fa187394c1b1326fa0b5c6b6a1ac96/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /libs/WynnScript2-1.0-all.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WynnLab/WynnLab-Core/9950bc1485fa187394c1b1326fa0b5c6b6a1ac96/libs/WynnScript2-1.0-all.jar -------------------------------------------------------------------------------- /libs/craftbukkit-1.16.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WynnLab/WynnLab-Core/9950bc1485fa187394c1b1326fa0b5c6b6a1ac96/libs/craftbukkit-1.16.5.jar -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | 2 | rootProject.name = 'WynnLab' 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/com/wynnlab/java/AddItemFlags.java: -------------------------------------------------------------------------------- 1 | package com.wynnlab.java; 2 | 3 | import org.bukkit.inventory.ItemFlag; 4 | import org.bukkit.inventory.meta.ItemMeta; 5 | 6 | public class AddItemFlags { 7 | public static void addAllItemFlags(ItemMeta meta) { 8 | meta.addItemFlags(ItemFlag.values()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/Main.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab 2 | 3 | import com.wynnlab.api.sidebars 4 | import com.wynnlab.commands.registerCommands 5 | import com.wynnlab.commands.tab_completers.registerTabCompleters 6 | import com.wynnlab.listeners.registerListeners 7 | import com.wynnlab.localization.loadLanguages 8 | import com.wynnlab.locations.loadLocations 9 | import com.wynnlab.util.DEG2RAD 10 | import com.wynnlab.util.RAD2DEG 11 | import com.wynnlab.util.registerSerializers 12 | import com.wynnlab.util.saveAllResources 13 | import net.kyori.adventure.text.Component 14 | import net.kyori.adventure.text.format.NamedTextColor 15 | import net.kyori.adventure.text.format.TextColor 16 | import org.bukkit.Bukkit 17 | import org.bukkit.GameRule 18 | import org.bukkit.World 19 | import org.bukkit.plugin.java.JavaPlugin 20 | import org.bukkit.util.Vector 21 | import org.python.util.PythonInterpreter 22 | 23 | class Main : JavaPlugin() { 24 | override fun onLoad() { 25 | instance = this 26 | 27 | python.set("plugin", this) 28 | python.set("random", random) 29 | python.set("RAD2DEG", RAD2DEG) 30 | python.set("DEG2RAD", DEG2RAD) 31 | python.set("VectorUP", Vector(0, 1, 0)) 32 | 33 | saveAllResources() 34 | } 35 | 36 | override fun onEnable() { 37 | registerCommands() 38 | registerTabCompleters() 39 | registerCommands() 40 | registerListeners() 41 | registerSerializers() 42 | 43 | setGameRules() 44 | Players.initPlayers() 45 | 46 | MainThread.schedule() 47 | 48 | loadClasses() 49 | 50 | loadLanguages() 51 | 52 | loadLocations() 53 | 54 | Bukkit.getServer().spigot().spigotConfig.set("settings.attribute.maxHealth.max", 1000000) 55 | } 56 | 57 | override fun onDisable() { 58 | Bukkit.getOnlinePlayers().forEach(Players::removePlayerFromActivities) 59 | 60 | sidebars.clear() 61 | 62 | python.close() 63 | } 64 | 65 | private fun setGameRules() { 66 | Bukkit.getWorlds().forEach { 67 | setGameRules(it) 68 | } 69 | } 70 | 71 | fun setGameRules(world: World) { 72 | world.setGameRule(GameRule.ANNOUNCE_ADVANCEMENTS, false) 73 | world.setGameRule(GameRule.DISABLE_RAIDS, false) 74 | world.setGameRule(GameRule.DO_FIRE_TICK, false) 75 | world.setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true) 76 | world.setGameRule(GameRule.DO_LIMITED_CRAFTING, false) 77 | world.setGameRule(GameRule.DO_MOB_SPAWNING, false) 78 | world.setGameRule(GameRule.DO_PATROL_SPAWNING, false) 79 | world.setGameRule(GameRule.FALL_DAMAGE, false) 80 | world.setGameRule(GameRule.MOB_GRIEFING, false) 81 | world.setGameRule(GameRule.NATURAL_REGENERATION, false) 82 | //world.setGameRule(GameRule.REDUCED_DEBUG_INFO, true) 83 | world.setGameRule(GameRule.SPAWN_RADIUS, 0) 84 | world.setGameRule(GameRule.SPECTATORS_GENERATE_CHUNKS, false) 85 | } 86 | } 87 | 88 | private lateinit var instance: Main 89 | val wynnlab get() = instance 90 | 91 | val WL_COLOR = TextColor.color(0x82e617) 92 | val PREFIX = Component.text("[", NamedTextColor.DARK_GRAY) 93 | .append(Component.text("WynnLab", WL_COLOR)) 94 | .append(Component.text("] ", NamedTextColor.DARK_GRAY)) 95 | //"§8[§bWynnLab§8] §r" 96 | val PLAY_WYNNLAB_TK = Component.text("play.", TextColor.color(0x666666)) 97 | .append(Component.text("WYNNLAB", WL_COLOR)) 98 | .append(Component.text(".tk", TextColor.color(0x666666))) 99 | 100 | val random = java.util.Random() 101 | 102 | val python by lazy { PythonInterpreter() } 103 | 104 | val NL_REGEX = Regex("\\n") -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/MainThread.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab 2 | 3 | import com.wynnlab.api.* 4 | import com.wynnlab.essentials.Party 5 | import com.wynnlab.localization.Language 6 | import com.wynnlab.locations.updateLocations 7 | import com.wynnlab.spells.PySpell 8 | import net.kyori.adventure.text.Component 9 | import net.kyori.adventure.text.event.ClickEvent 10 | import net.kyori.adventure.text.event.HoverEvent 11 | import net.kyori.adventure.text.format.NamedTextColor 12 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer 13 | import org.bukkit.Bukkit 14 | import org.bukkit.attribute.Attribute 15 | import org.bukkit.entity.Player 16 | import org.bukkit.event.Listener 17 | import org.bukkit.potion.PotionEffect 18 | import org.bukkit.potion.PotionEffectType 19 | 20 | object MainThread : Listener { 21 | fun schedule() { 22 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> onTick() }, 1L, 1L) 23 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> onSecond() }, 20L, 20L) 24 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> on4Seconds() }, 80L, 80L) 25 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> on10Seconds() }, 200L, 200L) 26 | Bukkit.getScheduler().runTaskTimer(wynnlab, { -> on5Minutes() }, 100L, 6000L) 27 | } 28 | 29 | private fun onTick() { 30 | for (player in Bukkit.getOnlinePlayers()) { 31 | val pvp = player.hasScoreboardTag("pvp") 32 | 33 | // Send action bar 34 | player.standardActionBar() 35 | 36 | // Reset exhaustion to not lose mana except in spell casts 37 | player.exhaustion = 0f 38 | 39 | // Store max health and set attribute 40 | val maxHealth = (505 + player.getId("health_bonus") + player.getArmorHealth()).coerceIn(1, 1000000).toDouble() 41 | player.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.baseValue = maxHealth 42 | 43 | if (!player.hasPotionEffect(PotionEffectType.INVISIBILITY) && "invis" in player.scoreboardTags) 44 | PySpell.castSpell(player, "ASSASSIN", 5) 45 | 46 | // Walk speed 47 | val speed = player.getId("speed") 48 | player.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED)!!.baseValue = .1 + (if (pvp) speed.coerceAtMost(100) else speed) * .001 49 | } 50 | } 51 | 52 | private fun onSecond() { 53 | Party.parties.forEach(Party::update) 54 | 55 | for (player in Bukkit.getOnlinePlayers()) { 56 | val pvp = player.hasScoreboardTag("pvp") 57 | 58 | // Natural mana regen 59 | player.foodLevel = (player.foodLevel + if (player.hasPotionEffect(PotionEffectType.INVISIBILITY)) -1 else if (pvp) 2 else 1).coerceIn(0, 20) 60 | 61 | val jumpHeight = player.getId("jump_height") - 1 62 | if (jumpHeight != 0) player.addPotionEffect(PotionEffect(PotionEffectType.JUMP, 21, 63 | if (pvp) jumpHeight.coerceAtMost(3) else jumpHeight, 64 | true, false, false)) 65 | 66 | player.testInventory() 67 | player.updateLocations() 68 | player.updateSidebar() 69 | } 70 | } 71 | 72 | private fun on4Seconds() { 73 | for (player in Bukkit.getOnlinePlayers()) { 74 | if (!player.hasPotionEffect(PotionEffectType.INVISIBILITY)) player.foodLevel = (player.foodLevel + player.getId("mana_regen")).coerceIn(0, 20) 75 | 76 | if (player.hasScoreboardTag("pvp")) 77 | continue 78 | healthRegen(player, false) 79 | } 80 | } 81 | 82 | private fun on10Seconds() { 83 | for (player in Bukkit.getOnlinePlayers()) { 84 | if (!player.hasScoreboardTag("pvp")) 85 | continue 86 | healthRegen(player, true) 87 | } 88 | } 89 | 90 | private fun on5Minutes() { 91 | for (player in Bukkit.getOnlinePlayers()) { 92 | val msg = Language[player.locale()].getRandomMessageAsString("tips") 93 | var c = LegacyComponentSerializer.legacy('&').deserialize(msg) 94 | if (msg.startsWith("ᛩf2")) 95 | c = c.append(Component.text("https://discord.gg/7ktHKn2nZG", COLOR_DISCORD) 96 | .hoverEvent(HoverEvent.showText(Component.text("Click to join!", NamedTextColor.GRAY))) 97 | .clickEvent(ClickEvent.openUrl("https://discord.gg/7ktHKn2nZG"))) 98 | player.sendMessage(c) 99 | } 100 | } 101 | 102 | private fun healthRegen(player: Player, pvp: Boolean) { 103 | val maxHealth = (505 + player.getId("health_bonus") + player.getArmorHealth()).coerceIn(1, 1000000).toDouble() 104 | val healthBonus = player.getId("health_regen_raw") * (1 + player.getId("health_regen") / 100f) 105 | player.health = (player.health + if (pvp && healthBonus > 2500) (healthBonus - 2500) * .15f + 2500 else healthBonus).coerceIn(1.0, maxHealth) 106 | } 107 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/WynnClass.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("Classes") 2 | 3 | package com.wynnlab 4 | 5 | import com.wynnlab.registry.ClassRegistry 6 | import com.wynnlab.spells.Spell 7 | import com.wynnlab.util.BaseSerializable 8 | import com.wynnlab.util.ConfigurationDeserializable 9 | import org.bukkit.Material 10 | import org.bukkit.configuration.file.YamlConfiguration 11 | import java.io.File 12 | import java.util.logging.Level 13 | 14 | data class WynnClass( 15 | val id: String, 16 | val item: Material, 17 | val itemDamage: Int, 18 | val metaStats: Tuple4, 19 | val invertedControls: Boolean, 20 | val spells: List 21 | ) : BaseSerializable() { 22 | 23 | override fun serialize(): Map { 24 | val out = LinkedHashMap() 25 | 26 | out["id"] = id 27 | out["item"] = item.name 28 | if (itemDamage != 0) out["item_damage"] = itemDamage 29 | out["metaStats"] = mapOf("damage" to metaStats.v1, "defence" to metaStats.v2, "range" to metaStats.v3, "spells" to metaStats.v4) 30 | out["invertedControls"] = invertedControls 31 | out["spells"] = spells 32 | 33 | return out 34 | } 35 | 36 | override val deserializer = Companion 37 | 38 | companion object : ConfigurationDeserializable { 39 | @JvmStatic 40 | @Suppress("unused", "unchecked_cast") 41 | override fun deserialize(map: Map): WynnClass { 42 | val id = map["id"] as String 43 | val item = Material.valueOf(map["item"] as String) 44 | val itemDamage = (map["item_damage"] as Number??: 0).toInt() 45 | val metaStats = map["metaStats"] as Map 46 | val invertedControls = map["invertedControls"] as Boolean 47 | val spells = map["spells"] as List 48 | 49 | spellOrdinal = 0 50 | 51 | return WynnClass(id, item, itemDamage, 52 | Tuple4(metaStats["damage"]!!.toInt(), metaStats["defence"]!!.toInt(), metaStats["range"]!!.toInt(), metaStats["spells"]!!.toInt()), 53 | invertedControls, spells) 54 | } 55 | 56 | operator fun get(string: String) = classes[string] 57 | } 58 | } 59 | 60 | val classes = linkedMapOf() 61 | 62 | internal var spellOrdinal = 0 63 | 64 | fun loadClasses() { 65 | val classFolder = File(wynnlab.dataFolder, "classes") 66 | 67 | if (!classFolder.exists()) { 68 | wynnlab.logger.log(Level.WARNING, "No classes loaded") 69 | return 70 | } 71 | 72 | for (f in classFolder.listFiles { f, _ -> f.isDirectory } ?: return) { 73 | currentClassLoadFolder = f 74 | 75 | wynnlab.logger.log(Level.INFO, "Loading class ${f.name} ...") 76 | 77 | val configFile = File(f, "${f.name}.yml") 78 | val config = YamlConfiguration() 79 | config.load(configFile) 80 | val wynnClass = config.getSerializable("class", WynnClass::class.java) ?: continue 81 | classes[wynnClass.id] = wynnClass 82 | } 83 | 84 | classes.remove("MONK")?.let { classes["MONK"] = it } 85 | 86 | ClassRegistry.entries().forEach { 87 | classes[it.id] = it 88 | } 89 | 90 | //plugin.logger.log(Level.INFO, "Classes: $classes") 91 | //plugin.logger.log(Level.INFO, "Listeners: ${plugin.projectileHitListener.tags}") 92 | } 93 | 94 | data class Tuple4(val v1: T, val v2: T, val v3: T, val v4: T) 95 | 96 | internal lateinit var currentClassLoadFolder: File -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/api/item api.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("ItemAPI") 2 | 3 | package com.wynnlab.api 4 | 5 | import com.wynnlab.items.WynnItem 6 | import org.bukkit.inventory.ItemStack 7 | import org.bukkit.inventory.meta.Damageable 8 | import org.bukkit.inventory.meta.ItemMeta 9 | import kotlin.contracts.ExperimentalContracts 10 | import kotlin.contracts.InvocationKind 11 | import kotlin.contracts.contract 12 | 13 | @OptIn(ExperimentalContracts::class) 14 | inline fun ItemStack.meta(edit: ItemMeta.() -> Unit): ItemStack { 15 | contract { callsInPlace(edit, InvocationKind.EXACTLY_ONCE) } 16 | val meta = itemMeta 17 | meta.edit() 18 | itemMeta = meta 19 | return this 20 | } 21 | 22 | //BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER 23 | @OptIn(ExperimentalContracts::class) 24 | inline fun ItemStack.metaAs(edit: T.() -> Unit): ItemStack { 25 | contract { callsInPlace(edit, InvocationKind.EXACTLY_ONCE) } 26 | val meta = itemMeta as? T ?: return this 27 | meta.edit() 28 | itemMeta = meta as ItemMeta 29 | return this 30 | } 31 | 32 | fun ItemStack.setAppearance(damage: Int): ItemStack { 33 | val meta = itemMeta 34 | (meta as Damageable).damage = damage 35 | meta.isUnbreakable = true 36 | itemMeta = meta 37 | return this 38 | } 39 | 40 | fun ItemStack.getWynnType() = itemMeta?.data?.getString("type")?.let { WynnItem.Type.valueOf(it) } 41 | fun ItemStack.takeIfType(type: WynnItem.Type) = takeIf { it.getWynnType() == type } 42 | 43 | fun ItemStack.getClassReq() = itemMeta?.data?.getString("class_req") 44 | 45 | fun ItemStack.getAttackSpeed() = itemMeta?.data?.getString("attack_speed")?.let { WynnItem.AttackSpeed.valueOf(it) } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/api/nms api.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.api 2 | 3 | //val World.nms get() = (this as CraftWorld).handle -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/api/persistent data api.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("PersistentDataAPI") 2 | 3 | package com.wynnlab.api 4 | 5 | import com.wynnlab.wynnlab 6 | import org.bukkit.NamespacedKey 7 | import org.bukkit.persistence.PersistentDataContainer 8 | import org.bukkit.persistence.PersistentDataHolder 9 | import org.bukkit.persistence.PersistentDataType 10 | 11 | inline val PersistentDataHolder.data get() = persistentDataContainer 12 | 13 | operator fun PersistentDataContainer.get(key: String, type: PersistentDataType) = 14 | try { this[NamespacedKey(wynnlab, key), type] } catch (e: IllegalArgumentException) { null } 15 | 16 | fun PersistentDataContainer.getString(key: String, default: String? = null) = this[key, PersistentDataType.STRING] ?: default 17 | 18 | fun PersistentDataContainer.getInt(key: String, default: Int? = null) = this[key, PersistentDataType.INTEGER] ?: default 19 | 20 | fun PersistentDataContainer.getIntArray(key: String, default: IntArray? = null) = this[key, PersistentDataType.INTEGER_ARRAY] ?: default 21 | 22 | fun PersistentDataContainer.getContainer(key: String, default: PersistentDataContainer? = null) = this[key, PersistentDataType.TAG_CONTAINER] ?: default 23 | 24 | fun PersistentDataContainer.getContainerArray(key: String, default: Array? = null): Array? = this[key, PersistentDataType.TAG_CONTAINER_ARRAY] ?: default 25 | 26 | fun PersistentDataContainer.getBoolean(key: String, default: Boolean = false): Boolean { return (this[key, PersistentDataType.BYTE] ?: return default) != 0.toByte() } 27 | 28 | fun PersistentDataContainer.getDouble(key: String, default: Double? = null) = this[key, PersistentDataType.DOUBLE] ?: default 29 | 30 | 31 | operator fun PersistentDataContainer.set(key: String, type: PersistentDataType, value: Z) = 32 | set(NamespacedKey(wynnlab, key), type, value!!) 33 | 34 | fun PersistentDataContainer.setString(key: String, value: String) = set(key, PersistentDataType.STRING, value) 35 | 36 | fun PersistentDataContainer.setInt(key: String, value: Int) = set(key, PersistentDataType.INTEGER, value) 37 | 38 | fun PersistentDataContainer.setIntArray(key: String, value: IntArray) = set(key, PersistentDataType.INTEGER_ARRAY, value) 39 | 40 | fun PersistentDataContainer.setContainer(key: String, value: PersistentDataContainer.() -> Unit) { 41 | val container = adapterContext.newPersistentDataContainer() 42 | container.value() 43 | set(key, PersistentDataType.TAG_CONTAINER, container) 44 | } 45 | 46 | fun PersistentDataContainer.setBoolean(key: String, value: Boolean) = set(key, PersistentDataType.BYTE, if (value) 1.toByte() else 0.toByte()) 47 | 48 | fun PersistentDataContainer.setDouble(key: String, value: Double) = set(key, PersistentDataType.DOUBLE, value) 49 | 50 | 51 | fun PersistentDataContainer.remove(key: String) = remove(NamespacedKey(wynnlab, key)) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/BaseCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.command.CommandExecutor 5 | 6 | abstract class BaseCommand(vararg val names: String) : CommandExecutor 7 | 8 | fun registerCommands() { 9 | registerCommand(BuildCommand) 10 | registerCommand(CastCommand) 11 | registerCommand(ClassCommand) 12 | registerCommand(DevCommands) 13 | registerCommand(DummyCommand) 14 | registerCommand(EssentialsCommands) 15 | registerCommand(GMCommands) 16 | registerCommand(ItemCommand) 17 | registerCommand(MobCommand) 18 | registerCommand(PVPCommands) 19 | registerCommand(RankCommand) 20 | } 21 | 22 | private fun registerCommand(command: BaseCommand) { 23 | for (name in command.names) 24 | wynnlab.getCommand(name)?.setExecutor(command) 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/BuildCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.items.Build 4 | import org.bukkit.command.Command 5 | import org.bukkit.command.CommandSender 6 | import org.bukkit.entity.Player 7 | 8 | object BuildCommand : BaseCommand("build") { 9 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 10 | val player = (sender as? Player) ?: return true 11 | if (args.isEmpty()) return false 12 | 13 | return when (args[0]) { 14 | "save" -> save(player, args) 15 | "equip" -> equip(player, args) 16 | "delete" -> delete(player, args) 17 | "publish" -> publish(player, args) 18 | "show" -> show(player, args) 19 | else -> false 20 | } 21 | } 22 | 23 | private fun save(player: Player, args: Array): Boolean { 24 | if (args.size != 2) return false 25 | val eq = player.equipment 26 | Build[player.uniqueId, args[1]] = Build(eq?.helmet, eq?.chestplate, eq?.leggings, eq?.boots, eq?.itemInMainHand) 27 | return true 28 | } 29 | 30 | private fun equip(player: Player, args: Array): Boolean { 31 | if (args.size != 2) return false 32 | (Build[player.uniqueId, args[1]] ?: run { 33 | player.sendMessage("§cThe build §f${args[1]}§c doesn't exist") 34 | return true 35 | }).equip(player) 36 | return true 37 | } 38 | 39 | private fun delete(player: Player, args: Array): Boolean { 40 | if (args.size != 2) return false 41 | Build.remove(player.uniqueId, args[1]) ?: player.sendMessage("§cThe build §f${args[1]}§c doesn't exist") 42 | return true 43 | } 44 | 45 | private fun publish(player: Player, args: Array): Boolean { 46 | if (args.size == 2) player.sendMessage("§cSpecify a name for the build (e.g. §fVery cool build§c)") 47 | if (args.size < 3) return false 48 | (Build[player.uniqueId, args[1]] ?: run { 49 | player.sendMessage("§cThe build §f${args[1]}§c doesn't exist") 50 | return true 51 | }).publish(args.slice(2 until args.size).joinToString(" ")) 52 | return true 53 | } 54 | 55 | private fun show(player: Player, args: Array): Boolean { 56 | if (args.size != 1) return false 57 | Build.GUI(player).show() 58 | return true 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/CastCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.api.getWynnClass 4 | import com.wynnlab.events.SpellCastEvent 5 | import org.bukkit.Bukkit 6 | import org.bukkit.command.Command 7 | import org.bukkit.command.CommandSender 8 | import org.bukkit.entity.Player 9 | 10 | object CastCommand : BaseCommand("cast") { 11 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 12 | if (sender !is Player) { 13 | sender.sendMessage("§cThis command can only be executed by players") 14 | return true 15 | } 16 | if (args.size != 1) { 17 | sender.sendMessage("§cPlease specify a spell id") 18 | return false 19 | } 20 | val wynnClass = sender.getWynnClass() 21 | if (wynnClass == null) { 22 | sender.sendMessage("§cPLease select a class first") 23 | return true 24 | } 25 | val spell = args[0].toIntOrNull() 26 | if (spell == null || spell < 0 || spell > 4) { 27 | sender.sendMessage("§c'${args[0]}' is not a valid spell id") 28 | return false 29 | } 30 | Bukkit.getPluginManager().callEvent(SpellCastEvent(sender, spell)) 31 | return true 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/ClassCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.api.hasScoreboardTag 4 | import com.wynnlab.api.setWynnClass 5 | import com.wynnlab.gui.ClassGUI 6 | import org.bukkit.command.Command 7 | import org.bukkit.command.CommandSender 8 | import org.bukkit.entity.Player 9 | 10 | object ClassCommand : BaseCommand("class") { 11 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 12 | if (sender !is Player) { 13 | sender.sendMessage("§cThis command can only be executed by players") 14 | return true 15 | } 16 | 17 | if (sender.hasScoreboardTag("pvp")) { 18 | sender.sendMessage("§cYou can't change your class in PVP") 19 | return true 20 | } 21 | 22 | if (args.size != 1) { 23 | return if (args.isEmpty()) { 24 | ClassGUI(sender).show() 25 | true 26 | } else false 27 | } 28 | sender.setWynnClass(args[0].toUpperCase()) 29 | return true 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/DevCommands.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.api.getId 4 | import com.wynnlab.api.sendWynnMessage 5 | import com.wynnlab.localization.Language 6 | import org.bukkit.command.Command 7 | import org.bukkit.command.CommandSender 8 | import org.bukkit.entity.Player 9 | 10 | /** 11 | * Commands: 12 | * - itemdata 13 | * - getid 14 | * - script //TODO 15 | */ 16 | object DevCommands : BaseCommand("itemdata", "getid") { 17 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 18 | if (!sender.isOp) { 19 | sender.sendMessage("§4You need to be an operator to execute this command") 20 | return true 21 | } 22 | return when (label) { 23 | "itemdata" -> itemdata(sender, args) 24 | "getid" -> getid(sender, args) 25 | else -> false 26 | } 27 | } 28 | 29 | private fun itemdata(sender: CommandSender, args: Array): Boolean { 30 | if (sender !is Player) { 31 | sender.sendMessage("§cThis command can only be performed by players") 32 | return true 33 | } 34 | if (args.isEmpty()) { 35 | sender.sendMessage("§cPlease specify an item index") 36 | return false 37 | } 38 | sender.performCommand("data get entity @s Inventory[${args[0]}].tag.PublicBukkitValues${ 39 | if (args.size == 1) "" else args.slice(1 until args.size).joinToString(".", ".") { "wynnlab:$it" } 40 | }") 41 | return true 42 | } 43 | 44 | private fun getid(sender: CommandSender, args: Array): Boolean { 45 | if (!sender.isOp) { 46 | if (sender is Player) 47 | sender.sendWynnMessage("commands.no_op") 48 | else 49 | sender.sendMessage(Language.en_us.getMessage("commands.no_op")) 50 | return true 51 | } 52 | if (args.isEmpty()) { 53 | sender.sendMessage("§cPlease specify an id name") 54 | return false 55 | } 56 | 57 | val id = args[0] 58 | 59 | val target: Player = if (args.size == 1) { 60 | if (sender is Player) sender else null 61 | } else { 62 | if (args.size == 2) sender.server.selectEntities(sender, args[1]).filterIsInstance().let { 63 | if (it.size != 1) null 64 | else it[0] 65 | } else null 66 | } ?: run { 67 | sender.sendMessage("§cPlease specify one valid target") 68 | return false 69 | } 70 | 71 | sender.sendMessage("§b${target.name}§7's id '§e$id§7' is: ${target.getId(id).let { if (it > 0) "§a+$it" else "§c$it" }}") 72 | 73 | return true 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/DummyCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.api.hasScoreboardTag 4 | import com.wynnlab.entities.Dummy 5 | import org.bukkit.command.Command 6 | import org.bukkit.command.CommandSender 7 | import org.bukkit.entity.Player 8 | 9 | object DummyCommand : BaseCommand("dummy") { 10 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 11 | if (sender !is Player) { 12 | sender.sendMessage("§cThis command can only be executed by players") 13 | return true 14 | } 15 | 16 | if (sender.hasScoreboardTag("pvp")) { 17 | sender.sendMessage("§cYou can't spawn a dummy during pvp") 18 | return true 19 | } 20 | 21 | if (args.isNotEmpty()) 22 | return false 23 | 24 | Dummy(sender.location).spawn(sender.world) 25 | /*val wynnMob = WynnMob("Dummy", EntityTypes.VINDICATOR, WynnMob.AI.values()[random.nextInt(4)], 0, 100000, 0, 0..0, 26 | 1.0, null, .1, .0, false, false, false, .0, 27 | null, null, SoundEffects.ENTITY_DONKEY_DEATH, SoundEffects.BLOCK_GLASS_BREAK, SoundEffects.ENTITY_ENDER_DRAGON_DEATH, .0, 28 | WynnMob.Equipment(null), listOf())*/ 29 | 30 | //wynnMob.spawn(sender.location) 31 | 32 | return true 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/GMCommands.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.WynnClass 4 | import com.wynnlab.classes 5 | import com.wynnlab.loadClasses 6 | import com.wynnlab.wynnlab 7 | import org.bukkit.Bukkit 8 | import org.bukkit.command.Command 9 | import org.bukkit.command.CommandSender 10 | import org.bukkit.configuration.file.YamlConfiguration 11 | import java.io.File 12 | import java.io.FileWriter 13 | import java.io.IOException 14 | import java.net.MalformedURLException 15 | import java.net.URL 16 | 17 | object GMCommands : BaseCommand("upload", "wlrl") { 18 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean = 19 | when (label) { 20 | "upload" -> upload(sender, args) 21 | "wlrl" -> wlrl(sender, args) 22 | else -> false 23 | } 24 | 25 | private fun upload(sender: CommandSender, args: Array): Boolean { 26 | if (!/*sender.hasPermission("gm")*/sender.isOp) { 27 | sender.sendMessage("§cYou don't have permission to perform this command") 28 | return true 29 | } 30 | 31 | if (args.size < 3) 32 | return false 33 | 34 | val newFileLoc = when (args[0]) { 35 | "item" -> File(wynnlab.dataFolder, "custom_items") 36 | "mob" -> File(wynnlab.dataFolder, "mobs") 37 | "mob_spell" -> File(File(wynnlab.dataFolder, "mobs"), "scripts") 38 | "music" -> File(Bukkit.getPluginManager().getPlugin("JukeBox")?.dataFolder, "songs") 39 | else -> return false 40 | } 41 | 42 | if (!newFileLoc.exists()) newFileLoc.mkdirs() 43 | 44 | val downloadFile = File(newFileLoc, args[1]) 45 | if (!downloadFile.createNewFile()) { 46 | sender.sendMessage("The file ${args[1]} already exists") 47 | return true 48 | } 49 | 50 | val url = try { 51 | URL(args.slice(2 until args.size).joinToString("%20")) 52 | } catch (e: MalformedURLException) { 53 | sender.sendMessage("§cMalformed URL") 54 | return false 55 | } 56 | 57 | val text = try { 58 | url.openStream().reader().readText() 59 | } catch (e: IOException) { 60 | sender.sendMessage("§cIO Exception") 61 | return true 62 | } 63 | 64 | FileWriter(downloadFile).use { writer -> 65 | writer.write(text) 66 | } 67 | 68 | sender.sendMessage("§aSuccessfully uploaded your ${args[0]} to ${args[1]}") 69 | 70 | return true 71 | } 72 | 73 | private fun wlrl(sender: CommandSender, args: Array): Boolean { 74 | if (!/*sender.hasPermission("gm")*/sender.isOp) { 75 | sender.sendMessage("§cYou don't have permission to perform this command") 76 | return true 77 | } 78 | 79 | if (args.isEmpty()) 80 | return false 81 | 82 | when (args[0]) { 83 | "mobs" -> { 84 | MobCommand.mobs.clear() 85 | } 86 | "mob" -> { 87 | if (args.size < 2) { 88 | sender.sendMessage("§cPlease specify a mob to reload") 89 | return false 90 | } 91 | MobCommand.mobs.remove(args[1]) ?: run { 92 | sender.sendMessage("§cThe mob ${args[1]} doesn't exist") 93 | return false 94 | } 95 | } 96 | "classes" -> { 97 | classes.clear() 98 | loadClasses() 99 | } 100 | "class" -> { 101 | if (args.size < 2) { 102 | sender.sendMessage("§cPlease specify a class to reload") 103 | return false 104 | } 105 | classes[args[1]] ?: run { 106 | sender.sendMessage("§cThe class ${args[1]} doesn't exist") 107 | return true 108 | } 109 | val configFile = (File(wynnlab.dataFolder, "classes").listFiles { _, name -> name.equals(args[1]) })?.let { files -> 110 | if (files.isEmpty()) null 111 | else files[0] 112 | } ?: run { 113 | sender.sendMessage("§cThe class ${args[1]} doesn't exist") 114 | return true 115 | } 116 | val config = YamlConfiguration() 117 | config.load(configFile) 118 | config.getSerializable("class", WynnClass::class.java)?.let { classes.replace(args[1], it) } ?: run { 119 | sender.sendMessage("§cMalformed config") 120 | return true 121 | } 122 | } 123 | } 124 | 125 | sender.sendMessage("§aReloaded ${args.joinToString(" ")}") 126 | 127 | return true 128 | } 129 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/ItemCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.api.hasScoreboardTag 4 | import com.wynnlab.items.SpecialItems 5 | import com.wynnlab.items.WynnItem 6 | import com.wynnlab.items.getAPIResults 7 | import com.wynnlab.wynnlab 8 | import net.kyori.adventure.text.Component 9 | import org.bukkit.Bukkit 10 | import org.bukkit.command.Command 11 | import org.bukkit.command.CommandSender 12 | import org.bukkit.entity.Player 13 | 14 | object ItemCommand : BaseCommand("item") { 15 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 16 | if (sender !is Player) { 17 | sender.sendMessage("§cThis command can only be executed by players") 18 | return true 19 | } 20 | 21 | if (sender.hasScoreboardTag("pvp")) { 22 | sender.sendMessage("§cYou can't give yourself items during pvp") 23 | return true 24 | } 25 | 26 | if (args.isEmpty()) { 27 | sender.sendMessage("§cPlease specify an item name") 28 | return false 29 | } 30 | 31 | val itemName = args.joinToString(" ") 32 | 33 | try { 34 | sender.inventory.addItem(SpecialItems.valueOf(itemName).itemStack(sender)) 35 | } catch (ignored: IllegalArgumentException) { } 36 | 37 | getAPIResults(itemName).execute { jsonObjects -> 38 | if (jsonObjects.isEmpty()) { 39 | sender.sendMessage("§c\"$itemName\" was not found") 40 | return@execute 41 | } 42 | if (jsonObjects.size == 1) { 43 | val wynnItem = WynnItem.parse(jsonObjects[0]) 44 | sender.inventory.addItem(wynnItem.generateNewItem(sender)) 45 | } else { 46 | val inv = Bukkit.createInventory(sender, (jsonObjects.size / 9 + 1) * 9, Component.text("Your Items")) 47 | val wynnItems = jsonObjects.mapNotNull { WynnItem.parse(it).takeUnless { we -> we.isNormal() } } 48 | inv.addItem(*Array(wynnItems.size) { i -> 49 | wynnItems[i].generateNewItem(sender) 50 | }) 51 | Bukkit.getScheduler().scheduleSyncDelayedTask(wynnlab) { 52 | sender.openInventory(inv) 53 | } 54 | } 55 | } 56 | 57 | return true 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/PVPCommands.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.api.hasScoreboardTag 4 | import com.wynnlab.api.sendWynnMessage 5 | import com.wynnlab.gui.PVPGUI 6 | import org.bukkit.Bukkit 7 | import org.bukkit.command.Command 8 | import org.bukkit.command.CommandSender 9 | import org.bukkit.entity.Player 10 | 11 | object PVPCommands : BaseCommand("pvp", "hub", "leave", "stats") { 12 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 13 | return when (label) { 14 | "pvp" -> pvp(sender, args) 15 | "hub" -> hub(sender, args) 16 | "leave", "l" -> leave(sender, args) 17 | "stats" -> stats(sender, args) 18 | else -> false 19 | } 20 | } 21 | 22 | fun pvp(sender: CommandSender, args: Array): Boolean { 23 | if (args.isNotEmpty()) 24 | return false 25 | 26 | if (sender !is Player) { 27 | sender.sendMessage("§cThis command can only be executed by players!") 28 | return true 29 | } 30 | 31 | if (sender.hasScoreboardTag("pvp")) { 32 | sender.sendMessage("§cYou can't use that command during pvp") 33 | return true 34 | } 35 | 36 | PVPGUI(sender).show() 37 | 38 | return true 39 | } 40 | 41 | private fun hub(sender: CommandSender, args: Array): Boolean { 42 | if (args.isNotEmpty()) 43 | return false 44 | 45 | if (sender !is Player) { 46 | sender.sendMessage("§cThis command can only be executed by players!") 47 | return true 48 | } 49 | 50 | sender.teleport(Bukkit.getWorld("neww")!!.spawnLocation) 51 | 52 | return true 53 | } 54 | 55 | private fun leave(sender: CommandSender, args: Array): Boolean { 56 | if (args.isNotEmpty()) 57 | return false 58 | 59 | if (sender !is Player) { 60 | sender.sendMessage("§cThis command can only be executed by players!") 61 | return true 62 | } 63 | 64 | if (!sender.hasScoreboardTag("pvp")) { 65 | sender.sendMessage("§cThere's nothing to leave") 66 | return true 67 | } 68 | 69 | sender.teleport(Bukkit.getWorld("neww")!!.spawnLocation) 70 | 71 | return true 72 | } 73 | 74 | private fun stats(sender: CommandSender, args: Array): Boolean { 75 | if (args.size > 1) 76 | return false 77 | 78 | if (sender !is Player) { 79 | sender.sendMessage("§cThis command can only be executed by players!") 80 | return true 81 | } 82 | 83 | if (!sender.hasScoreboardTag("ffa")) { 84 | sender.sendMessage("§cYou don't have stats here") 85 | return true 86 | } 87 | 88 | val target = if (args.isEmpty()) sender else Bukkit.getPlayer(args[0]) ?: run { 89 | sender.sendWynnMessage("messages.player_not_exist") 90 | return true 91 | } 92 | 93 | sender.sendWynnMessage("messages.stats.stats_of", target.name) 94 | sender.sendWynnMessage("messages.stats.kills", 0) 95 | sender.sendWynnMessage("messages.stats.deaths", 0) 96 | sender.sendWynnMessage("messages.stats.kd", 0) 97 | sender.sendWynnMessage("messages.stats.damage_dealt", 0) 98 | sender.sendWynnMessage("messages.stats.damage_taken", 0) 99 | 100 | return true 101 | } 102 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/RankCommand.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands 2 | 3 | import com.wynnlab.essentials.Rank 4 | import org.bukkit.command.Command 5 | import org.bukkit.command.CommandSender 6 | import org.bukkit.entity.Player 7 | 8 | object RankCommand : BaseCommand("rank") { 9 | override fun onCommand(sender: CommandSender, command: Command, label: String, args: Array): Boolean { 10 | if (!sender.isOp) { 11 | sender.sendMessage("§cYou need to be an operator to execute this command") 12 | return true 13 | } 14 | if (args.isEmpty()) { 15 | sender.sendMessage("§cPlease specify a rank") 16 | return false 17 | } 18 | 19 | val rank: Rank = try { 20 | Rank.valueOf(args[0].toUpperCase()) 21 | } catch (e: IllegalArgumentException) { 22 | sender.sendMessage("§cPlease specify a valid rank") 23 | return false 24 | } 25 | 26 | val targets: List = if (args.size == 1) { 27 | if (sender is Player) listOf(sender) else null 28 | } else { 29 | if (args.size == 2) sender.server.selectEntities(sender, args[1]).filterIsInstance() else null 30 | } ?: run { 31 | sender.sendMessage("§cPlease specify a valid target") 32 | return false 33 | } 34 | 35 | targets.forEach { 36 | rank.apply(it) 37 | } 38 | 39 | return true 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/BaseTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.command.TabCompleter 5 | 6 | abstract class BaseTabCompleter(vararg val names: String) : TabCompleter { 7 | fun completeWord(words: List, input: String) = words.filter { it.startsWith(input) } 8 | } 9 | 10 | fun registerTabCompleters() { 11 | registerTabCompleter(BuildTabCompleter) 12 | registerTabCompleter(CastTabCompleter) 13 | registerTabCompleter(ClassTabCompleter) 14 | registerTabCompleter(EssentialsTabCompleters) 15 | registerTabCompleter(GMTabCompleters) 16 | registerTabCompleter(ItemTabCompleter) 17 | registerTabCompleter(MobTabCompleter) 18 | registerTabCompleter(RankTabCompleter) 19 | registerTabCompleter(NoTabCompleter) 20 | } 21 | 22 | private fun registerTabCompleter(tabCompleter: BaseTabCompleter) { 23 | for (name in tabCompleter.names) 24 | wynnlab.getCommand(name)?.tabCompleter = tabCompleter 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/BuildTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import com.wynnlab.items.Build 4 | import org.bukkit.command.Command 5 | import org.bukkit.command.CommandSender 6 | import org.bukkit.entity.Player 7 | 8 | object BuildTabCompleter : BaseTabCompleter("build") { 9 | override fun onTabComplete( 10 | sender: CommandSender, 11 | command: Command, 12 | alias: String, 13 | args: Array 14 | ): List? = if (sender is Player && args.size == 2) when (args[0]) { 15 | "save" -> emptyList() 16 | "equip", "delete", "publish" -> completeWord(Build.buildNamesOf(sender).toList(), args[1]) 17 | else -> null 18 | } else if (args.size == 1) completeWord(subcommands, args[0]) else emptyList() 19 | 20 | private val subcommands = listOf("save", "equip", "delete", "publish", "show") 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/CastTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import org.bukkit.command.Command 4 | import org.bukkit.command.CommandSender 5 | 6 | object CastTabCompleter : BaseTabCompleter("cast") { 7 | override fun onTabComplete( 8 | sender: CommandSender, 9 | command: Command, 10 | alias: String, 11 | args: Array 12 | ): List? = if (args.size == 1) 13 | castIds 14 | else null 15 | 16 | private val castIds = listOf("1", "2", "3", "4") 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/ClassTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import org.bukkit.command.Command 4 | import org.bukkit.command.CommandSender 5 | 6 | object ClassTabCompleter : BaseTabCompleter("class") { 7 | override fun onTabComplete( 8 | sender: CommandSender, 9 | command: Command, 10 | alias: String, 11 | args: Array 12 | ): List? = if (args.size == 1) 13 | completeWord(classes, args[0]) 14 | else null 15 | 16 | private val classes = listOf("archer", "assassin", "mage", "shaman", "warrior") 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/EssentialsTabCompleters.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import org.bukkit.command.Command 4 | import org.bukkit.command.CommandSender 5 | import org.bukkit.entity.Player 6 | 7 | object EssentialsTabCompleters : BaseTabCompleter("msg", "party") { 8 | override fun onTabComplete( 9 | sender: CommandSender, 10 | command: Command, 11 | alias: String, 12 | args: Array 13 | ): List? = 14 | when (alias) { 15 | "msg" -> { 16 | if (args.size == 1) 17 | (sender as? Player)?.world?.players?.map { it.name } 18 | else null 19 | } 20 | "party" -> { 21 | when { 22 | args.size == 1 -> completeWord(partyArgs, args[0]) 23 | args.size > 1 -> when (args[0]) { 24 | "invite" -> (sender as? Player)?.world?.players?.map { it.name } 25 | else -> null 26 | } 27 | else -> null 28 | } 29 | } 30 | else -> null 31 | } 32 | 33 | private val partyArgs = listOf("create", "invite", "join", "leave") 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/GMTabCompleters.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("IntroduceWhenSubject") 2 | 3 | package com.wynnlab.commands.tab_completers 4 | 5 | import org.bukkit.command.Command 6 | import org.bukkit.command.CommandSender 7 | 8 | object GMTabCompleters : BaseTabCompleter("upload", "wlrl") { 9 | override fun onTabComplete( 10 | sender: CommandSender, 11 | command: Command, 12 | alias: String, 13 | args: Array 14 | ): List? = 15 | when (alias) { 16 | "upload" -> if (args.size == 1) 17 | completeWord(uploadArgs, args[0]) 18 | else null 19 | "wlrl" -> when { 20 | args.size == 1 -> completeWord(wlrlArgs, args[0]) 21 | else -> null 22 | } 23 | else -> null 24 | } 25 | 26 | private val uploadArgs = listOf("item", "mob", "mob_spell", "music") 27 | 28 | private val wlrlArgs = listOf("mob", "mobs", "class", "classes") 29 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/ItemTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import com.wynnlab.items.getAPIResults 4 | import org.bukkit.command.Command 5 | import org.bukkit.command.CommandSender 6 | 7 | object ItemTabCompleter : BaseTabCompleter("item") { 8 | override fun onTabComplete( 9 | sender: CommandSender, 10 | command: Command, 11 | alias: String, 12 | args: Array 13 | ): List? { 14 | if (args.isEmpty()) 15 | return null 16 | 17 | val itemName = args.joinToString(" ") 18 | 19 | if (itemName.length < 3) 20 | return listOf(args.last()) 21 | 22 | val apiResults = getAPIResults(itemName).task() 23 | 24 | val list = apiResults.mapNotNull { 25 | it["name"] as String? 26 | } 27 | 28 | return if (args.size == 1) 29 | list 30 | else 31 | list.filter { it.startsWith(itemName, ignoreCase = true) } 32 | .map { it.substring(itemName.length - args.last().length) } 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/MobTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.command.Command 5 | import org.bukkit.command.CommandSender 6 | import java.io.File 7 | 8 | object MobTabCompleter : BaseTabCompleter("mob") { 9 | override fun onTabComplete( 10 | sender: CommandSender, 11 | command: Command, 12 | alias: String, 13 | args: Array 14 | ): List? { 15 | if (args.isEmpty()) 16 | return null 17 | 18 | return completeWord( 19 | (File(wynnlab.dataFolder, "mobs").list() ?: return emptyList()).asList() 20 | .filter { it.endsWith(".yml") }.map { it.substring(0, it.length - 4) }, 21 | args[0]) 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/NoTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import org.bukkit.command.Command 4 | import org.bukkit.command.CommandSender 5 | 6 | object NoTabCompleter : BaseTabCompleter("pvp", "hub", "leave") { 7 | override fun onTabComplete( 8 | _0: CommandSender, 9 | _1: Command, 10 | _2: String, 11 | _3: Array 12 | ): List? = null 13 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/commands/tab_completers/RankTabCompleter.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.commands.tab_completers 2 | 3 | import org.bukkit.command.Command 4 | import org.bukkit.command.CommandSender 5 | 6 | object RankTabCompleter : BaseTabCompleter("rank") { 7 | override fun onTabComplete( 8 | sender: CommandSender, 9 | command: Command, 10 | alias: String, 11 | args: Array 12 | ): List? = if (args.size == 1) 13 | completeWord(ranks, args[0]) 14 | else null 15 | 16 | private val ranks = listOf("player", "vip", "vip+", "hero", "champion", "ct", "mod", "admin") 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/CustomEntity.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities 2 | 3 | import net.minecraft.world.entity.Entity 4 | import org.bukkit.World 5 | import org.bukkit.craftbukkit.v1_17_R1.CraftWorld 6 | import org.bukkit.event.entity.CreatureSpawnEvent 7 | 8 | interface CustomEntity { 9 | fun spawn(world: World) { 10 | (world as CraftWorld).addEntity(this as Entity, CreatureSpawnEvent.SpawnReason.CUSTOM) 11 | } 12 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/Dummy.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities 2 | 3 | import net.minecraft.network.chat.ChatComponentText 4 | import net.minecraft.world.entity.EntityTypes 5 | import net.minecraft.world.entity.ai.attributes.GenericAttributes 6 | import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat 7 | import net.minecraft.world.entity.monster.EntityVindicator 8 | import org.bukkit.Location 9 | import org.bukkit.craftbukkit.v1_17_R1.CraftWorld 10 | import org.bukkit.entity.Vindicator 11 | 12 | class Dummy(location: Location) : EntityVindicator(EntityTypes.aW, (location.world as CraftWorld).handle), CustomEntity { 13 | init { 14 | setLocation(location.x, location.y, location.z, location.yaw, location.pitch) 15 | 16 | //collides = false 17 | 18 | customName = ChatComponentText("Dummy") 19 | customNameVisible = true 20 | 21 | getAttributeInstance(GenericAttributes.a)!!.value = 100000.0 22 | health = 100000f 23 | } 24 | 25 | override fun initPathfinder() { 26 | bO.a(0, PathfinderGoalFloat(this)) 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/Hologram.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities 2 | 3 | import com.wynnlab.wynnlab 4 | import net.minecraft.network.chat.ChatComponentText 5 | import net.minecraft.world.entity.EntityTypes 6 | import net.minecraft.world.entity.decoration.EntityArmorStand 7 | import org.bukkit.Bukkit 8 | import org.bukkit.Location 9 | import org.bukkit.craftbukkit.v1_17_R1.CraftWorld 10 | import org.bukkit.entity.ArmorStand 11 | 12 | class Hologram(location: Location, text: String) : EntityArmorStand(EntityTypes.c, (location.world as CraftWorld).handle), CustomEntity { 13 | init { 14 | isInvisible = true 15 | isInvulnerable = true 16 | collides = false 17 | isNoGravity = true 18 | isSmall = true 19 | 20 | setLocation(location.x, location.y, location.z, location.yaw, location.pitch) 21 | 22 | customName = ChatComponentText(text) 23 | customNameVisible = true 24 | } 25 | 26 | fun removeAfter(time: Long) = Bukkit.getScheduler().runTaskLater(wynnlab, ::remove, time) 27 | 28 | fun remove() { 29 | die() 30 | } 31 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/class stubs.txt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities 2 | 3 | import com.wynnlab.spells.MobSpell 4 | import net.minecraft.server.v1_16_R3.Entity 5 | import net.minecraft.server.v1_16_R3.EntityTypes 6 | import net.minecraft.server.v1_16_R3.EntityVindicator 7 | import org.bukkit.Location 8 | import org.bukkit.Sound 9 | import org.bukkit.craftbukkit.v1_16_R3.CraftWorld 10 | import org.bukkit.entity.Projectile 11 | import org.bukkit.entity.Vindicator 12 | 13 | class WEntityImpl( 14 | val location: Location, 15 | val name: String, 16 | val level: Int, 17 | val ai: WynnMob.AI, 18 | val health: Int, 19 | val regen: Int, 20 | val damage: IntRange, 21 | val attackSpeed: Double, 22 | val projectile: Class?, 23 | val speed: Double, 24 | val vision: Double, 25 | val invisible: Boolean = false, 26 | val burning: Boolean = false, 27 | val baby: Boolean = false, 28 | val defense: Double, 29 | val elementalDamage: WynnMob.Elemental?, 30 | val elementalDefense: WynnMob.Elemental?, 31 | val ambientSound: Sound, 32 | val hurtSound: Sound, 33 | val deathSound: Sound, 34 | val kbResistance: Double, 35 | val spells: List 36 | ) : WEntity { 37 | override fun init(entity: Entity) { 38 | entity.setLocation(location.x, location.y, location.z, location.yaw, location.pitch) 39 | } 40 | } 41 | 42 | interface WEntity : CustomEntity { 43 | fun init(entity: Entity) 44 | } 45 | 46 | class WVindicator( 47 | location: Location, 48 | name: String, 49 | level: Int, 50 | ai: WynnMob.AI, 51 | health: Int, 52 | regen: Int, 53 | damage: IntRange, 54 | attackSpeed: Double, 55 | projectile: Class?, 56 | speed: Double, 57 | vision: Double, 58 | invisible: Boolean = false, 59 | burning: Boolean = false, 60 | baby: Boolean = false, 61 | defense: Double, 62 | elementalDamage: WynnMob.Elemental?, 63 | elementalDefense: WynnMob.Elemental?, 64 | ambientSound: Sound, 65 | hurtSound: Sound, 66 | deathSound: Sound, 67 | kbResistance: Double, 68 | spells: List 69 | ) : EntityVindicator(EntityTypes.VINDICATOR, (location.world as CraftWorld).handle), 70 | WEntity by WEntityImpl(location, name, level, ai, health, regen, damage, attackSpeed, projectile, speed, vision, invisible, burning, baby, defense, elementalDamage, elementalDefense, ambientSound, hurtSound, deathSound, kbResistance, spells) { 71 | init { 72 | init(this) 73 | } 74 | } 75 | fun createWVindicator( 76 | location: Location, 77 | name: String, 78 | level: Int, 79 | ai: WynnMob.AI, 80 | health: Int, 81 | regen: Int, 82 | damage: IntRange, 83 | attackSpeed: Double, 84 | projectile: Class?, 85 | speed: Double, 86 | vision: Double, 87 | invisible: Boolean = false, 88 | burning: Boolean = false, 89 | baby: Boolean = false, 90 | defense: Double, 91 | elementalDamage: WynnMob.Elemental?, 92 | elementalDefense: WynnMob.Elemental?, 93 | ambientSound: Sound, 94 | hurtSound: Sound, 95 | deathSound: Sound, 96 | kbResistance: Double, 97 | spells: List 98 | ) = WVindicator(location, name, level, ai, health, regen, damage, attackSpeed, projectile, speed, vision, invisible, burning, baby, defense, elementalDamage, elementalDefense, ambientSound, hurtSound, deathSound, kbResistance, spells) 99 | 100 | val entityTypeToClass: Map, (Location, String, Int, WynnMob.AI, Int, Int, IntRange, Double, Class?, Double, Double, Boolean, Boolean, Boolean, Double, WynnMob.Elemental?, WynnMob.Elemental?, Sound, Sound, Sound, Double, List) -> Entity> = 101 | hashMapOf(EntityTypes.VINDICATOR to ::createWVindicator) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/pathfinder/PathfinderGoalCastSpell.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities.pathfinder 2 | 3 | import com.wynnlab.base.BaseSpell 4 | import com.wynnlab.mobs.spells.BaseMobSpell 5 | import com.wynnlab.spells.MobSpell 6 | import com.wynnlab.wynnlab 7 | import net.minecraft.server.level.EntityPlayer 8 | import net.minecraft.world.entity.EntityCreature 9 | import net.minecraft.world.entity.EntityLiving 10 | import net.minecraft.world.entity.ai.goal.PathfinderGoal 11 | import org.bukkit.Bukkit 12 | import org.bukkit.NamespacedKey 13 | import org.bukkit.entity.Entity 14 | import org.bukkit.entity.Player 15 | import java.util.* 16 | 17 | class PathfinderGoalCastSpell(private val creature: EntityCreature, range: Double, private val spells: List) : PathfinderGoal() { 18 | private val range = range * range 19 | 20 | private var cooldown = 20 21 | private var prepare = 0 22 | 23 | private var target: EntityLiving? = null 24 | 25 | private var mobSpell: MobSpell? = null 26 | private var baseMobSpell: BaseMobSpell? = null 27 | private var runnable: MobSpell.Ticks? = null 28 | 29 | init { 30 | a(EnumSet.of(Type.b)) 31 | } 32 | 33 | override fun a(): Boolean { 34 | if (cooldown > 0) { 35 | --cooldown 36 | return false 37 | } 38 | 39 | target = (creature.goalTarget as? EntityPlayer) ?: return false 40 | 41 | if (target == null) 42 | return false 43 | 44 | if (target!!.f(creature) > range) 45 | return false 46 | 47 | return true 48 | } 49 | 50 | override fun c() { 51 | val spell = try { spells.random() } catch (e: NoSuchElementException) { return } 52 | if (spell is MobSpell) mobSpell = spell else baseMobSpell = (spell as (Entity, Player) -> BaseMobSpell)(creature.bukkitEntity, target!!.bukkitEntity as Player) 53 | 54 | cooldown = mobSpell?.cooldown ?: baseMobSpell!!.cooldown 55 | prepare = mobSpell?.prepareTime ?: 20 56 | 57 | //spell!!.spellEffects(creature.bukkitEntity) 58 | mobSpell?.spellEffects(creature.bukkitEntity) ?: MobSpell.spellEffects(creature.bukkitEntity) 59 | 60 | if (mobSpell?.hasBossBar == true) 61 | creature.bukkitEntity.world.getNearbyEntities(creature.bukkitEntity.location, 10.0, 10.0, 10.0) { it is Player } 62 | .forEach { mobSpell!!.bossBar!!.addPlayer(it as Player) } 63 | } 64 | 65 | override fun b(): Boolean { 66 | if (mobSpell == null && baseMobSpell == null) 67 | return false 68 | 69 | if (prepare > 0) { 70 | --prepare 71 | 72 | if (mobSpell?.hasBossBar == true) 73 | mobSpell!!.bossBar!!.progress = 1.0 - prepare / mobSpell!!.prepareTime.toDouble() 74 | 75 | return true 76 | } else if (prepare == 0) { 77 | if (mobSpell?.hasBossBar == true) { 78 | mobSpell!!.bossBar!!.removeAll() 79 | Bukkit.removeBossBar(NamespacedKey(wynnlab, "prepare_${creature.id}")) 80 | } 81 | 82 | runnable = mobSpell?.newInstance(creature.bukkitEntity, target!!.bukkitEntity as Player) 83 | baseMobSpell?.onCast() 84 | --prepare 85 | } 86 | 87 | if (!(runnable?.tick() ?: true.also { baseMobSpell!!.onTick() })) 88 | return false 89 | 90 | //++runnable!!.t 91 | runnable?.t?.inc() ?: baseMobSpell!!.t.inc() 92 | 93 | val cancel = (runnable?.t ?: baseMobSpell!!.t) > (mobSpell?.maxTick ?: BaseSpell::class.java.getDeclaredField("maxTick").getInt(runnable)) 94 | 95 | if (cancel && baseMobSpell != null) 96 | baseMobSpell!!.onCancel() 97 | 98 | return !cancel 99 | } 100 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/pathfinder/PathfinderGoalMeleeAttack.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities.pathfinder 2 | 3 | class PathfinderGoalMeleeAttack -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/entities/pathfinder/PathfinderGoalRangedAttack.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.entities.pathfinder 2 | 3 | import net.minecraft.world.entity.EntityCreature 4 | import net.minecraft.world.entity.EntityLiving 5 | import net.minecraft.world.entity.ai.goal.PathfinderGoal 6 | import org.bukkit.Material 7 | import org.bukkit.entity.Projectile 8 | import org.bukkit.entity.Snowball 9 | import org.bukkit.inventory.ItemStack 10 | import org.bukkit.projectiles.ProjectileSource 11 | import java.util.* 12 | 13 | class PathfinderGoalRangedAttack(private val creature: EntityCreature, range: Double, private val cooldown: Int, private val projectile: Class, private val projectileMaterial: Material?) : PathfinderGoal() { 14 | private val range = range * range 15 | 16 | private var c = cooldown 17 | 18 | private var target: EntityLiving? = null 19 | 20 | init { 21 | a(EnumSet.of(Type.b)) 22 | } 23 | 24 | override fun a(): Boolean { 25 | if (c > 0) { 26 | --c 27 | return false 28 | } 29 | 30 | c = cooldown 31 | 32 | target = creature.goalTarget 33 | 34 | if (target == null) 35 | return false 36 | 37 | if (target!!.f(creature) > range) 38 | return false 39 | 40 | return true 41 | } 42 | 43 | override fun c() { 44 | val p = ((creature.bukkitEntity as? ProjectileSource) ?: return).launchProjectile(projectile, target!!.bukkitEntity.location.toVector().subtract(creature.bukkitEntity.location.toVector()).normalize().multiply(3)) 45 | 46 | if (p is Snowball && projectileMaterial != null) 47 | p.item = ItemStack(projectileMaterial) 48 | 49 | p.addScoreboardTag("mob_projectile") 50 | } 51 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/essentials/Party.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.essentials 2 | 3 | import com.wynnlab.COLOR_HEALTH_HEART 4 | import com.wynnlab.COLOR_HEALTH_VALUE 5 | import com.wynnlab.COLOR_PARTY 6 | import com.wynnlab.PREFIX 7 | import com.wynnlab.api.sendWynnMessage 8 | import com.wynnlab.localization.Language 9 | import net.kyori.adventure.text.Component 10 | import net.kyori.adventure.text.event.ClickEvent 11 | import net.kyori.adventure.text.event.HoverEvent 12 | import net.kyori.adventure.text.format.NamedTextColor 13 | import net.kyori.adventure.text.format.Style 14 | import net.kyori.adventure.text.format.TextDecoration 15 | import org.bukkit.entity.Player 16 | 17 | data class Party( 18 | var owner: Player, 19 | val members: MutableList = mutableListOf() 20 | ) { 21 | var healthTexts = listOf() 22 | 23 | fun addMember(player: Player) { 24 | this.members.forEach { 25 | it.sendWynnMessage("messages.party.joined", player.name) 26 | } 27 | 28 | this.members.add(player) 29 | Party.members[player] = this 30 | 31 | player.sendWynnMessage("messages.party.joined_you") 32 | } 33 | 34 | fun removeMember(player: Player) { 35 | player.sendWynnMessage("messages.party.left_you") 36 | 37 | this.members.remove(player) 38 | Party.members.remove(player) 39 | 40 | this.members.forEach { 41 | it.sendWynnMessage("messages.party.left", player.name) 42 | } 43 | 44 | if (members.isEmpty()) { 45 | parties.remove(this) 46 | return 47 | } 48 | 49 | if (player == owner) { 50 | promote(this.members[0]) 51 | } 52 | } 53 | 54 | private fun promote(player: Player) { 55 | player.sendWynnMessage("messages.party.promote") 56 | 57 | owner = player 58 | } 59 | 60 | @Suppress("unchecked_cast") 61 | fun invite(player: Player) { 62 | invites[player] = this 63 | 64 | val language = Language[player.locale()] 65 | 66 | player.sendMessage("$PREFIX${language.getMessage("messages.party.invite.get", owner.name)}") 67 | 68 | player.sendMessage( 69 | Component.text("$PREFIX${language.getMessage("messages.party.join.left")}") 70 | .append(language.getMessage("messages.party.join.link") 71 | .hoverEvent { HoverEvent.showText( 72 | language.getMessage("messages.party.join.hover") 73 | ) as HoverEvent } 74 | .clickEvent(ClickEvent.runCommand("/party join"))) 75 | .append(language.getMessage("messages.party.join.right")) 76 | ) 77 | 78 | owner.sendWynnMessage("messages.party.invite.send", player.name) 79 | } 80 | 81 | internal fun update() { 82 | healthTexts = members.sortedBy { it.health }.map { 83 | Component.text("- ", COLOR_PARTY) 84 | .append(Component.text(it.health.toInt(), COLOR_HEALTH_VALUE)) 85 | .append(Component.text("❤ ", COLOR_HEALTH_HEART)) 86 | .append(Component.text(it.name, if (it.isDead) Style.style(NamedTextColor.DARK_GRAY, TextDecoration.STRIKETHROUGH) else Style.style(NamedTextColor.WHITE))) 87 | } 88 | } 89 | 90 | fun getSbTexts(): List { 91 | return healthTexts 92 | } 93 | 94 | companion object { 95 | val parties = mutableListOf() 96 | 97 | val members = mutableMapOf() 98 | 99 | val invites = mutableMapOf() 100 | } 101 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/essentials/Rank.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.essentials 2 | 3 | import com.wynnlab.api.data 4 | import com.wynnlab.api.prefix 5 | import com.wynnlab.api.setString 6 | import org.bukkit.ChatColor 7 | import org.bukkit.entity.Player 8 | 9 | enum class Rank( 10 | val donation: Boolean, 11 | val tag: String, 12 | private val color: ChatColor 13 | ) { 14 | PLAYER(false, "", ChatColor.WHITE), 15 | 16 | VIP(true, "§a[VIP] ", ChatColor.GREEN), 17 | @Suppress("EnumEntryName") `VIP+`(true, "§b[§3VIP+§b] ", ChatColor.AQUA), 18 | HERO(true, "§5[§dHERO§5] ", ChatColor.DARK_PURPLE), 19 | CHAMPION(true, "§e[§6CHAMPION§e] ", ChatColor.YELLOW), 20 | 21 | CT(false, "§3[CT] ", ChatColor.DARK_AQUA), 22 | MOD(false, "§6[§eMOD§6] ", ChatColor.GOLD), 23 | ADMIN(false, "§4[§cADMIN§4] ", ChatColor.DARK_RED); 24 | 25 | /*private val team: Team = registerMainTeam("WynnLab.${name}") 26 | 27 | init { 28 | team.color = color 29 | team.prefix = tag 30 | team.displayName = name 31 | }*/ 32 | 33 | fun apply(player: Player) { 34 | //team.addEntry(player.name) 35 | player.prefix = tag+color 36 | player.data.setString("rank", name) 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/events/SpellCastEvent.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.events 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.event.Event 5 | import org.bukkit.event.HandlerList 6 | 7 | class SpellCastEvent(val player: Player, val spellId: Int) : Event() { 8 | override fun getHandlers(): HandlerList = handlerList 9 | 10 | companion object { 11 | @JvmStatic 12 | val handlerList = HandlerList() 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/events/WorldInstanceEvents.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.events 2 | 3 | class DeleteWorldInstanceEvent() -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/gui/ClassGUI.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.gui 2 | 3 | import com.wynnlab.Tuple4 4 | import com.wynnlab.WynnClass 5 | import com.wynnlab.api.* 6 | import com.wynnlab.classes 7 | import com.wynnlab.classes.BaseClass 8 | import com.wynnlab.util.emptyComponent 9 | import org.bukkit.Sound 10 | import org.bukkit.entity.Player 11 | import org.bukkit.event.inventory.ClickType 12 | import org.bukkit.inventory.ItemFlag 13 | import org.bukkit.inventory.ItemStack 14 | import org.bukkit.inventory.meta.Damageable 15 | 16 | class ClassGUI(player: Player) : GUI(player, player.getLocalizedText("gui.class.title"), 1) { 17 | private val classCount = classes.size 18 | private val itemPositions = (5 - (classCount + .5f) / 2f).toInt()..(4 + classCount / 2) 19 | 20 | init { 21 | registerListener { e -> 22 | e.isCancelled = true 23 | 24 | val classIndex = itemPositions.indexOf(e.slot) 25 | if (classIndex == -1) return@registerListener 26 | val clazz = classes.values.toList()[classIndex] 27 | 28 | if (when (e.click) { 29 | ClickType.LEFT, ClickType.SHIFT_LEFT -> false 30 | ClickType.RIGHT, ClickType.SHIFT_RIGHT -> true 31 | else -> return@registerListener 32 | }) { 33 | player.sendWynnMessage("gui.class.select", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.cloneName")) 34 | player.addScoreboardTag("clone") 35 | } else { 36 | player.sendWynnMessage("gui.class.select", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.className")) 37 | player.removeScoreboardTag("clone") 38 | } 39 | 40 | player.playSound(player.location, Sound.ENTITY_PLAYER_LEVELUP, 1f, 1f) 41 | 42 | player.setWynnClass((clazz as? WynnClass)?.id ?: (clazz as BaseClass).id) 43 | 44 | player.closeInventory() 45 | } 46 | } 47 | 48 | override fun update() { 49 | val iterator = itemPositions.iterator() 50 | 51 | for (clazz in classes.values) { 52 | /*if (clazz is BaseClass) { 53 | inventory.setItem(iterator.nextInt(), ItemStack(Material.BARRIER)) 54 | continue 55 | } 56 | if (clazz !is WynnClass && clazz !is BaseClass) 57 | continue*/ 58 | 59 | val item = (clazz as? WynnClass)?.item?.let { ItemStack(it) } ?: (clazz as BaseClass).item 60 | val meta = item.itemMeta 61 | 62 | meta.isUnbreakable = true 63 | meta.addItemFlags(*ItemFlag.values()) 64 | 65 | if (clazz is WynnClass && clazz.itemDamage != 0 && meta is Damageable) 66 | meta.damage = clazz.itemDamage 67 | 68 | meta.displayName(player.getLocalizedText("gui.class.item.title", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.className"))) 69 | val lore = mutableListOf(emptyComponent) 70 | 71 | val (damage, defence, range, spells) = (clazz as? WynnClass)?.metaStats ?: (clazz as BaseClass).metaStats.let { (a, b, c, d) -> Tuple4(a, b, c, d) } 72 | lore.add(player.getLocalizedText("gui.class.item.damage", damage.squares())) 73 | lore.add(player.getLocalizedText("gui.class.item.defence", defence.squares())) 74 | lore.add(player.getLocalizedText("gui.class.item.range", range.squares())) 75 | lore.add(player.getLocalizedText("gui.class.item.spells", spells.squares())) 76 | 77 | lore.add(emptyComponent) 78 | lore.addAll(player.getLocalizedTextMultiline("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.lore")) 79 | 80 | lore.add(player.getLocalizedText("gui.class.item.clone", player.getLocalizedString("classes.${(clazz as? WynnClass)?.id ?: (clazz as BaseClass).id}.cloneName"))) 81 | 82 | meta.lore(lore) 83 | item.itemMeta = meta 84 | 85 | inventory.setItem(iterator.nextInt(), item) 86 | } 87 | } 88 | 89 | private fun Int.squares() = when (this) { 90 | 0 -> "§7■■■■■" 91 | 1 -> "§a■§7■■■■" 92 | 2 -> "§a■■§7■■■" 93 | 3 -> "§a■■■§7■■" 94 | 4 -> "§a■■■■§7■" 95 | else -> "§a■■■■■" 96 | } 97 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/gui/GUI.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.gui 2 | 3 | import com.wynnlab.api.meta 4 | import com.wynnlab.listeners.GUIListener 5 | import com.wynnlab.localization.Language 6 | import com.wynnlab.wynnlab 7 | import net.kyori.adventure.text.Component 8 | import net.kyori.adventure.text.TextComponent 9 | import org.bukkit.Bukkit 10 | import org.bukkit.Material 11 | import org.bukkit.entity.Player 12 | import org.bukkit.event.inventory.InventoryClickEvent 13 | import org.bukkit.inventory.ItemStack 14 | 15 | abstract class GUI( 16 | val player: Player, 17 | val title: TextComponent, 18 | private val rows: Int 19 | ) { 20 | val inventory = Bukkit.createInventory(player, rows * 9, title) 21 | 22 | protected val language = Language[player.locale()] 23 | 24 | private val decorator get() = com.wynnlab.gui.decorator 25 | 26 | fun decorate() { 27 | var i = 0 28 | while (i < rows * 9) { 29 | if (i / 9 == 0 || i / 9 == rows - 1) 30 | inventory.setItem(i, decorator) 31 | else if (i % 9 == 0 || i % 9 == 8) 32 | inventory.setItem(i, decorator) 33 | ++i 34 | } 35 | } 36 | 37 | abstract fun update() 38 | 39 | fun show() { 40 | Bukkit.getScheduler().runTaskAsynchronously( 41 | wynnlab, Runnable { 42 | showSync() 43 | }) 44 | } 45 | 46 | fun showSync() { 47 | update() 48 | Bukkit.getScheduler().scheduleSyncDelayedTask(wynnlab) { 49 | player.openInventory(inventory) 50 | } 51 | } 52 | 53 | @GuiListener 54 | inline fun registerListener(crossinline action: (InventoryClickEvent) -> Unit) { 55 | GUIListener.inventories[title.content()] = { 56 | action(it) 57 | update() 58 | } 59 | } 60 | } 61 | 62 | @DslMarker 63 | annotation class GuiListener 64 | 65 | private val decorator = ItemStack(Material.BLACK_STAINED_GLASS_PANE).meta { 66 | displayName(Component.empty()) 67 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/gui/PVPGUI.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.gui 2 | 3 | import com.wynnlab.api.getLocalizedString 4 | import com.wynnlab.api.getLocalizedText 5 | import com.wynnlab.api.getLocalizedTextMultiline 6 | import com.wynnlab.api.meta 7 | import com.wynnlab.java.AddItemFlags 8 | import com.wynnlab.pvp.Duels 9 | import com.wynnlab.pvp.FFA 10 | import com.wynnlab.util.emptyComponent 11 | import org.bukkit.Material 12 | import org.bukkit.entity.Player 13 | import org.bukkit.inventory.ItemStack 14 | import org.bukkit.inventory.meta.Damageable 15 | 16 | class PVPGUI(player: Player) : GUI(player, player.getLocalizedText("gui.pvp.title"), 3) { 17 | init { 18 | registerListener { e -> 19 | e.isCancelled = true 20 | when (val slot = e.slot) { 21 | 10 -> FFA.join(player) 22 | else -> { 23 | val index = slot - 11 24 | val currentDuels = Duels.duels.size 25 | if (index == currentDuels) { 26 | // Start duel 27 | Duels.startDuel(player, 0) 28 | player.closeInventory() 29 | } else if (index < currentDuels) { 30 | // Join / leave duel 31 | val duel = Duels.duels[index] 32 | if (duel.player1?.name != player.name && duel.player2?.name != player.name) { 33 | duel.join(player) 34 | } else if (e.isRightClick) { 35 | duel.leave(player) 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | override fun update() { 44 | decorate() 45 | 46 | inventory.setItem(10, ItemStack(if (FFA.players.size < 100) Material.GREEN_CONCRETE else Material.RED_CONCRETE).meta { 47 | //(this as Damageable).damage = 20 48 | //isUnbreakable = true 49 | //addItemFlags(*ItemFlag.values()) 50 | 51 | displayName(player.getLocalizedText("gui.pvp.ffa.title")) 52 | val l = mutableListOf(emptyComponent) 53 | l.addAll(player.getLocalizedTextMultiline("gui.pvp.ffa.lore")) 54 | l.add(emptyComponent) 55 | l.add(player.getLocalizedText("gui.pvp.ffa.online", FFA.players.size, 100)) 56 | lore(l) 57 | }) 58 | 59 | var i = 10 60 | for (duel in Duels.duels) { 61 | ++i 62 | 63 | val full = duel.player1 != null && duel.player2 != null 64 | inventory.setItem(i, ItemStack(Material.GOLDEN_SHOVEL).meta { 65 | (this as Damageable).damage = if (full) 18 else if (duel.ready) 20 else 19 66 | isUnbreakable = true 67 | AddItemFlags.addAllItemFlags(this) 68 | 69 | displayName(player.getLocalizedText("gui.pvp.duel.title")) 70 | lore(listOf( 71 | player.getLocalizedText("gui.pvp.duel.map", player.getLocalizedString("gui.pvp.duel.maps.${Duels.maps[duel.map]}")), 72 | emptyComponent, 73 | player.getLocalizedText("gui.pvp.duel.player1", duel.player1?.name ?: "-"), 74 | player.getLocalizedText("gui.pvp.duel.player2", duel.player2?.name ?: "-"), 75 | emptyComponent, 76 | player.getLocalizedText(if (full) "gui.pvp.duel.spectate" else if (duel.player1?.name != player.name && duel.player2?.name != player.name) "gui.pvp.duel.join" else "gui.pvp.duel.leave") 77 | )) 78 | }) 79 | } 80 | 81 | ++i 82 | inventory.setItem(i, ItemStack(Material.GOLDEN_SHOVEL).meta { 83 | (this as Damageable).damage = 22 84 | isUnbreakable = true 85 | AddItemFlags.addAllItemFlags(this) 86 | 87 | displayName(player.getLocalizedText("gui.pvp.duel.create.title")) 88 | }) 89 | } 90 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/guilds/Guild.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.guilds 2 | 3 | import com.wynnlab.api.metaAs 4 | import com.wynnlab.util.OnlyAsync 5 | import com.wynnlab.util.getWynncraftAPIResult 6 | import org.bukkit.DyeColor 7 | import org.bukkit.Material 8 | import org.bukkit.block.banner.Pattern 9 | import org.bukkit.block.banner.PatternType 10 | import org.bukkit.inventory.ItemFlag 11 | import org.bukkit.inventory.ItemStack 12 | import org.bukkit.inventory.meta.BannerMeta 13 | import org.json.simple.JSONArray 14 | import org.json.simple.JSONObject 15 | 16 | @OnlyAsync 17 | class Guild(val name: String) { 18 | private val guildObject = getWynncraftAPIResult("https://api.wynncraft.com/public_api.php?action=guildStats&command=${name.replace(" ", "%20")}").task() 19 | val tag = guildObject["prefix"] as String 20 | 21 | val members = (guildObject["members"] as JSONArray).associate { data -> data as JSONObject 22 | (data["name"] as String) to Member( 23 | Member.Rank.valueOf(data["rank"] as String), 24 | data["joinedFriendly"] as String 25 | ) 26 | } 27 | 28 | val banner: ItemStack = try { 29 | val bannerData = guildObject["banner"] as JSONObject 30 | ItemStack(Material.valueOf("${bannerData["base"]}_BANNER")).metaAs { 31 | addItemFlags(*ItemFlag.values()) 32 | for (layer in bannerData["layers"] as JSONArray) { layer as JSONObject 33 | addPattern(Pattern(DyeColor.valueOf(layer["colour"] as String), PatternType.valueOf(layer["pattern"] as String))) 34 | } 35 | } 36 | } catch (e: Exception) { 37 | ItemStack(Material.WHITE_BANNER) 38 | } 39 | 40 | data class Member( 41 | val rank: Rank, 42 | val joined: String 43 | ) { 44 | enum class Rank { 45 | OWNER, CHIEF, STRATEGIST, CAPTAIN, RECRUITER, RECRUIT; 46 | 47 | val friendlyName = name.toLowerCase().capitalize() 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/items/SpecialItems.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.items 2 | 3 | import com.wynnlab.api.* 4 | import com.wynnlab.listeners.PlayerClickListener 5 | import com.wynnlab.spells.PySpell 6 | import com.wynnlab.util.emptyComponent 7 | import org.bukkit.Color 8 | import org.bukkit.Material 9 | import org.bukkit.entity.Player 10 | import org.bukkit.inventory.ItemFlag 11 | import org.bukkit.inventory.ItemStack 12 | import org.bukkit.inventory.meta.PotionMeta 13 | 14 | enum class SpecialItems(val itemStack: (Player) -> ItemStack, private val rightClick: ((Player, ItemStack) -> Unit)?) { 15 | HealPotion ({ p -> 16 | ItemStack(Material.POTION).metaAs { 17 | addItemFlags(*ItemFlag.values()) 18 | 19 | color = Color.FUCHSIA 20 | 21 | displayName(p.getLocalizedText("items.heal_potion.title", 3)) 22 | 23 | val lore = mutableListOf(emptyComponent, 24 | p.getLocalizedText("items.heal_potion.effects"), 25 | p.getLocalizedText("items.heal_potion.heal", 24), 26 | p.getLocalizedText("items.heal_potion.duration"), 27 | emptyComponent, 28 | p.getLocalizedText("items.items.combat_lv_min", "§a✔", 5), 29 | emptyComponent 30 | ) 31 | 32 | lore.addAll(p.getLocalizedTextMultiline("items.heal_potion.lore")) 33 | 34 | lore(lore) 35 | 36 | data.setString("type", "HealPotion") 37 | data.setInt("healing", 24) 38 | 39 | }}, { p, i -> 40 | i.itemMeta.data.getInt("healing")?.toDouble()?.let { PySpell.heal(p, it) } 41 | }); 42 | 43 | init { 44 | if (rightClick != null) 45 | PlayerClickListener.rcEvents[name] = { e -> e.item?.let { rightClick.invoke(e.player, it) } } 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/items/api access.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.items 2 | 3 | import com.wynnlab.wynnlab 4 | import com.wynnlab.util.Deferred 5 | import com.wynnlab.util.getWynncraftAPIResult 6 | import com.wynnlab.util.jsonParser 7 | import org.json.simple.JSONObject 8 | import java.io.File 9 | import java.io.FileNotFoundException 10 | 11 | @Suppress("unchecked_cast") 12 | @Throws(APIException::class) 13 | fun getAPIResults(search: String): Deferred> = Deferred { 14 | val root = getWynncraftAPIResult("https://api.wynncraft.com/public_api.php?action=itemDB&search=${search.replace(" ", "%20")}").task() 15 | val items = (root["items"] as List).toMutableList() 16 | 17 | val customItems = customItemFolder?.listFiles { file -> search in file.name } ?: arrayOf() 18 | customItems.forEach { item -> 19 | items.add(jsonParser.parse(item.readText()) as JSONObject) 20 | } 21 | 22 | items 23 | } 24 | 25 | val customItemFolder by lazy { try { File(wynnlab.dataFolder, "custom_items") } catch (e: FileNotFoundException) { null } } 26 | 27 | class APIException(message: String) : Exception("Could not access the API ($message)") -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/BaseListener.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.Bukkit 5 | import org.bukkit.event.Listener 6 | 7 | abstract class BaseListener : Listener 8 | 9 | fun registerListeners() { 10 | registerListener(CastListener()) 11 | registerListener(CommandListener()) 12 | registerListener(DamageListener()) 13 | registerListener(FallingBlockListener()) 14 | registerListener(GUIListener()) 15 | registerListener(PlayerClickListener()) 16 | registerListener(PlayerEventsListener()) 17 | registerListener(ProjectileHitListener()) 18 | registerListener(ScriptAPIListeners()) 19 | } 20 | 21 | private fun registerListener(listener: BaseListener) { 22 | Bukkit.getPluginManager().registerEvents(listener, wynnlab) 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/CastListener.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import com.wynnlab.WynnClass 4 | import com.wynnlab.api.* 5 | import com.wynnlab.classes 6 | import com.wynnlab.classes.BaseClass 7 | import com.wynnlab.classes.BasePlayerSpell 8 | import com.wynnlab.events.SpellCastEvent 9 | import com.wynnlab.spells.Spell 10 | import com.wynnlab.spells.lifeSteal 11 | import com.wynnlab.spells.manaSteal 12 | import com.wynnlab.util.RefreshRunnable 13 | import net.kyori.adventure.text.Component 14 | import net.kyori.adventure.text.format.NamedTextColor 15 | import net.kyori.adventure.text.format.TextColor 16 | import org.bukkit.Sound 17 | import org.bukkit.entity.Player 18 | import org.bukkit.event.EventHandler 19 | import org.bukkit.event.EventPriority 20 | import kotlin.math.ceil 21 | import kotlin.math.floor 22 | 23 | class CastListener : BaseListener() { 24 | @EventHandler(priority = EventPriority.HIGHEST) 25 | fun onSpellCast(e: SpellCastEvent) { 26 | val player = e.player 27 | val spellClass = player.getWynnClass()?.let { classes[it] } ?: return 28 | val spellId = e.spellId 29 | val spell = ((spellClass as? WynnClass)?.spells?.get(spellId) ?: (spellClass as BaseClass).spells[spellId](player)) 30 | 31 | val cost = cost(player, spellId, (spell as? Spell)?.cost ?: (spell as BasePlayerSpell).cost) 32 | 33 | if (spellId > 0) { 34 | player.data.setInt("spell_cost_extra", if (player.data.getInt("last_spell") == spellId) (player.data.getInt("spell_cost_extra") ?: 0) + 1 else 0) 35 | player.data.setInt("last_spell", spellId) 36 | 37 | RefreshRunnable(player.data, "spell_cost_extra") { 38 | player.data.setInt("spell_cost_extra", 0) 39 | player.data.setInt("last_spell", 0) 40 | }.schedule(100L) 41 | } 42 | 43 | if (spellId > 0) { 44 | if (player.foodLevel > cost) { 45 | player.playSound(player.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, .5f) 46 | player.updateActionBar( 47 | player.getLocalizedText("classes.${player.getWynnClass()}.spells.${if (player.isCloneClass) "${spellId}c" else spellId.toString()}") 48 | .color(TextColor.color(0x75ebf0)) 49 | .append(Component.text(" Cast ", TextColor.color(0x9feaed))) 50 | .append(Component.text("[",TextColor.color(0x23abb0))) 51 | .append(Component.text(-cost, TextColor.color(0x23e1e8))) 52 | .append(Component.text("✺ ", TextColor.color(0x2bd3d9))) 53 | .append(Component.text("]",TextColor.color(0x23abb0))) 54 | //"${} Cast " + 55 | // "§3[§b-${cost}✺§3]" 56 | ) 57 | player.foodLevel -= cost 58 | } else { 59 | player.playSound(player.location, Sound.BLOCK_ANVIL_PLACE, 1f, 1f) 60 | player.updateActionBar(Component.text("Not enough mana!", NamedTextColor.DARK_RED)) 61 | return 62 | } 63 | } else { 64 | if (player.cooldown()) return 65 | } 66 | 67 | if (player.removeScoreboardTag("life_steal")) 68 | lifeSteal(player.getId("life_steal"), player) 69 | if (player.removeScoreboardTag("mana_steal")) 70 | manaSteal(player.getId("mana_steal"), player) 71 | player.removeScoreboardTag("no_life_steal") 72 | player.removeScoreboardTag("no_mana_steal") 73 | player.removeScoreboardTag("no_exploding") 74 | 75 | (spell as? Spell)?.cast(player) ?: (spell as BasePlayerSpell).schedule() 76 | } 77 | 78 | private fun cost(player: Player, spellIndex: Int, cost: Int) = 79 | floor(ceil(cost * (1.0 - skillPercentage(player.getSkill(2)).let { if (player.hasScoreboardTag("pvp")) it.coerceAtMost(.55) else it }) + player.getId("spell_cost_raw_$spellIndex")) * 80 | (1.0 + player.getId("spell_cost_pct_$spellIndex") / 100.0) + (player.data.getInt("spell_cost_extra") ?: 0)).coerceAtLeast(1.0).toInt() 81 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/CommandListener.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import org.bukkit.event.EventHandler 4 | import org.bukkit.event.player.PlayerCommandPreprocessEvent 5 | 6 | class CommandListener : BaseListener() { 7 | @EventHandler 8 | fun onCommandPreprocess(e: PlayerCommandPreprocessEvent) { 9 | if (e.message == "/kill") { 10 | e.player.health = .0 11 | e.message = "/wynnlab:class" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/FallingBlockListener.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.Bukkit 5 | import org.bukkit.Particle 6 | import org.bukkit.entity.FallingBlock 7 | import org.bukkit.event.EventHandler 8 | import org.bukkit.event.EventPriority 9 | import org.bukkit.event.entity.EntityChangeBlockEvent 10 | 11 | class FallingBlockListener : BaseListener() { 12 | @EventHandler(priority = EventPriority.HIGHEST) 13 | fun onTouchGround(e: EntityChangeBlockEvent) { 14 | if (e.entity is FallingBlock) { 15 | if (!e.to.hasGravity()) { 16 | e.entity.world.spawnParticle(Particle.BLOCK_CRACK, e.entity.location, 16, 1.0, 0.25, 1.0, 1.0, e.to.createBlockData()) 17 | val from = e.block.type 18 | Bukkit.getScheduler().runTaskLater(wynnlab, Runnable { e.block.type = from }, 2L) 19 | e.entity.remove() 20 | e.isCancelled = true 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/PlayerClickListener.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import com.wynnlab.api.* 4 | import com.wynnlab.gui.CompassGUI 5 | import org.bukkit.GameMode 6 | import org.bukkit.event.EventHandler 7 | import org.bukkit.event.EventPriority 8 | import org.bukkit.event.block.Action 9 | import org.bukkit.event.player.PlayerAnimationEvent 10 | import org.bukkit.event.player.PlayerAnimationType 11 | import org.bukkit.event.player.PlayerInteractEvent 12 | import org.bukkit.inventory.EquipmentSlot 13 | 14 | class PlayerClickListener : BaseListener() { 15 | @EventHandler(priority = EventPriority.HIGHEST) 16 | fun onLeftClick(e: PlayerAnimationEvent) { 17 | if (e.player.gameMode != GameMode.ADVENTURE) 18 | return 19 | if (e.animationType != PlayerAnimationType.ARM_SWING) 20 | return 21 | 22 | e.player.inventory.itemInMainHand.itemMeta?.data?.getString("type")?.let { 23 | lcEvents[it]?.invoke(e) 24 | } 25 | 26 | if (!e.player.checkWeapon()) 27 | return 28 | 29 | e.player.addLeftClick() 30 | 31 | e.isCancelled = true 32 | } 33 | 34 | @EventHandler(priority = EventPriority.HIGHEST) 35 | fun onRightClick(e: PlayerInteractEvent) { 36 | if (e.player.gameMode != GameMode.ADVENTURE) 37 | return 38 | if (e.action != Action.RIGHT_CLICK_BLOCK && e.action != Action.RIGHT_CLICK_AIR) 39 | return 40 | if (e.hand != EquipmentSlot.HAND) 41 | return 42 | 43 | when (e.player.inventory.heldItemSlot) { 44 | 6 -> { 45 | CompassGUI(e.player).show() 46 | e.isCancelled = true 47 | } 48 | 7 -> { 49 | e.isCancelled = true 50 | } 51 | 8 -> { 52 | e.isCancelled = true 53 | } 54 | else -> { 55 | e.player.inventory.itemInMainHand.itemMeta?.data?.getString("type")?.let { 56 | rcEvents[it]?.invoke(e) 57 | } 58 | 59 | if (!e.player.checkWeapon()) 60 | return 61 | 62 | e.player.addRightClick() 63 | e.isCancelled = true 64 | } 65 | } 66 | } 67 | 68 | companion object { 69 | val rcEvents = hashMapOf Unit>( 70 | "HELMET" to { e -> 71 | val l = e.player.inventory.helmet 72 | e.player.inventory.helmet = e.player.inventory.itemInMainHand 73 | e.player.inventory.setItemInMainHand(l) 74 | }, 75 | "CHESTPLATE" to { e -> 76 | val l = e.player.inventory.chestplate 77 | e.player.inventory.chestplate = e.player.inventory.itemInMainHand 78 | e.player.inventory.setItemInMainHand(l) 79 | }, 80 | "LEGGINGS" to { e -> 81 | val l = e.player.inventory.leggings 82 | e.player.inventory.leggings = e.player.inventory.itemInMainHand 83 | e.player.inventory.setItemInMainHand(l) 84 | }, 85 | "BOOTS" to { e -> 86 | val l = e.player.inventory.boots 87 | e.player.inventory.boots = e.player.inventory.itemInMainHand 88 | e.player.inventory.setItemInMainHand(l) 89 | }, 90 | "RING" to { e -> 91 | val l = e.player.inventory.getItem(9) 92 | e.player.inventory.setItem(9, e.player.inventory.itemInMainHand) 93 | e.player.inventory.setItemInMainHand(l) 94 | }, 95 | "BRACELET" to { e -> 96 | val l = e.player.inventory.getItem(11) 97 | e.player.inventory.setItem(11, e.player.inventory.itemInMainHand) 98 | e.player.inventory.setItemInMainHand(l) 99 | }, 100 | "NECKLACE" to { e -> 101 | val l = e.player.inventory.getItem(12) 102 | e.player.inventory.setItem(12, e.player.inventory.itemInMainHand) 103 | e.player.inventory.setItemInMainHand(l) 104 | } 105 | ) 106 | 107 | val lcEvents = hashMapOf Unit>() 108 | } 109 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/ProjectileHitListener.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import org.bukkit.entity.Arrow 4 | import org.bukkit.entity.Mob 5 | import org.bukkit.entity.Player 6 | import org.bukkit.event.EventHandler 7 | import org.bukkit.event.EventPriority 8 | import org.bukkit.event.entity.ProjectileHitEvent 9 | 10 | class ProjectileHitListener : BaseListener() { 11 | @EventHandler(priority = EventPriority.HIGHEST) 12 | fun onProjectileHit(e: ProjectileHitEvent) { 13 | val proj = e.entity 14 | 15 | if ("mob_projectile" in proj.scoreboardTags) 16 | proj.remove() 17 | 18 | if (proj.shooter !is Player) 19 | return 20 | 21 | for (tag in proj.scoreboardTags) { 22 | tags[tag]?.let { 23 | if (e.hitEntity is Mob) (e.hitEntity as Mob).noDamageTicks = 0 24 | if (proj is Arrow) proj.damage = 0.0 25 | it(e) 26 | } 27 | } 28 | } 29 | 30 | companion object { 31 | val tags = hashMapOf Unit>() 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/listeners/ScriptAPIListeners.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.listeners 2 | 3 | import com.wynnlab.events.DamageEvent 4 | import com.wynnlab.events.HealEvent 5 | import com.wynnlab.spells.damage 6 | import com.wynnlab.spells.heal 7 | import org.bukkit.entity.Player 8 | import org.bukkit.event.EventHandler 9 | 10 | class ScriptAPIListeners : BaseListener() { 11 | @EventHandler 12 | fun onDamage(e: DamageEvent) { 13 | if (e.source !is Player) 14 | return 15 | 16 | damage(e.source as Player, e.target, e.melee, e.multiplier, *e.conversion) 17 | } 18 | 19 | @EventHandler 20 | fun onHeal(e: HealEvent) { 21 | heal(e.target, e.amount) 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/localization/Language.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.localization 2 | 3 | import com.wynnlab.NL_REGEX 4 | import com.wynnlab.wynnlab 5 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer 6 | import org.bukkit.configuration.file.YamlConfiguration 7 | import java.io.File 8 | import java.util.* 9 | import java.util.logging.Level 10 | 11 | class Language(private val locale: Locale) { 12 | private val config = YamlConfiguration() 13 | 14 | init { 15 | val file = File(languageFolder, "${locale.toLanguageTag().replace('-', '_')}.yml") 16 | config.load(file) 17 | } 18 | 19 | init { 20 | languages[locale] = this 21 | if (language_fallbacks[locale.language] == null) language_fallbacks[locale.language] = locale 22 | } 23 | 24 | fun getMessage(key: String, vararg format_args: Any?) = LegacyComponentSerializer.legacy('&').deserialize(getMessageAsString(key, *format_args)) 25 | 26 | fun getMessageMultiline(key: String, vararg format_args: Any?) = getMessageAsString(key, *format_args).split(NL_REGEX).map { 27 | LegacyComponentSerializer.legacy('&').deserialize(it) 28 | } 29 | 30 | fun getMessageAsString(key: String, vararg format_args: Any?) = getMessageOrNull(key, format_args) ?: 31 | Language[language_fallbacks[locale.language]!!].getMessageOrNull(key, format_args) ?: 32 | en_us.getMessageOrNull(key, format_args) ?: "&4Nls: &r$key" 33 | 34 | 35 | fun getRandomMessage(key: String, vararg format_args: Any?) = LegacyComponentSerializer.legacy('&').deserialize(getRandomMessageAsString(key, *format_args)) 36 | 37 | fun getRandomMessageAsString(key: String, vararg format_args: Any?): String = getRandomMessageOrNull(key, format_args) ?: 38 | Language[language_fallbacks[locale.language]!!].getMessageOrNull(key, format_args) ?: 39 | en_us.getRandomMessageOrNull(key, format_args) ?: "&4Nls: &r$key" 40 | 41 | 42 | private fun getRandomMessageOrNull(key: String, format_args: Array) = config.getList(key)?.let { 43 | it.randomOrNull()?.let { r -> String.format(r as String, *format_args) } 44 | } 45 | 46 | private fun getMessageOrNull(key: String, format_args: Array): String? = config.getString(key)?.let { 47 | String.format(it, *format_args) 48 | } 49 | 50 | companion object { 51 | private val languages = hashMapOf() 52 | private val language_fallbacks = hashMapOf() 53 | 54 | val en_us = Language(Locale.US) 55 | operator fun get(locale: Locale) = languages[locale] ?: 56 | languages[language_fallbacks[locale.language]] ?: 57 | en_us 58 | } 59 | } 60 | 61 | private val languageFolder by lazy { File(wynnlab.dataFolder, "lang") } 62 | 63 | fun loadLanguages() { 64 | for (f in languageFolder.list() ?: return) { 65 | val name = f.substring(0, f.length - 4) 66 | wynnlab.logger.log(Level.INFO, "Loading language $name ...") 67 | try { 68 | if (name == "en_US") Language[Locale.US] 69 | else Language(Locale.US) 70 | } catch (e: Exception) { 71 | e.printStackTrace() 72 | continue 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/locations/Location.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.locations 2 | 3 | import com.wynnlab.WL_COLOR 4 | import com.wynnlab.api.getLocalizedText 5 | import com.wynnlab.api.getLocalizedTextMultiline 6 | import com.wynnlab.util.BaseSerializable 7 | import com.wynnlab.util.ConfigurationDeserializable 8 | import net.kyori.adventure.text.Component 9 | import net.kyori.adventure.text.format.NamedTextColor 10 | import net.kyori.adventure.text.format.TextDecoration 11 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer 12 | import org.bukkit.Sound 13 | import org.bukkit.SoundCategory 14 | import org.bukkit.entity.Player 15 | import org.bukkit.util.BoundingBox 16 | import java.util.* 17 | import org.bukkit.Location as _Location 18 | 19 | class Location( 20 | val name: String, 21 | private val pos1: _Location, 22 | private val pos2: _Location, 23 | private val announce: Boolean, 24 | private val subtitle: String?, 25 | private val lore: String?, 26 | ) : BaseSerializable() { 27 | 28 | override val deserializer = Companion 29 | 30 | private val discovered = mutableListOf() 31 | 32 | val bossBarTitle = "§3$name" 33 | 34 | fun announce(player: Player, entering: Boolean = true): Boolean { 35 | if (!announce) return false 36 | 37 | player.sendTitle(LegacyComponentSerializer.legacy('§').serialize(player.getLocalizedText(when { 38 | player.uniqueId !in discovered -> "titles.location.discover" 39 | entering -> "titles.location.enter" 40 | else -> "titles.location.leave" 41 | }, name)), 42 | subtitle?.let { LegacyComponentSerializer.legacy('§').serialize(player.getLocalizedText(it)) }, 43 | 10, 30, 10) 44 | 45 | return true 46 | } 47 | 48 | fun discover(player: Player) { 49 | if (player.uniqueId !in discovered) { 50 | discovered.add(player.uniqueId) 51 | 52 | player.playSound(player.location, Sound.ENTITY_PLAYER_LEVELUP, SoundCategory.MASTER, 1f, 1f) 53 | 54 | player.sendMessage("§0") 55 | 56 | //player.sendMessage(" ${player.getLocalizedText("titles.location.discover", name)}") 57 | player.sendMessage(Component.text(" ") 58 | .append(player.getLocalizedText("titles.location.discover", name))) 59 | //subtitle?.let { player.sendMessage(" §2§o${player.getLocalizedText(it)}") } 60 | subtitle?.let { 61 | player.sendMessage(Component.text(" ") 62 | .append(player.getLocalizedText(it) 63 | .color(NamedTextColor.DARK_GREEN) 64 | .decorate(TextDecoration.ITALIC))) 65 | } 66 | 67 | lore?.let { l -> 68 | player.sendMessage("§0") 69 | 70 | player.getLocalizedTextMultiline(l).forEach { 71 | player.sendMessage(Component.text(" ") 72 | .append(it.color(WL_COLOR))) 73 | } 74 | } 75 | 76 | player.sendMessage("§0") 77 | } 78 | } 79 | 80 | operator fun contains(l: _Location) = bb.contains(l.x, l.y, l.z) 81 | 82 | private val bb: BoundingBox = BoundingBox(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z) 83 | 84 | override fun serialize(): Map { 85 | val map = mutableMapOf() 86 | 87 | map["name"] = name 88 | map["pos1"] = pos1 89 | map["pos2"] = pos2 90 | map["announce"] = announce 91 | subtitle?.let { map["subtitle"] = it } 92 | 93 | return map 94 | } 95 | 96 | companion object : ConfigurationDeserializable { 97 | @JvmStatic 98 | override fun deserialize(map: Map): Location { 99 | val name = map["name"] as String 100 | val pos1 = map["pos1"] as _Location 101 | val pos2 = map["pos2"] as _Location 102 | val announce = (map["announce"] ?: false) as Boolean 103 | val subtitle = map["subtitle"] as String? 104 | val lore = map["lore"] as String? 105 | 106 | return Location(name, pos1, pos2, announce, subtitle, lore) 107 | } 108 | } 109 | 110 | override fun toString(): String { 111 | return "Location(name='$name', pos1=$pos1, pos2=$pos2, announce=$announce, subtitle=$subtitle)" 112 | } 113 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/locations/locations.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.locations 2 | 3 | import com.wynnlab.api.hasScoreboardTag 4 | import com.wynnlab.wynnlab 5 | import org.bukkit.Bukkit 6 | import org.bukkit.NamespacedKey 7 | import org.bukkit.boss.BarColor 8 | import org.bukkit.boss.BarStyle 9 | import org.bukkit.boss.KeyedBossBar 10 | import org.bukkit.configuration.file.YamlConfiguration 11 | import org.bukkit.entity.Player 12 | import java.io.File 13 | 14 | @Suppress("unchecked_cast") 15 | fun loadLocations() { 16 | val file = File(wynnlab.dataFolder, "locations.yml") 17 | if (!file.exists()) return 18 | 19 | val config = YamlConfiguration() 20 | config.load(file) 21 | 22 | val ls = try { 23 | config.getList("locations") as? List ?: return 24 | } catch (e: IllegalArgumentException) { return } 25 | 26 | ls.forEach { if (it != null) locations.add(it) } 27 | 28 | Bukkit.broadcastMessage(locations.toString()) 29 | } 30 | 31 | fun testLocations(player: Player): List = locations.filter { player.location in it } 32 | 33 | fun Player.updateLocations() { 34 | if (locations.isEmpty()) return 35 | 36 | val labb = playerLocations[this] 37 | val before = labb?.locations 38 | val now = testLocations(this) 39 | val bb = labb?.bb ?: createLBB(this) 40 | val entered = before?.let { b -> now.filter { it !in b } } ?: now 41 | 42 | var announced = false 43 | for (l in entered) { 44 | if (!announced && l.announce(this)) 45 | announced = true 46 | 47 | l.discover(this) 48 | 49 | bb.setTitle(l.bossBarTitle) 50 | } 51 | 52 | if (!announced) { 53 | val left = before?.let { b -> b.filter { it !in now } } ?: emptyList() 54 | 55 | for (l in left) { 56 | if (!announced && l.announce(this, false)) 57 | announced = true 58 | } 59 | } 60 | 61 | if (now.isEmpty()) { 62 | if (hasScoreboardTag("ffa")) { 63 | bb.setTitle("§cFFA §8- §6Kills: §b0 §6Deaths: §b0 §6K/D: §b0") 64 | } else { 65 | bb.setTitle("§c") 66 | } 67 | } 68 | 69 | playerLocations[this] = LocationsAndBB(now, bb) 70 | } 71 | 72 | private fun createLBB(player: Player): KeyedBossBar = 73 | Bukkit.createBossBar(NamespacedKey(wynnlab, "locations_${player.name}"), "Title", BarColor.BLUE, BarStyle.SOLID).apply { 74 | isVisible = true 75 | progress = 1.0 76 | 77 | addPlayer(player) 78 | } 79 | 80 | val locations: MutableList = mutableListOf() 81 | 82 | class LocationsAndBB( 83 | val locations: List, 84 | val bb: KeyedBossBar, 85 | ) 86 | 87 | val playerLocations: MutableMap = mutableMapOf() 88 | 89 | fun removePlayerLocations(player: Player) { 90 | val labb = playerLocations.remove(player) ?: return 91 | labb.bb.run { 92 | removeAll() 93 | Bukkit.removeBossBar(key) 94 | } 95 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/pvp/FFA.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.pvp 2 | 3 | import com.wynnlab.api.sendWynnMessage 4 | import org.bukkit.Bukkit 5 | import org.bukkit.entity.Player 6 | 7 | 8 | object FFA { 9 | val players = mutableListOf() 10 | 11 | fun join(player: Player) { 12 | val w = Bukkit.getWorld("FFA") ?: run { 13 | player.sendMessage("§cFFA is currently unavailable") 14 | return 15 | } 16 | 17 | player.teleport(w.spawnLocation) 18 | 19 | val console = Bukkit.getServer().consoleSender 20 | val command = "execute as ${player.name} at @s run spreadplayers 0 0 25 50 false @s" 21 | Bukkit.dispatchCommand(console, command) 22 | } 23 | 24 | fun onJoinWorld(player: Player) { 25 | player.addScoreboardTag("pvp") 26 | player.addScoreboardTag("ffa") 27 | 28 | players.add(player) 29 | 30 | player.sendWynnMessage("messages.ffa.welcome") 31 | player.sendWynnMessage("messages.ffa.stats") 32 | player.sendWynnMessage("messages.ffa.leave") 33 | 34 | players.forEach { 35 | it.sendMessage("§8[§cFFA§8] §a>> §r${player.playerListName}") 36 | } 37 | } 38 | 39 | fun onLeaveWorld(player: Player) { 40 | player.removeScoreboardTag("pvp") 41 | player.removeScoreboardTag("ffa") 42 | 43 | players.remove(player) 44 | 45 | players.forEach { 46 | it.sendMessage("§8[§cFFA§8] §4<< §r${player.playerListName}") 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/scoreboard/ConfiguredSidebar.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.scoreboard 2 | 3 | import org.bukkit.entity.Player 4 | 5 | interface ConfiguredSidebar { 6 | fun apply(player: Player, sidebar: Sidebar) 7 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/scoreboard/PartySidebar.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.scoreboard 2 | 3 | import com.wynnlab.COLOR_DARKER_GRAY 4 | import com.wynnlab.COLOR_PARTY 5 | import com.wynnlab.essentials.Party 6 | import net.kyori.adventure.text.Component 7 | import org.bukkit.entity.Player 8 | 9 | object PartySidebar : ConfiguredSidebar { 10 | override fun apply(player: Player, sidebar: Sidebar) { 11 | val party = Party.members[player]!! 12 | 13 | sidebar.setForUpdate(1, pos(player)) 14 | 15 | sidebar.setForUpdate(3, Component.text("Party: ", COLOR_PARTY) 16 | .append(Component.text("(${party.members.size})", COLOR_DARKER_GRAY))) 17 | 18 | var i = 4 19 | party.getSbTexts().forEach { 20 | sidebar.setForUpdate(i++, it) 21 | } 22 | 23 | sidebar.displayLines = i - 1 24 | 25 | while (i < 16) 26 | sidebar.clearForUpdate(i++) 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/scoreboard/Sidebar.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.scoreboard 2 | 3 | import net.kyori.adventure.text.Component 4 | import org.bukkit.Bukkit 5 | import org.bukkit.entity.Player 6 | import org.bukkit.scoreboard.DisplaySlot 7 | import org.bukkit.scoreboard.Team 8 | 9 | class Sidebar(title: Component) { 10 | private val sb = Bukkit.getScoreboardManager().newScoreboard 11 | private val o = sb.registerNewObjective("o", "dummy", title) 12 | init { 13 | o.displaySlot = DisplaySlot.SIDEBAR 14 | } 15 | 16 | var title = title 17 | set(value) { 18 | o.displayName(value) 19 | field = value 20 | } 21 | 22 | private val lines = Array(16) { null } 23 | private val setLines = BooleanArray(16) 24 | 25 | var displayLines = 0 26 | 27 | fun show(player: Player) { 28 | player.scoreboard = sb 29 | } 30 | 31 | /** 32 | * line is top down 0-16 33 | */ 34 | @Throws(ArrayIndexOutOfBoundsException::class) 35 | fun set(line: Int, text: Component) { 36 | setForUpdate(line, text) 37 | 38 | fillEmptyLines() 39 | } 40 | 41 | /** 42 | * line is top down 0-16 43 | */ 44 | @Throws(ArrayIndexOutOfBoundsException::class) 45 | fun setForUpdate(line: Int, text: Component) { 46 | if (displayLines <= line) displayLines = line + 1 47 | lines[line] = text 48 | setLines[line] = true 49 | 50 | setScore(16 - line, text) 51 | } 52 | 53 | /** 54 | * line is top down 0-16 55 | */ 56 | @Throws(ArrayIndexOutOfBoundsException::class) 57 | fun get(line: Int) = lines[line] 58 | 59 | /** 60 | * line is top down 0-16 61 | */ 62 | @Throws(ArrayIndexOutOfBoundsException::class) 63 | fun clear(line: Int) { 64 | clearForUpdate(line) 65 | 66 | setDisplayLines() 67 | fillEmptyLines() 68 | } 69 | 70 | fun clearForUpdate(line: Int) { 71 | lines[line] = null 72 | setLines[line] = false 73 | } 74 | 75 | fun clear() { 76 | for (i in 0..15) { 77 | lines[i] = null 78 | setLines[i] = false 79 | removeScore(i) 80 | } 81 | displayLines = 0 82 | } 83 | 84 | fun update() = fillEmptyLines() 85 | 86 | private fun setScore(score: Int, text: Component) { 87 | val t = getTeam(score) 88 | t.prefix(text) 89 | o.getScore(colorInt(score)).score = score 90 | } 91 | 92 | private fun removeScore(score: Int) { 93 | val name = colorInt(score) 94 | if (o.getScore(name).isScoreSet) 95 | return 96 | sb.resetScores(name) 97 | } 98 | 99 | private fun getTeam(score: Int): Team { 100 | val name = colorInt(score) 101 | return sb.getEntryTeam(name) ?: sb.registerNewTeam(score.toString()).apply { 102 | addEntry(name) 103 | } 104 | } 105 | 106 | private fun setDisplayLines() { 107 | var i = -1 108 | var last = i 109 | for (b in setLines) { 110 | if (!b) 111 | last = i 112 | 113 | ++i 114 | } 115 | displayLines = last + 1 116 | } 117 | 118 | private fun fillEmptyLines() { 119 | var i = -1 120 | for (b in setLines) { 121 | ++i 122 | if (i >= displayLines) 123 | removeScore(16 - i) 124 | else if (!b) 125 | setScore(16 - i, Component.empty()) 126 | } 127 | } 128 | 129 | private fun colorInt(int: Int) = "§${(int-1).toString(0x10)}" 130 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/scoreboard/StandardSidebar.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.scoreboard 2 | 3 | import com.wynnlab.COLOR_GOLD 4 | import net.kyori.adventure.text.Component 5 | import org.bukkit.entity.Player 6 | 7 | object StandardSidebar : ConfiguredSidebar { 8 | override fun apply(player: Player, sidebar: Sidebar) { 9 | sidebar.setForUpdate(1, quests(player)) 10 | 11 | sidebar.setForUpdate(3, pos(player)) 12 | 13 | sidebar.setForUpdate(5, Component.text("5 ✯✯✯✯✯", COLOR_GOLD)) 14 | 15 | sidebar.clearForUpdate(4) 16 | var i = 6 17 | while (i < 16) 18 | sidebar.clearForUpdate(i++) 19 | sidebar.displayLines = 5 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/scoreboard/elements.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.scoreboard 2 | 3 | import com.wynnlab.* 4 | import com.wynnlab.util.yawToDir 5 | import net.kyori.adventure.text.Component 6 | import org.bukkit.entity.Player 7 | 8 | fun quests(@Suppress("unused") player: Player) = Component.text("Quests: ", COLOR_QUESTS) 9 | .append(Component.text("0/0", COLOR_QUESTS_COUNT)) 10 | .append(Component.text(" [", COLOR_QUESTS_BRACKET)) 11 | .append(Component.text("100%", COLOR_QUESTS_COUNT)) 12 | .append(Component.text("]", COLOR_QUESTS_BRACKET)) 13 | 14 | fun pos(player: Player) = Component.text("Pos: ", COLOR_ORANGE) 15 | .append(Component.text("${player.location.x.toInt()} ", COLOR_DES_RED)) 16 | .append(Component.text("${player.location.y.toInt()} ", COLOR_DES_GREEN)) 17 | .append(Component.text("${player.location.z.toInt()} ", COLOR_DES_BLUE)) 18 | .append(Component.text("[", COLOR_DARKER_GRAY)) 19 | .append(Component.text(yawToDir(player.eyeLocation.yaw), COLOR_ORANGE)) 20 | .append(Component.text("]", COLOR_DARKER_GRAY)) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/spells/PlayerSpell.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.spells 2 | 3 | import com.wynnlab.api.isCloneClass 4 | import com.wynnlab.currentClassLoadFolder 5 | import com.wynnlab.spellOrdinal 6 | import com.wynnlab.util.BaseSerializable 7 | import com.wynnlab.util.ConfigurationDeserializable 8 | import com.wynnlab.util.TickRunnable 9 | import com.wynnlab.util.prepareScript 10 | import com.wynnlab.wynnscript.CompiledWynnScript 11 | import com.wynnlab.wynnscript.NoSuchFunctionException 12 | import com.wynnlab.wynnscript.WynnScript 13 | import org.bukkit.entity.Player 14 | import java.io.File 15 | import java.io.FileReader 16 | 17 | data class PlayerSpell( 18 | override val cost: Int, 19 | override val maxTick: Int, 20 | val script: CompiledWynnScript, 21 | override val ordinal: Int 22 | ) : Spell, BaseSerializable() { 23 | init { 24 | prepareScript(script) 25 | } 26 | 27 | override fun invoke(player: Player, vararg args: Any?) { 28 | script.resetData() 29 | 30 | val spellPlayer = SpellPlayer(player) 31 | val clone = player.isCloneClass 32 | 33 | val runnable = object : TickRunnable() { 34 | override fun init() { 35 | script.setData("task", this) 36 | try { 37 | script("init", spellPlayer, clone, *args) 38 | } catch (_: NoSuchFunctionException) { 39 | } catch (e: Throwable) { 40 | reportError(e, "§cError at initializing script", player) 41 | } 42 | } 43 | 44 | override fun tick() { 45 | try { 46 | script("tick", t, spellPlayer, clone) 47 | } catch (e: Throwable) { 48 | reportError(e, "§cError at executing script (tick $t)", player) 49 | } 50 | } 51 | } 52 | 53 | runnable.schedule() 54 | } 55 | 56 | override fun serialize(): MutableMap { 57 | val out = LinkedHashMap() 58 | 59 | out["cost"] = cost 60 | out["maxTick"] = maxTick 61 | 62 | return out 63 | } 64 | 65 | override val deserializer = Companion 66 | 67 | companion object : ConfigurationDeserializable { 68 | @JvmStatic 69 | @Suppress("unused") 70 | override fun deserialize(map: Map): PlayerSpell { 71 | val cost = (map["cost"] as Number? ?: 0).toInt() 72 | val maxTick = (map["maxTick"] as Number).toInt() 73 | 74 | val scriptFile = File(currentClassLoadFolder, map["script"] as String) 75 | 76 | val script = FileReader(scriptFile).use { reader -> 77 | WynnScript(reader) 78 | }.compile() 79 | 80 | return PlayerSpell(cost, maxTick, script, spellOrdinal++) 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/spells/Spell.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.spells 2 | 3 | import com.wynnlab.api.getId 4 | import com.wynnlab.api.isCloneClass 5 | import com.wynnlab.currentClassLoadFolder 6 | import com.wynnlab.python 7 | import com.wynnlab.spellOrdinal 8 | import com.wynnlab.util.BaseSerializable 9 | import com.wynnlab.util.ConfigurationDeserializable 10 | import net.kyori.adventure.text.Component 11 | import net.kyori.adventure.text.event.ClickEvent 12 | import net.kyori.adventure.text.event.HoverEvent 13 | import net.kyori.adventure.text.format.NamedTextColor 14 | import org.bukkit.configuration.serialization.ConfigurationSerializable 15 | import org.bukkit.entity.Player 16 | import org.python.core.Py 17 | import org.python.core.PyBoolean 18 | import org.python.core.PyInteger 19 | import org.python.core.PyType 20 | import java.io.File 21 | import java.io.FileReader 22 | 23 | interface Spell : ConfigurationSerializable { 24 | val cost: Int 25 | val maxTick: Int 26 | val ordinal: Int 27 | 28 | fun cast(player: Player, vararg args: Any?) { 29 | invoke(player, args) 30 | } 31 | 32 | fun invoke(player: Player, args: Array) 33 | } 34 | 35 | @Suppress("unchecked_cast") 36 | fun reportError(e: Throwable, msg: String, player: Player) { 37 | player.sendMessage("§4=====================") 38 | player.sendMessage(msg) 39 | player.sendMessage("§bPlease immediately submit a bug report on GitHub!") 40 | val stackTrace = e.stackTraceToString() 41 | player.sendMessage( 42 | Component.text("Error: (${e::class.qualifiedName}) $e ") 43 | .color(NamedTextColor.DARK_RED) 44 | .append( 45 | Component.text("[Stack trace]") 46 | .color(NamedTextColor.YELLOW) 47 | .hoverEvent { HoverEvent.showText(Component.text("Copy")) as HoverEvent } 48 | .clickEvent(ClickEvent.copyToClipboard(e.stackTraceToString())) 49 | ) 50 | ) 51 | player.sendMessage("§4=====================") 52 | } 53 | 54 | @Deprecated("Use WynnScript") 55 | data class PythonSpell ( 56 | override val cost: Int, 57 | override val maxTick: Int, 58 | val pythonClass: PyType, 59 | override val ordinal: Int 60 | ) : Spell, BaseSerializable() { 61 | 62 | override fun invoke(player: Player, vararg args: Any?) { 63 | val instance = try { 64 | pythonClass.__call__(Array(args.size) { i -> Py.java2py(args[i]) }) 65 | } catch (e: Throwable) { 66 | reportError(e, "§cError instantiating §nPython §cSpell ($ordinal)", player) 67 | return 68 | } 69 | try { 70 | instance.__setattr__("player", Py.java2py(player)) 71 | instance.__setattr__("clone", PyBoolean(player.isCloneClass)) 72 | instance.__setattr__("maxTick", PyInteger(maxTick)) 73 | } catch (e: Throwable) { 74 | reportError(e, "§cError setting attributes for §nPython §cSpell ($ordinal)", player) 75 | return 76 | } 77 | 78 | try { 79 | instance("schedule") 80 | } catch (e: Throwable) { 81 | reportError(e, "§cError executing §nPython §cSpell ($ordinal)", player) 82 | try { 83 | instance("cancel") 84 | } catch (e: Throwable) { 85 | reportError(e, "§c§lVery critical§c error instantiating §nPython §cSpell ($ordinal)", player) 86 | } 87 | } 88 | } 89 | 90 | override fun serialize(): MutableMap { 91 | val out = LinkedHashMap() 92 | 93 | out["cost"] = cost 94 | out["maxTick"] = maxTick 95 | 96 | return out 97 | } 98 | 99 | override val deserializer = Companion 100 | 101 | companion object : ConfigurationDeserializable { 102 | @JvmStatic 103 | @Suppress("unused") 104 | override fun deserialize(map: Map): PythonSpell { 105 | val cost = (map["cost"] as Number? ?: 0).toInt() 106 | val maxTick = (map["maxTick"] as Number).toInt() 107 | 108 | val scriptFile = File(currentClassLoadFolder, map["script"] as String) 109 | 110 | val script = FileReader(scriptFile).use { reader -> 111 | python.compile(reader) 112 | } 113 | python.exec(script) 114 | val pythonClass: PyType = python.get("Spell") as PyType //TODO: name 115 | 116 | return PythonSpell(cost, maxTick, pythonClass, spellOrdinal++) 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/spells/SpellPlayer.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.spells 2 | 3 | import org.bukkit.Location 4 | import org.bukkit.Particle 5 | import org.bukkit.Sound 6 | import org.bukkit.entity.Entity 7 | import org.bukkit.entity.LivingEntity 8 | import org.bukkit.entity.Mob 9 | import org.bukkit.entity.Player 10 | import org.bukkit.util.Vector 11 | 12 | class SpellPlayer( 13 | val player: Player 14 | ) { 15 | fun getLocation() = player.location.clone() 16 | fun getEyeLocation() = player.eyeLocation.clone() 17 | fun getDirection() = player.eyeLocation.direction.clone() 18 | 19 | fun damage(e: LivingEntity, melee: Boolean, multiplier: Double) = 20 | this.damage(e, melee, multiplier, *doubleArrayOf()) 21 | 22 | fun damage(e: LivingEntity, melee: Boolean, multiplier: Double, vararg conversion: Double) = 23 | damage(player, e, melee, multiplier, *conversion) 24 | 25 | @Suppress("unused") 26 | fun damageBy(e: LivingEntity, melee: Boolean, multiplier: Double) = 27 | this.damageBy(e, melee, multiplier, *doubleArrayOf()) 28 | 29 | @Suppress("unused") 30 | fun damageBy(e: LivingEntity, melee: Boolean, multiplier: Double, vararg conversion: Double) = 31 | damageBy(player, e, melee, multiplier, *conversion) 32 | 33 | fun heal(amount: Double) = 34 | heal(player, amount) 35 | 36 | fun knockback(target: Entity, direction: Vector, amount: Double) = 37 | com.wynnlab.spells.knockback(target, direction, amount) 38 | 39 | @Suppress("unused") 40 | fun knockback(target: Entity, amount: Double) = 41 | knockbackFromPlayer(target, player, amount) 42 | 43 | fun particle(location: Location, particle: Particle, count: Int, offX: Double, offY: Double, offZ: Double, speed: Double) = 44 | particle(player, location, particle, count, offX, offY, offZ, speed) 45 | 46 | fun particle(location: Location, particle: Particle, count: Int, offX: Double, offY: Double, offZ: Double, speed: Double, data: T?) = 47 | particle(player, location, particle, count, offX, offY, offZ, speed, data) 48 | 49 | fun sound(sound: Sound, volume: Float, pitch: Float) = 50 | sound(player, sound, volume, pitch) 51 | 52 | fun sound(location: Location, sound: Sound, volume: Float, pitch: Float) = 53 | sound(player, location, sound, volume, pitch) 54 | 55 | fun nearbyMobs(x: Double, y: Double, z: Double) = 56 | nearbyMobs(player, x, y, z) 57 | 58 | @Suppress("unchecked_cast") 59 | fun nearbyMobs(location: Location, x: Double, y: Double, z: Double): Collection = 60 | nearbyMobs(player, location, x, y, z) 61 | 62 | @Suppress("unused") 63 | fun nearbyMobsAndTag(location: Location, x: Double, y: Double, z: Double, tag: String): Collection = 64 | nearbyMobsAndTag(player, location, x, y, z, tag) 65 | 66 | fun castSpell(clazz: String, index: Int, vararg args: Any?) = 67 | castSpell(player, clazz, index, *args) 68 | 69 | @Suppress("unused") 70 | fun message(message: List) = player.sendMessage(message.joinToString("")) 71 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/BaseSerializable.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.WynnClass 4 | import com.wynnlab.entities.WynnMob 5 | import com.wynnlab.locations.Location 6 | import com.wynnlab.spells.MobSpell 7 | import com.wynnlab.spells.PlayerSpell 8 | import com.wynnlab.spells.PythonSpell 9 | import com.wynnlab.spells.Spell 10 | import org.bukkit.configuration.serialization.ConfigurationSerializable 11 | import org.bukkit.configuration.serialization.ConfigurationSerialization 12 | 13 | abstract class BaseSerializable> : ConfigurationSerializable { 14 | 15 | abstract val deserializer: ConfigurationDeserializable 16 | 17 | abstract override fun serialize(): Map 18 | } 19 | 20 | interface ConfigurationDeserializable { 21 | fun deserialize(map: Map): T 22 | } 23 | 24 | fun registerSerializers() { 25 | registerSerializer() 26 | registerSerializer() 27 | registerSerializer() 28 | registerSerializer() 29 | registerSerializer() 30 | registerSerializer() 31 | registerSerializer() 32 | registerSerializer() 33 | } 34 | 35 | private inline fun registerSerializer() = 36 | ConfigurationSerialization.registerClass(T::class.java) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/Deferred.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.Bukkit 5 | 6 | class Deferred( 7 | val task: () -> T 8 | ) { 9 | inline fun execute(crossinline then: (T) -> Unit) { 10 | Bukkit.getScheduler().runTaskAsynchronously(wynnlab, Runnable { 11 | then(task()) 12 | }) 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/LocationIterator.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import org.bukkit.Location 4 | 5 | class LocationIterator( 6 | val start: Location, 7 | val end: Location, 8 | val step: Double 9 | ) : Iterable { 10 | private val d = end.clone().subtract(start).toVector().normalize().multiply(step) 11 | 12 | override operator fun iterator(): Iterator = 13 | object : Iterator { 14 | private var l = start 15 | 16 | private var iStep = 0.0 17 | private val dist: Double = end.distance(start) 18 | 19 | override operator fun hasNext(): Boolean { 20 | return iStep <= dist 21 | } 22 | 23 | override operator fun next(): Location { 24 | val r = l 25 | l.add(d) 26 | iStep += step 27 | return r 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/OnlyAsync.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | /** 4 | * A function/class that should only be executed in async environment 5 | */ 6 | @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) 7 | @Retention(AnnotationRetention.SOURCE) 8 | annotation class OnlyAsync -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/Optional.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | sealed class Optional { 4 | class Some(val value: T) : Optional() { 5 | override fun toString(): String = value.toString() 6 | } 7 | 8 | object None : Optional() { 9 | override fun toString(): String = "NONE" 10 | } 11 | 12 | @Suppress("unchecked_cast") 13 | inline fun ifSome(block: (T) -> R): Optional = when (this) { 14 | is Some -> Some(block(value)) 15 | is None -> None as Optional 16 | } 17 | 18 | inline fun ifSomeRun(block: (T) -> Unit) { 19 | if (this is None) 20 | return 21 | block((this as Some).value) 22 | } 23 | 24 | inline fun either(ifSome: (T) -> R, ifNone: () -> R): R = when (this) { 25 | is Some -> ifSome(value) 26 | is None -> ifNone() 27 | } 28 | 29 | inline infix fun or(block: () -> T): T = when (this) { 30 | is Some -> value 31 | is None -> block() 32 | } 33 | 34 | companion object { 35 | @Suppress("unchecked_cast") 36 | operator fun invoke(nullable: T?): Optional = nullable?.let { Some(it) } ?: None as Optional 37 | } 38 | } 39 | 40 | fun T?.optional() = Optional(this) 41 | 42 | @Suppress("unchecked_cast") 43 | fun Any?.optionalAs() = Optional(this as T?) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/RefreshRunnable.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.api.getInt 4 | import com.wynnlab.api.remove 5 | import com.wynnlab.api.setInt 6 | import com.wynnlab.wynnlab 7 | import org.bukkit.Bukkit 8 | import org.bukkit.persistence.PersistentDataContainer 9 | 10 | /** 11 | * A delayed runnable which delay can be refreshed to delay it further 12 | */ 13 | abstract class RefreshRunnable(private val data: PersistentDataContainer, private val id: String) : Runnable { 14 | final override fun run() { 15 | val delay = data.getInt("RR_$id")!! 16 | if (delay > 0) 17 | data.setInt("RR_$id", delay - 1) 18 | if (delay <= 1) { 19 | task() 20 | data.remove("RR_$id") 21 | } 22 | } 23 | 24 | abstract fun task() 25 | 26 | fun schedule(delay: Long) { 27 | Bukkit.getScheduler().runTaskLater(wynnlab, this, delay) 28 | data.setInt("RR_$id", (data.getInt("RR_$id") ?: 0) + 1) 29 | } 30 | 31 | companion object { 32 | inline operator fun invoke(data: PersistentDataContainer, id: String, crossinline task: () -> Unit) = 33 | object : RefreshRunnable(data, id) { 34 | override fun task() { 35 | task() 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/TickRunnable.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.Bukkit 5 | 6 | abstract class TickRunnable : Runnable { 7 | var t = 0 8 | 9 | private var _taskId = -1 10 | val taskId get() = _taskId 11 | 12 | private var scheduled = false 13 | var maxTick = 0 14 | 15 | open fun init() {} 16 | 17 | abstract fun tick() 18 | 19 | fun delay() { 20 | --t 21 | } 22 | 23 | fun cancel() { 24 | Bukkit.getScheduler().cancelTask(_taskId) 25 | } 26 | 27 | final override fun run() { 28 | if (scheduled) { 29 | if (t <= maxTick) { 30 | try { 31 | tick() 32 | } catch (e: Throwable) { 33 | cancel() 34 | throw e 35 | } 36 | ++t 37 | } else { 38 | cancel() 39 | } 40 | } 41 | } 42 | 43 | fun schedule() { 44 | init() 45 | _taskId = Bukkit.getScheduler().runTaskTimer(wynnlab, this, 0L, 1L).taskId 46 | scheduled = true 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/WynnScript utils.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.spells.SpellUtils 4 | import com.wynnlab.wynnscript.CompiledWynnScript 5 | import com.wynnlab.wynnscript.Invocable 6 | import org.bukkit.Location 7 | import org.bukkit.Material 8 | import org.bukkit.Particle 9 | import org.bukkit.Sound 10 | 11 | fun prepareScript(script: CompiledWynnScript) { 12 | script["print"] = Invocable { _, args -> if (args.size != 1) throw IllegalArgumentException() else 13 | println(args[0]) 14 | } 15 | 16 | script["array"] = Invocable { _, args -> args } 17 | script["list"] = Invocable { _, args -> mutableListOf(*args) } 18 | script["set"] = Invocable { _, args -> mutableSetOf(*args) } 19 | script["map"] = Invocable { _, args -> if (args.isNotEmpty()) throw IllegalArgumentException() else 20 | mutableMapOf() 21 | } 22 | 23 | script["SpellUtils"] = SpellUtils 24 | 25 | script["locations"] = Invocable { _, args -> if (args.size != 3) throw IllegalArgumentException() else 26 | LocationIterator(args[0] as Location, args[1] as Location, (args[2] as Number).toDouble()) 27 | } 28 | 29 | script["Material"] = Material::class.java 30 | script["Particle"] = Particle::class.java 31 | script["Sound"] = Sound::class.java 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/adventure utils.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import net.kyori.adventure.text.Component 4 | import net.kyori.adventure.text.format.Style 5 | import net.kyori.adventure.text.format.TextColor 6 | import net.kyori.adventure.text.format.TextDecoration 7 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer 8 | 9 | val emptyComponent: Component get() = Component.text("") 10 | 11 | fun Component.serialize(char: Char = '§') = LegacyComponentSerializer.legacy(char).serialize(this) 12 | 13 | fun colorNonItalic(color: Int): Style = Style.style { sb: Style.Builder -> 14 | sb.decoration(TextDecoration.ITALIC, false) 15 | sb.color(TextColor.color(color)) 16 | } 17 | fun colorNonItalic(color: TextColor): Style = Style.style { sb: Style.Builder -> 18 | sb.decoration(TextDecoration.ITALIC, false) 19 | sb.color(color) 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/bukkit utils.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("BukkitUtils") 2 | 3 | package com.wynnlab.util 4 | 5 | import org.bukkit.Bukkit 6 | import org.bukkit.scoreboard.Team 7 | import org.bukkit.util.Vector 8 | 9 | fun Vector.normalizeOnXZ() = if (x == 0.0 && z == 0.0) { 10 | y = 0.0; this 11 | } else { 12 | y = 0.0; normalize() 13 | } 14 | 15 | fun registerMainTeam(name: String): Team = try { 16 | Bukkit.getScoreboardManager().mainScoreboard.registerNewTeam(name) 17 | } catch (e: IllegalArgumentException) { 18 | Bukkit.getScoreboardManager().mainScoreboard.getTeam(name)?.unregister() 19 | Bukkit.getScoreboardManager().mainScoreboard.registerNewTeam(name) 20 | } 21 | 22 | fun yawToDir(yaw: Float) = when { 23 | yaw < -157.5f -> "N" 24 | yaw < -112.5f -> "NE" 25 | yaw < -67.5f -> "E" 26 | yaw < -22.5f -> "SE" 27 | yaw < 22.5f -> "S" 28 | yaw < 67.5f -> "SW" 29 | yaw < 112.5f -> "W" 30 | yaw < 157.5f -> "NW" 31 | else -> "N" 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/operators.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import org.bukkit.Location 4 | import org.bukkit.util.Vector 5 | import kotlin.math.PI 6 | 7 | const val RAD2DEG = 180.0 / PI 8 | const val DEG2RAD = PI / 180.0 9 | 10 | operator fun Location.plus(l: Location) = clone().add(l) 11 | operator fun Location.plus(l: Vector) = clone().add(l) 12 | fun Location.plus(x: Double, y: Double, z: Double) = clone().add(x, y, z) 13 | 14 | fun Location.minus(x: Double, y: Double, z: Double) = clone().subtract(x, y, z) 15 | 16 | 17 | operator fun Vector.plus(v: Vector) = clone().add(v) 18 | operator fun Vector.plusAssign(v: Vector) { add(v) } 19 | 20 | operator fun Vector.minus(v: Vector) = clone().subtract(v) 21 | 22 | operator fun Vector.times(x: Double) = clone().multiply(x) 23 | operator fun Vector.times(v: Vector) = clone().multiply(v) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/resources.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.wynnlab 4 | import java.util.logging.Level 5 | 6 | fun saveAllResources() { 7 | wynnlab.logger.log(Level.INFO, "Saving resources...") 8 | resources.forEach { 9 | wynnlab.saveResource(it, true) 10 | } 11 | wynnlab.logger.log(Level.INFO, "... Done") 12 | } 13 | 14 | val resources = arrayOf( 15 | ///////////////////////////////////// 16 | // Top Level 17 | ///////////////////////////////////// 18 | "locations.yml", 19 | 20 | // Temp 21 | "mobs/dummy.yml", 22 | "mobs/scripts/pull.ws2", 23 | 24 | 25 | ///////////////////////////////////// 26 | // Classes 27 | ///////////////////////////////////// 28 | 29 | /*"classes/archer/archer.yml", 30 | "classes/archer/archer_main.py", 31 | "classes/archer/arrow_storm.py", 32 | "classes/archer/escape.py", 33 | "classes/archer/bomb_arrow.py", 34 | "classes/archer/arrow_shield.py", 35 | "classes/archer/arrow_rain.py",*/ 36 | 37 | "classes/assassin/assassin.yml", 38 | "classes/assassin/assassin_main.py", 39 | "classes/assassin/spin_attack.py", 40 | "classes/assassin/vanish.py", 41 | "classes/assassin/multihit.py", 42 | "classes/assassin/smoke_bomb.py", 43 | "classes/assassin/vanish_end.py", 44 | "classes/assassin/smoke_bomb_tick.py", 45 | 46 | /*"classes/mage/mage.yml", 47 | "classes/mage/mage_main.py", 48 | "classes/mage/mage_main.ws2", 49 | "classes/mage/heal.py", 50 | "classes/mage/teleport.py", 51 | "classes/mage/meteor.py", 52 | "classes/mage/ice_snake.py",*/ 53 | 54 | "classes/shaman/shaman.yml", 55 | "classes/shaman/shaman_main.py", 56 | "classes/shaman/totem.py", 57 | "classes/shaman/haul.py", 58 | "classes/shaman/aura.py", 59 | "classes/shaman/uproot.py", 60 | "classes/shaman/totem_tick.py", 61 | 62 | "classes/warrior/warrior.yml", 63 | "classes/warrior/warrior_main.py", 64 | "classes/warrior/bash.py", 65 | "classes/warrior/charge.py", 66 | "classes/warrior/uppercut.py", 67 | "classes/warrior/war_scream.py", 68 | "classes/warrior/uppercut_throw.py", 69 | 70 | "classes/monk/monk.yml", 71 | "classes/monk/monk_main.py", 72 | "classes/monk/shield.py", 73 | "classes/monk/step.py", 74 | "classes/monk/silence.py", 75 | "classes/monk/control.py", 76 | 77 | ///////////////////////////////////// 78 | // Languages 79 | ///////////////////////////////////// 80 | 81 | "lang/en_US.yml", 82 | "lang/de_DE.yml", 83 | "lang/ar_SA.yml" 84 | ) -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/task utils.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import org.bukkit.scheduler.BukkitRunnable 4 | 5 | inline fun bukkitRunnable(crossinline task: (BukkitRunnable) -> Unit) = object : BukkitRunnable() { 6 | override fun run() { 7 | task(this) 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/worlds.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.wynnlab 4 | import org.bukkit.* 5 | import org.bukkit.entity.Player 6 | import java.io.File 7 | import java.nio.file.DirectoryNotEmptyException 8 | import java.nio.file.Files 9 | import java.nio.file.LinkOption 10 | import java.nio.file.StandardCopyOption 11 | 12 | fun createInstancedWorld(worldName: String, instanceWorldName: String) = Deferred { 13 | //player.sendMessage("Copying $worldName ...") 14 | try { 15 | Files.copy( 16 | File("./$worldName/").toPath(), File("./$instanceWorldName/").toPath(), 17 | StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS) 18 | } catch (_: DirectoryNotEmptyException) { 19 | deleteDir(File("./$instanceWorldName/")) 20 | Files.copy( 21 | File("./$worldName/").toPath(), File("./$instanceWorldName/").toPath(), 22 | StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS) 23 | } 24 | copyDir(File("./$worldName"), File("./$instanceWorldName")) 25 | File("./$instanceWorldName/uid.dat").delete() 26 | loadWorld(instanceWorldName) 27 | } 28 | 29 | @OnlyAsync 30 | private fun loadWorld(name: String): InstancedWorld? { 31 | //player.sendMessage("Starting wc") 32 | 33 | val wc = WorldCreator.ofNameAndKey(name, 34 | NamespacedKey(wynnlab, name) 35 | ) 36 | //player.sendMessage("Initialized wc") 37 | 38 | wc.type(WorldType.FLAT) 39 | wc.generateStructures(false) 40 | wc.environment(World.Environment.NORMAL) 41 | wc.generatorSettings("""{"layers":[{"height":0,"block":"minecraft:air"}],"biome":"minecraft:the_void","structures":{"stronghold":{"distance":0,"count":0,"spread":0},"structures":{}}}""") 42 | wc.hardcore(true) 43 | //player.sendMessage("Set wc options") 44 | 45 | //player.sendMessage("Set world border") 46 | 47 | Bukkit.getScheduler().runTaskLaterAsynchronously(wynnlab, { -> 48 | deleteDir(File("./$name")) 49 | }, 20L) 50 | 51 | return InstancedWorld(name, wc) 52 | } 53 | 54 | class InstancedWorld(val name: String, wc: WorldCreator) { 55 | lateinit var world: World 56 | init { 57 | Bukkit.getScheduler().scheduleSyncDelayedTask(wynnlab) { 58 | world = wc.createWorld()!! 59 | world.worldBorder.apply { 60 | center = Location(world, .0, .0, .0) 61 | size = 64.0 62 | } 63 | } 64 | } 65 | 66 | fun sendPlayer(player: Player, x: Double, y: Double, z: Double, yaw: Float = 0f, pitch: Float = 0f) { 67 | player.teleport(Location(world, x, y, z, yaw, pitch)) 68 | } 69 | 70 | fun unload() { 71 | Bukkit.getServer().unloadWorld(world, false) 72 | Bukkit.getScheduler().runTaskAsynchronously(wynnlab) { -> deleteDir(File("./$name")) } 73 | } 74 | 75 | fun unloadOnZeroPlayers() { 76 | Bukkit.getScheduler().runTaskTimer(wynnlab, { task -> 77 | if (world.playerCount < 1) { 78 | unload() 79 | task.cancel() 80 | } 81 | }, 20L, 20L) 82 | } 83 | } 84 | 85 | private fun copyDir(from: File, to: File) { 86 | from.list()!!.forEach { n -> 87 | val f = File(from, n) 88 | val t = File(to, n) 89 | Files.copy(f.toPath(), t.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES, LinkOption.NOFOLLOW_LINKS) 90 | if (f.isDirectory) 91 | copyDir(f, t) 92 | } 93 | } 94 | 95 | private fun deleteDir(dir: File) { 96 | fun deleteDir(dir: File) { 97 | dir.listFiles()!!.forEach { f -> 98 | if (f.isDirectory) 99 | deleteDir(f) 100 | f.delete() 101 | //println("deleted file: $f") 102 | } 103 | } 104 | deleteDir(dir) 105 | dir.delete() 106 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/wynnlab/util/wynncraft api.kt: -------------------------------------------------------------------------------- 1 | package com.wynnlab.util 2 | 3 | import com.wynnlab.items.APIException 4 | import org.json.simple.JSONObject 5 | import org.json.simple.parser.JSONParser 6 | import java.net.HttpURLConnection 7 | import java.net.MalformedURLException 8 | import java.net.URL 9 | import java.util.* 10 | 11 | fun getWynncraftAPIResult(address: String): Deferred { 12 | val task = { 13 | val url = try { 14 | URL(address) 15 | } catch (e: MalformedURLException) { 16 | throw APIException("Malformed URL") 17 | } 18 | 19 | val connection = url.openConnection() as HttpURLConnection 20 | connection.requestMethod = "GET" 21 | connection.connect() 22 | val responseCode = connection.responseCode 23 | 24 | if (responseCode != 200) 25 | throw APIException("Response code: $responseCode") 26 | 27 | val scanner = Scanner(url.openStream()) 28 | val inline = buildString { 29 | while (scanner.hasNext()) 30 | append(scanner.nextLine()) 31 | } 32 | scanner.close() 33 | 34 | jsonParser.parse(inline) as JSONObject 35 | } 36 | 37 | return Deferred(task) 38 | } 39 | 40 | val jsonParser = JSONParser() -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/assassin.yml: -------------------------------------------------------------------------------- 1 | class: 2 | ==: com.wynnlab.WynnClass 3 | id: ASSASSIN 4 | item: SHEARS 5 | metaStats: 6 | damage: 5 7 | defence: 4 8 | range: 1 9 | spells: 3 10 | invertedControls: false 11 | spells: 12 | - ==: com.wynnlab.spells.PythonSpell 13 | maxTick: 0 14 | script: assassin_main.py 15 | - ==: com.wynnlab.spells.PythonSpell 16 | cost: 6 17 | maxTick: 16 18 | script: spin_attack.py 19 | - ==: com.wynnlab.spells.PythonSpell 20 | cost: 1 21 | maxTick: 0 22 | script: vanish.py 23 | - ==: com.wynnlab.spells.PythonSpell 24 | cost: 8 25 | maxTick: 22 26 | script: multihit.py 27 | - ==: com.wynnlab.spells.PythonSpell 28 | cost: 8 29 | maxTick: 0 30 | script: smoke_bomb.py 31 | - ==: com.wynnlab.spells.PythonSpell 32 | maxTick: 0 33 | script: vanish_end.py 34 | - ==: com.wynnlab.spells.PythonSpell 35 | maxTick: 180 36 | script: smoke_bomb_tick.py -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/assassin_main.py: -------------------------------------------------------------------------------- 1 | #function tick() { 2 | # this.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .8); 3 | # var l = this.player.getEyeLocation().clone().add(this.player.getEyeLocation().getDirection()); 4 | # this.particle(l, Particle.SWEEP_ATTACK, 1, 0, 0, 0, 0); 5 | # 6 | # this.nearbyMobs(l, 2, 2, 2).forEach(function (e) { 7 | # this.damage(e, 2); 8 | # }); 9 | #} 10 | from org.bukkit import Particle, Sound 11 | from org.bukkit.potion import PotionEffectType 12 | 13 | from com.wynnlab.spells import PySpell 14 | 15 | class Spell(PySpell): 16 | def tick(self): 17 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY): 18 | self.castSpell('ASSASSIN', 5) 19 | 20 | self.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .8) 21 | l = self.player.getEyeLocation().clone().add(self.player.getEyeLocation().getDirection()) 22 | self.particle(l, Particle.SWEEP_ATTACK, 1, 0, 0, 0, 0) 23 | 24 | for e in self.nearbyMobs(l, 2, 2, 2): 25 | self.damage(e, True, 1) 26 | self.knockback(e, .5) -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/multihit.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.potion import PotionEffectType 3 | 4 | from com.wynnlab.spells import PySpell 5 | from com.wynnlab.util import BukkitUtils 6 | 7 | class Spell(PySpell): 8 | def __init__(self): 9 | self.l = None 10 | self.entities = None 11 | self.shift = False 12 | 13 | def init(self): 14 | self.shift = self.player.isSneaking() 15 | 16 | def tick(self): 17 | if self.t % 2 != 0: 18 | return 19 | 20 | if self.t == 0: 21 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY): 22 | self.castSpell('ASSASSIN', 5) 23 | 24 | self.sound(Sound.ENTITY_PLAYER_ATTACK_STRONG, .5, 1) 25 | self.sound(Sound.ENTITY_IRON_GOLEM_HURT, 1, 1.5) 26 | if self.clone: 27 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .3, 1.5) 28 | 29 | v = BukkitUtils.normalizeOnXZ(self.player.getEyeLocation().getDirection()) 30 | self.l = self.player.getLocation().clone().add(v).add(0, .5, 0) 31 | 32 | self.particle(self.l, Particle.SWEEP_ATTACK, 5, .5, .5, .5, .1) 33 | 34 | self.entities = self.nearbyMobs(self.l, 3, 3, 3) 35 | 36 | self.particle(self.l.add(v), Particle.SWEEP_ATTACK, 5, .5, .5, .5, .1) 37 | self.particle(self.l.add(v), Particle.SWEEP_ATTACK, 5, .5, .5, .5, .1) 38 | 39 | elif self.t <= 20: 40 | for e in self.entities: 41 | e.setVelocity(self.player.getEyeLocation().getDirection().multiply(.05 if self.shift else .3).setY(.2).rotateAroundY((.1 * self.t) if self.t % 2 == 0 else (-.1 * self.t))) 42 | 43 | self.particle(e.getLocation(), Particle.SWEEP_ATTACK, 5, .5, .5, .5, .5) 44 | if self.clone: 45 | self.particle(e.getLocation(), Particle.SPELL_WITCH, 7, .5, .5, .5, .2) 46 | self.particle(e.getLocation(), Particle.SQUID_INK, 6, .5, .5, .5, .1) 47 | self.particle(e.getLocation(), Particle.CRIT, 7 if self.clone else 10, .5, .5, .5, .1) 48 | 49 | self.sound(e.getLocation(), Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, 1.3) 50 | self.sound(e.getLocation(), Sound.ENTITY_PLAYER_ATTACK_CRIT, .8, 1.6) 51 | 52 | self.damage(e, False, .27) 53 | 54 | else: 55 | for e in self.entities: 56 | if not self.shift: 57 | e.setVelocity(self.player.getEyeLocation().getDirection().setY(.5)) 58 | 59 | self.sound(e.getLocation(), Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1, 1.3) 60 | 61 | self.damage(e, False, 1.2, .2, 0, .3, .5, 0, 0) 62 | if self.clone: 63 | self.sound(e.getLocation(), Sound.ENTITY_BLAZE_DEATH, 1, 1.2) 64 | self.sound(e.getLocation(), Sound.ENTITY_BLAZE_AMBIENT, 1, 1.6) 65 | self.sound(e.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, .5, 1) 66 | -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/smoke_bomb.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Material, Sound 2 | from org.bukkit.entity import Snowball 3 | from org.bukkit.inventory import ItemStack 4 | from org.bukkit.potion import PotionEffectType 5 | 6 | from com.wynnlab.spells import PySpell 7 | 8 | class Spell(PySpell): 9 | def tick(self): 10 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY): 11 | self.castSpell('ASSASSIN', 5) 12 | 13 | self.sound(Sound.ENTITY_ENDER_PEARL_THROW if self.clone else Sound.ENTITY_SNOWBALL_THROW, .8, 1.3) 14 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, .8, 1.3) 15 | self.sound(Sound.ENTITY_GENERIC_EXTINGUISH_FIRE, 1, 1.6) 16 | 17 | v = self.player.getEyeLocation().getDirection().multiply(3) 18 | snowballs = ( 19 | self.player.launchProjectile(Snowball, v), 20 | self.player.launchProjectile(Snowball, v.rotateAroundY(.4)), 21 | self.player.launchProjectile(Snowball, v.rotateAroundY(-.8)) 22 | ) 23 | 24 | for snowball in snowballs: 25 | if self.clone: 26 | snowball.setItem(ItemStack(Material.ENDER_PEARL)) 27 | snowball.addScoreboardTag('smoke_bomb') 28 | 29 | self.player.addScoreboardTag('smoke_bomb') 30 | 31 | def bomb_hit(event): 32 | event.getEntity().remove() 33 | PySpell.castSpell(event.getEntity().getShooter(), 'ASSASSIN', 6, event.getHitEntity().getLocation() if not event.getHitEntity() is None else event.getHitBlock().getLocation()) 34 | 35 | PySpell.registerProjectileHit('smoke_bomb', bomb_hit) -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/smoke_bomb_tick.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | 4 | from com.wynnlab.spells import PySpell 5 | 6 | class Spell(PySpell): 7 | def __init__(self, l): 8 | self.l = l 9 | 10 | def tick(self): 11 | if self.t > 0 and self.player.getScoreboardTags().contains('smoke_bomb'): 12 | self.cancel() 13 | 14 | if self.t % 4 == 0: 15 | self.particle(self.l, Particle.CLOUD, 16, 3, 3, 3, 0.1) 16 | self.particle(self.l, Particle.SPELL_WITCH if self.clone else Particle.SQUID_INK, 16, 3, 3, 3, .2 if self.clone else .1) 17 | 18 | if self.t % 20 == 0: 19 | self.sound(self.l,Sound.BLOCK_FIRE_EXTINGUISH, .3 , 1) 20 | 21 | for e in self.nearbyMobs(self.l, 3, 3, 3): 22 | self.damage(e, False, .6, .45, .25, 0, 0, 0, .3) 23 | PySpell.knockback(e, VectorUP, .5) 24 | e.addPotionEffect(PotionEffect(PotionEffectType.SLOW, 101, 2)) 25 | 26 | if self.t == 0: 27 | self.player.removeScoreboardTag('smoke_bomb') -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/spin_attack.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | 4 | from com.wynnlab.spells import PySpell 5 | 6 | from java.lang import Math 7 | 8 | class Spell(PySpell): 9 | def __init__(self): 10 | self.hit = set() 11 | 12 | def tick(self): 13 | if self.t == 0: 14 | if self.player.hasPotionEffect(PotionEffectType.INVISIBILITY): 15 | self.castSpell('ASSASSIN', 5) 16 | 17 | if self.clone: 18 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, .5, 1.6) 19 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .2, 1.5) 20 | 21 | l = self.player.getEyeLocation().clone().add(Math.sin(self.t * -22.5 * DEG2RAD) * 5, 0, Math.cos(self.t * -22.5 * DEG2RAD) * 5) 22 | 23 | for e in self.nearbyMobs(l, 3, 3, 3): 24 | if e in self.hit: 25 | continue 26 | self.hit.add(e) 27 | 28 | self.damage(e, False, 1.5, .7, 0, .3, 0, 0, 0) 29 | PySpell.knockback(e, VectorUP, .5) 30 | e.addPotionEffect(PotionEffect(PotionEffectType.BLINDNESS, 100, 1)) 31 | e.addPotionEffect(PotionEffect(PotionEffectType.SLOW, 20, 8)) 32 | 33 | self.particle(l.clone().subtract(0, .5, 0), Particle.SWEEP_ATTACK, 4, .5, .5, .5, 0) 34 | self.particle(l, Particle.CLOUD if self.clone else Particle.SQUID_INK, 5, .5, .5, .5, .1) 35 | self.particle(l, Particle.SPELL_WITCH if self.clone else Particle.CRIT_MAGIC, 10, .5, .5, .5, .2) 36 | 37 | self.sound(l, Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, 1.2) 38 | self.sound(l, Sound.ITEM_FLINTANDSTEEL_USE, 1, 1.3) 39 | -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/vanish.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Bukkit, Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | from org.bukkit.util import Vector 4 | 5 | from com.wynnlab.spells import PySpell 6 | 7 | class Spell(PySpell): 8 | def tick(self): 9 | v = self.player.getEyeLocation().getDirection() 10 | self.player.setVelocity(v.clone().setY(v.getY() * (.6 if v.getY() >= 0 else .2)).multiply(1.3).add(Vector(0, .5, 0))) 11 | 12 | self.player.addPotionEffect(PotionEffect(PotionEffectType.SPEED, 100, 4, True, False, True)) 13 | self.player.addPotionEffect(PotionEffect(PotionEffectType.INCREASE_DAMAGE, 100, 4, True, False, True)) 14 | self.player.addPotionEffect(PotionEffect(PotionEffectType.INVISIBILITY, 100, 0, True, False, True)) 15 | 16 | self.particle(self.player.getEyeLocation(), Particle.SQUID_INK, 30, .5, 1, .5, .2) 17 | self.particle(self.player.getEyeLocation(), Particle.SPELL_WITCH, 40, .5, 1, .5, .5) 18 | 19 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, 1, 1.6) 20 | self.sound(Sound.ENTITY_GHAST_SHOOT, .6, 1) 21 | 22 | self.player.addScoreboardTag('invis') 23 | 24 | for p in Bukkit.getOnlinePlayers(): 25 | p.hidePlayer(plugin, self.player) 26 | #TODO: Remove Vanish, Shadow Clone (?) -------------------------------------------------------------------------------- /src/main/resources/classes/assassin/vanish_end.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Bukkit, Particle, Sound 2 | from org.bukkit.potion import PotionEffectType 3 | 4 | from com.wynnlab.spells import PySpell 5 | 6 | class Spell(PySpell): 7 | def tick(self): 8 | self.player.removeScoreboardTag('invis') 9 | 10 | self.player.removePotionEffect(PotionEffectType.SPEED) 11 | self.player.removePotionEffect(PotionEffectType.INCREASE_DAMAGE) 12 | self.player.removePotionEffect(PotionEffectType.INVISIBILITY) 13 | 14 | self.particle(self.player.getEyeLocation(), Particle.SQUID_INK, 30, .5, 1, .5, .2) 15 | self.particle(self.player.getEyeLocation(), Particle.SPELL_WITCH, 40, .5, 1, .5, .5) 16 | 17 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, 1, 1.6) 18 | self.sound(Sound.ENTITY_GHAST_SHOOT, .6, 1) 19 | 20 | for p in Bukkit.getOnlinePlayers(): 21 | p.showPlayer(plugin, self.player) -------------------------------------------------------------------------------- /src/main/resources/classes/monk/control.py: -------------------------------------------------------------------------------- 1 | from com.wynnlab.spells import PySpell 2 | 3 | class Spell(PySpell): 4 | def tick(self): 5 | pass -------------------------------------------------------------------------------- /src/main/resources/classes/monk/monk.yml: -------------------------------------------------------------------------------- 1 | class: 2 | ==: com.wynnlab.WynnClass 3 | id: MONK 4 | item: BARRIER #WOODEN_SHOVEL 5 | #item_damage: 1 6 | metaStats: 7 | damage: 0 8 | defence: 0 9 | range: 0 10 | spells: 0 11 | invertedControls: false 12 | spells: 13 | - ==: com.wynnlab.spells.PythonSpell 14 | maxTick: 0 15 | script: monk_main.py 16 | - ==: com.wynnlab.spells.PythonSpell 17 | cost: 0 18 | maxTick: 0 19 | script: shield.py 20 | - ==: com.wynnlab.spells.PythonSpell 21 | cost: 0 22 | maxTick: 0 23 | script: step.py 24 | - ==: com.wynnlab.spells.PythonSpell 25 | cost: 0 26 | maxTick: 0 27 | script: silence.py 28 | - ==: com.wynnlab.spells.PythonSpell 29 | cost: 0 30 | maxTick: 0 31 | script: control.py -------------------------------------------------------------------------------- /src/main/resources/classes/monk/monk_main.py: -------------------------------------------------------------------------------- 1 | from com.wynnlab.spells import PySpell 2 | 3 | class Spell(PySpell): 4 | def tick(self): 5 | pass -------------------------------------------------------------------------------- /src/main/resources/classes/monk/shield.py: -------------------------------------------------------------------------------- 1 | from com.wynnlab.spells import PySpell 2 | 3 | class Spell(PySpell): 4 | def tick(self): 5 | pass -------------------------------------------------------------------------------- /src/main/resources/classes/monk/silence.py: -------------------------------------------------------------------------------- 1 | from com.wynnlab.spells import PySpell 2 | 3 | class Spell(PySpell): 4 | def tick(self): 5 | pass -------------------------------------------------------------------------------- /src/main/resources/classes/monk/step.py: -------------------------------------------------------------------------------- 1 | from com.wynnlab.spells import PySpell 2 | 3 | class Spell(PySpell): 4 | def tick(self): 5 | pass -------------------------------------------------------------------------------- /src/main/resources/classes/shaman/aura.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | from org.bukkit.util import Vector 4 | 5 | from com.wynnlab.api import PersistentDataAPI, PlayerAPI 6 | from com.wynnlab.spells import PySpell 7 | 8 | from java.lang import Math 9 | 10 | class Spell(PySpell): 11 | def __init__(self): 12 | self.totem = None 13 | self.hit = set() 14 | 15 | def tick(self): 16 | if self.t == 0: 17 | # Find totem 18 | totem_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem', None) 19 | for e in self.player.getNearbyEntities(16, 16, 16): 20 | if e.getEntityId() == totem_id: 21 | self.totem = e 22 | 23 | if self.totem is None: 24 | PlayerAPI.sendWynnMessage(self.player, 'messages.totem_out') 25 | self.cancel() 26 | return 27 | 28 | self.sound(self.totem.getLocation(), Sound.ENTITY_PLAYER_ATTACK_STRONG, .4, 1) 29 | self.sound(self.totem.getLocation(), Sound.ENTITY_SHULKER_SHOOT, .9, .7) 30 | self.sound(self.totem.getLocation(), Sound.ENTITY_EVOKER_CAST_SPELL, 1, 1.3) 31 | self.sound(self.totem.getLocation(), Sound.ENTITY_EVOKER_PREPARE_SUMMON, .7, .5) 32 | 33 | if self.clone: 34 | self.sound(self.totem.getLocation(), Sound.ENTITY_BLAZE_SHOOT, .7, .7) 35 | self.sound(self.totem.getLocation(), Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, .4, .6) 36 | 37 | elif self.t <= 10: 38 | i = 0 39 | while i < 360: 40 | l = self.totem.getLocation().clone().add(Math.sin(i * DEG2RAD) * (self.t + 1), .4, Math.cos(i * DEG2RAD) * (self.t + 1)) 41 | 42 | self.particle(l, Particle.SPELL_MOB if self.clone else Particle.CRIT_MAGIC, 0 if self.clone else 1, self.clone, self.clone, self.clone, self.clone) 43 | self.damageAndPull(l) 44 | 45 | i += 15 - self.t 46 | 47 | elif 15 < self.t <= 25: 48 | i = 0 49 | while i < 360: 50 | l = self.totem.getLocation().clone().add(Math.sin(i * DEG2RAD) * (26 - self.t), .4, Math.cos(i * DEG2RAD) * (26 - self.t)) 51 | 52 | self.particle(l, Particle.SPELL_MOB if self.clone else Particle.CRIT_MAGIC, 0 if self.clone else 1, self.clone, self.clone, self.clone, self.clone) 53 | self.damageAndPull(l) 54 | 55 | i += self.t - 14 56 | 57 | if self.t % 10 == 0: 58 | for i in range(0, 360, 20): 59 | self.particle(self.totem.getLocation().clone().add(Math.sin(i * DEG2RAD) * 2, 1.6, Math.cos(i * DEG2RAD) * 2), Particle.FIREWORKS_SPARK, 1, 0, 0, 0, 0) 60 | 61 | for e in self.nearbyMobs(self.totem.getLocation(), 1, 1, 1): 62 | e.addPotionEffect(PotionEffect(PotionEffectType.SLOW, 20, 9, True, False)) 63 | 64 | if self.t == 10 or self.t == 25: 65 | self.hit = set() 66 | 67 | def damageAndPull(self, l): 68 | for e in self.nearbyMobs(l, .5, 2, .5): 69 | pull_dir = self.totem.getLocation().clone().subtract(e.getLocation()).toVector() 70 | pull_dir = Vector(Math.max(Math.min(pull_dir.getX() / 5, 1), -1), 0.2, Math.max(Math.min(pull_dir.getZ() / 5, 1), -1)) 71 | 72 | e.setVelocity(pull_dir) 73 | 74 | if e in self.hit: 75 | continue 76 | self.hit.add(e) 77 | 78 | self.damage(e, False, 2, .7, 0, 0, .3, 0, 0) -------------------------------------------------------------------------------- /src/main/resources/classes/shaman/haul.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | from org.bukkit.util import Vector 4 | 5 | from com.wynnlab.api import PersistentDataAPI, PlayerAPI 6 | from com.wynnlab.spells import PySpell 7 | 8 | from java.lang import Math 9 | 10 | class Spell(PySpell): 11 | def __init__(self): 12 | self.hit = set() 13 | 14 | def tick(self): 15 | if self.t == 0: 16 | # Find totem 17 | totem = None 18 | totem_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem', None) 19 | for e in self.player.getWorld().getEntities(): 20 | if e.getEntityId() == totem_id: 21 | totem = e 22 | 23 | if totem is None: 24 | PlayerAPI.sendWynnMessage(self.player, 'messages.totem_out') 25 | self.cancel() 26 | return 27 | 28 | vector = totem.getLocation().clone().subtract(self.player.getLocation()).add(0, 2, 0).toVector() 29 | vector = Vector(Math.max(Math.min(vector.getX(), 6), -6), Math.max(Math.min(vector.getY(), 2), -2), Math.max(Math.min(vector.getZ(), 6), -6)) 30 | self.player.setVelocity(vector.clone().multiply(0.5).setY(vector.getY()).multiply(0.5)); 31 | 32 | self.particle(self.player.getLocation(), Particle.CLOUD, 6, 1, 1, 1, 0.1) 33 | self.particle(self.player.getLocation(), Particle.SQUID_INK, 6, 1, 1, 1, 0.1) 34 | 35 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, .4, .8) 36 | self.sound(Sound.ENTITY_BLAZE_SHOOT, 1, 1) 37 | self.sound(Sound.ENTITY_IRON_GOLEM_HURT, .8, .8) 38 | if self.clone: 39 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .1, .9) 40 | 41 | elif self.t > 10: 42 | if self.player.isOnGround(): 43 | self.particle(self.player.getLocation().clone().add(0, 1, 0), Particle.FIREWORKS_SPARK if self.clone else Particle.TOTEM, 5, 1, 2, 1, .2) 44 | self.particle(self.player.getLocation(), Particle.CLOUD, 6, 1, .2, 1, .1) 45 | self.particle(self.player.getLocation(), Particle.SQUID_INK, 6, 1, .2, 1, .1) 46 | if self.clone: 47 | self.particle(self.player.getLocation(), Particle.SPELL_MOB, 0, 1, 1, 1, 1) 48 | 49 | self.sound(Sound.BLOCK_STONE_STEP, 1, .9) 50 | self.sound(Sound.BLOCK_STONE_FALL, 1, .9) 51 | 52 | self.player.setVelocity(Vector(0, .5, 0)) 53 | 54 | self.cancel() 55 | 56 | else: 57 | for e in self.nearbyMobs(1, 1, 1): 58 | if e in self.hit: 59 | continue 60 | self.hit.add(e) 61 | 62 | self.damage(e, False, 1, .8, 0, .2, 0, 0, 0) 63 | PySpell.knockback(e, VectorUP, 2) 64 | e.addPotionEffect(PotionEffect(PotionEffectType.BLINDNESS, 100, 0, True, False)) -------------------------------------------------------------------------------- /src/main/resources/classes/shaman/shaman.yml: -------------------------------------------------------------------------------- 1 | class: 2 | ==: com.wynnlab.WynnClass 3 | id: SHAMAN 4 | item: STONE_SHOVEL 5 | item_damage: 7 6 | metaStats: 7 | damage: 2 8 | defence: 3 9 | range: 3 10 | spells: 5 11 | invertedControls: false 12 | spells: 13 | - ==: com.wynnlab.spells.PythonSpell 14 | maxTick: 15 15 | script: shaman_main.py 16 | - ==: com.wynnlab.spells.PythonSpell 17 | cost: 4 18 | maxTick: 0 19 | script: totem.py 20 | - ==: com.wynnlab.spells.PythonSpell 21 | cost: 1 22 | maxTick: 300 23 | script: haul.py 24 | - ==: com.wynnlab.spells.PythonSpell 25 | cost: 8 26 | maxTick: 30 27 | script: aura.py 28 | - ==: com.wynnlab.spells.PythonSpell 29 | cost: 6 30 | maxTick: 20 31 | script: uproot.py 32 | - ==: com.wynnlab.spells.PythonSpell 33 | maxTick: 400 34 | script: totem_tick.py -------------------------------------------------------------------------------- /src/main/resources/classes/shaman/shaman_main.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | 3 | from com.wynnlab.spells import PySpell 4 | 5 | class Spell(PySpell): 6 | def __init__(self): 7 | self.p_left = None 8 | self.p_center = None 9 | self.p_right = None 10 | 11 | self.dir_left = None 12 | self.dir_center = None 13 | self.dir_right = None 14 | 15 | self.hit = set() 16 | 17 | def init(self): 18 | self.p_left = self.player.getEyeLocation().clone() 19 | self.p_center = self.p_left.clone() 20 | self.p_right = self.p_center.clone() 21 | 22 | self.dir_center = self.player.getEyeLocation().getDirection().clone() 23 | self.dir_left = self.dir_center.clone().rotateAroundY(-.3) 24 | self.dir_right = self.dir_center.clone().rotateAroundY(.3) 25 | 26 | def tick(self): 27 | self.p_left.add(self.dir_left) 28 | self.p_center.add(self.dir_center) 29 | self.p_right.add(self.dir_right) 30 | 31 | if self.t == 0: 32 | self.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .6) 33 | self.sound(Sound.ENTITY_ZOMBIE_INFECT, .5, 1.8) 34 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, 1, 1.4) 35 | if self.clone: 36 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, .5, .2) 37 | 38 | else: 39 | self.particles(self.p_left) 40 | self.particles(self.p_center) 41 | self.particles(self.p_right) 42 | 43 | for e in self.nearbyMobs(self.p_left, 1, 2, 1): 44 | if e in self.hit: 45 | continue 46 | self.hit.add(e) 47 | self.damage(e, True, .333) 48 | self.knockback(e, .1) 49 | for e in self.nearbyMobs(self.p_center, 1, 2, 1): 50 | if e in self.hit: 51 | continue 52 | self.hit.add(e) 53 | self.damage(e, True, .333) 54 | self.knockback(e, .1) 55 | for e in self.nearbyMobs(self.p_right, 1, 2, 1): 56 | if e in self.hit: 57 | continue 58 | self.hit.add(e) 59 | self.damage(e, True, .333) 60 | self.knockback(e, .1) 61 | 62 | def particles(self, l): 63 | if self.clone: 64 | self.particle(l, Particle.SPELL_MOB, 0, 1, 1, 1, 1) 65 | else: 66 | self.particle(l, Particle.CRIT_MAGIC, 3, 0, 0, 0, 0) 67 | #self.particle(l, Particle.CRIT, 2, 0, 0, 0, 0) -------------------------------------------------------------------------------- /src/main/resources/classes/shaman/totem.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Bukkit, Material, Sound 2 | from org.bukkit.entity import EntityType 3 | from org.bukkit.inventory import ItemStack 4 | 5 | from com.wynnlab.api import PersistentDataAPI 6 | from com.wynnlab.spells import PySpell 7 | 8 | class Spell(PySpell): 9 | def tick(self): 10 | if self.player.getScoreboardTags().contains('totem'): 11 | totem_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem', None) 12 | if not totem_id is None: 13 | for e in self.player.getWorld().getEntities(): 14 | if e.getEntityId() == totem_id: 15 | e.remove() 16 | 17 | holo_id = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem_holo', None) 18 | if not holo_id is None: 19 | for e in self.player.getWorld().getEntities(): 20 | if e.getEntityId() == holo_id: 21 | e.remove() 22 | 23 | totem_task = PersistentDataAPI.getInt(PersistentDataAPI.getData(self.player), 'totem_task', None) 24 | if not totem_task is None: 25 | Bukkit.getScheduler().cancelTask(totem_task) 26 | 27 | self.player.addScoreboardTag('totem') 28 | 29 | self.sound(Sound.ENTITY_PLAYER_ATTACK_WEAK, .8, .3) 30 | self.sound(Sound.ENTITY_IRON_GOLEM_HURT, 1, .8) 31 | if self.clone: 32 | self.sound(Sound.ENTITY_BLAZE_SHOOT, 1, .9) 33 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .1, .7) 34 | 35 | dir = self.player.getEyeLocation().getDirection().clone().setY(self.player.getEyeLocation().getDirection().getY()) 36 | 37 | totem = self.player.getWorld().spawnEntity(self.player.getLocation().clone().add(0, 1, 0).add(dir), EntityType.ARMOR_STAND) 38 | 39 | totem.addScoreboardTag('totem') 40 | totem.setGravity(True) 41 | totem.setInvulnerable(True) 42 | totem.setVisible(True) 43 | 44 | totem_item = ItemStack(Material.STONE_SHOVEL) 45 | totem_meta = totem_item.getItemMeta() 46 | totem_meta.setUnbreakable(True) 47 | totem_meta.setDamage(29 if self.clone else 28) 48 | totem_item.setItemMeta(totem_meta) 49 | 50 | totem.getEquipment().setHelmet(totem_item) 51 | 52 | totem.setVelocity(dir.setY(1)) 53 | 54 | PersistentDataAPI.setInt(PersistentDataAPI.getData(self.player), 'totem', totem.getEntityId()) 55 | 56 | self.castSpell('SHAMAN', 5, totem, None, False) -------------------------------------------------------------------------------- /src/main/resources/classes/shaman/totem_tick.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.attribute import Attribute 3 | from org.bukkit.entity import EntityType, Mob, Player 4 | 5 | from com.wynnlab.api import PersistentDataAPI 6 | from com.wynnlab.spells import PySpell 7 | 8 | from java.lang import Math 9 | 10 | class Spell(PySpell): 11 | def __init__(self, totem, holo, hit): 12 | self.totem = totem 13 | self.holo = holo 14 | 15 | self.hit = hit 16 | 17 | def tick(self): 18 | if self.t == 0: 19 | PersistentDataAPI.setInt(PersistentDataAPI.getData(self.player), 'totem_task', self.getTaskId()) 20 | 21 | if not self.hit: 22 | if not self.totem.isOnGround(): 23 | self.particle(self.totem.getLocation().clone().add(0, 1, 0), Particle.END_ROD if self.clone else Particle.VILLAGER_HAPPY, 1, 0, 0, 0, 0) 24 | self.delay() 25 | 26 | else: 27 | self.hit = True 28 | 29 | self.totem.setMarker(True) 30 | 31 | self.holo = self.player.getWorld().spawnEntity(self.totem.getLocation().clone().add(0, 2.7, 0), EntityType.ARMOR_STAND) 32 | 33 | self.holo.setMarker(True) 34 | self.holo.setVisible(False) 35 | self.holo.setInvulnerable(True) 36 | self.holo.setCustomName(PySpell.colorText('20s', 'c')) 37 | self.holo.setCustomNameVisible(True) 38 | 39 | PersistentDataAPI.setInt(PersistentDataAPI.getData(self.player), 'totem_holo', self.holo.getEntityId()) 40 | 41 | l = self.totem.getLocation() 42 | 43 | self.particle(l.clone().add(0,-1,0), Particle.EXPLOSION_HUGE, 1, 0, 0, 0, 1) 44 | self.particle(l, Particle.FIREWORKS_SPARK if self.clone else Particle.CRIT_MAGIC, 5, 2, 2, 2, .8) 45 | self.particle(l, Particle.SQUID_INK, 5, 2, 2, 2, .5) 46 | 47 | self.sound(l, Sound.ENTITY_EVOKER_PREPARE_SUMMON, .9, 1.1) 48 | self.sound(l, Sound.ENTITY_IRON_GOLEM_DEATH, 1, .8) 49 | self.sound(l, Sound.ITEM_TOTEM_USE, .9, 1) 50 | if self.clone: 51 | self.sound(l, Sound.ENTITY_FIREWORK_ROCKET_BLAST_FAR, 1, .7) 52 | self.sound(l, Sound.BLOCK_FIRE_EXTINGUISH, .5, .5) 53 | self.sound(l, Sound.ENTITY_BLAZE_DEATH, .3, 1) 54 | 55 | for e in self.nearbyMobs(l, 4, 4, 4): 56 | self.damage(e, False, 1, .8, 0, 0, 0, .2, 0) 57 | PySpell.knockback(e, VectorUP, .5) 58 | 59 | else: 60 | if self.totem.isOnGround() and self.t >= 20: 61 | self.totem.setMarker(True) 62 | 63 | if self.t < 400: 64 | if self.t % 20 == 0: 65 | self.holo.setCustomName(PySpell.colorText('{0}s'.format((400 - self.t) // 20), 'c')) 66 | 67 | for e in self.player.getWorld().getNearbyEntities(self.totem.getLocation(), 8, 4, 8): 68 | if not isinstance(e, Mob): 69 | continue 70 | 71 | if isinstance(e, Player): 72 | PySpell.heal(e, self.player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue() / 10) 73 | 74 | else: 75 | self.damage(e, False, .2, .8, 0, 0, 0, 0, .2) 76 | 77 | l = self.totem.getLocation().clone().add(Math.sin(self.t * 10 * DEG2RAD) * 8, .7, Math.cos(self.t * 10 * DEG2RAD) * 8) 78 | self.particle(l, Particle.FIREWORKS_SPARK if self.clone else Particle.TOTEM, 1, 0, 0, 0, 0) 79 | 80 | self.particle(self.totem.getLocation().clone().add(0, 1, 0), Particle.SPELL_MOB, 2, .5, 1, .5, .5) 81 | 82 | self.holo.teleport(self.totem.getLocation().clone().add(0, 2.7, 0)) 83 | 84 | else: 85 | self.totem.remove() 86 | self.holo.remove() 87 | 88 | self.player.removeScoreboardTag('totem') -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/bash.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Material, Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | 4 | from com.wynnlab.spells import PySpell 5 | 6 | from java.lang import Math 7 | 8 | class Spell(PySpell): 9 | def __init__(self): 10 | self.bash_loc = None 11 | 12 | def tick(self): 13 | if self.t == 0: 14 | self.bash_loc = self.player.getLocation().clone().add(self.player.getEyeLocation().getDirection().multiply(2).setY(1)) 15 | self.bash() 16 | 17 | self.sound(self.bash_loc, Sound.ENTITY_GHAST_SHOOT, 1, 1) 18 | if self.clone: 19 | self.sound(self.bash_loc, Sound.ENTITY_EVOKER_CAST_SPELL, 1, .4) 20 | 21 | elif self.t == 10: 22 | self.bash_loc.add(self.player.getEyeLocation().getDirection().multiply(4).setY(0)) 23 | self.bash() 24 | 25 | self.sound(self.bash_loc, Sound.ENTITY_WITHER_BREAK_BLOCK, .4 if self.clone else .8, 1.8 if self.clone else .8) 26 | if self.clone: 27 | self.sound(self.bash_loc, Sound.BLOCK_GLASS_BREAK, 1, 1) 28 | self.sound(self.bash_loc, Sound.ENTITY_BLAZE_AMBIENT, .2, .8) 29 | 30 | for i in range(0, 360, 36): 31 | block_loc = self.bash_loc.clone().add(Math.sin(i * DEG2RAD) * 3, .5, Math.cos(i * DEG2RAD) * 3) 32 | block_data = (Material.GLOWSTONE if self.clone else Material.DIRT).createBlockData() 33 | 34 | self.particle(block_loc, Particle.BLOCK_CRACK, 10, .5, .5, .5, .2, block_data) 35 | 36 | block = self.player.getWorld().spawnFallingBlock(block_loc, block_data) 37 | block.setDropItem(False) 38 | block.setVelocity(block_loc.subtract(self.bash_loc).toVector().multiply(.05).setY(.4)) 39 | 40 | 41 | def bash(self): 42 | if not self.clone: 43 | self.particle(self.bash_loc, Particle.SMOKE_LARGE, 15, .5, .5, .5, .1) 44 | self.particle(self.bash_loc, Particle.FIREWORKS_SPARK if self.clone else Particle.SQUID_INK, 10 if self.clone else 5, .4, .4, .4, .4 if self.clone else .2) 45 | self.particle(self.bash_loc, Particle.CLOUD, 5, .2, .2, .2, .2) 46 | self.particle(self.bash_loc, Particle.EXPLOSION_LARGE, 1, 0, 0, 0, 0) 47 | self.sound(self.bash_loc, Sound.ENTITY_GENERIC_EXPLODE, 1, 1) 48 | 49 | hit_count = 0 50 | for e in self.nearbyMobs(self.bash_loc, 6, 6, 6): 51 | self.damage(e, False, 1.3, .6, .4, 0, 0, 0, 0) 52 | self.knockback(e, 2) 53 | hit_count += 1 54 | 55 | self.player.addPotionEffect(PotionEffect(PotionEffectType.INCREASE_DAMAGE, hit_count * 20, 1, True, False, True)) -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/charge.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.potion import PotionEffect, PotionEffectType 3 | 4 | from com.wynnlab.spells import PySpell 5 | 6 | class Spell(PySpell): 7 | def __init__(self): 8 | self.ground_start = False 9 | 10 | def tick(self): 11 | if self.t == 0: 12 | p_loc = self.player.getLocation().clone().add(0, 1, 0) 13 | self.particle(p_loc, Particle.VILLAGER_HAPPY if self.clone else Particle.SMOKE_LARGE, 5, .5, 2, .5, 0.1) 14 | self.particle(p_loc, Particle.CLOUD, 5, .5, 2, .5, .3) 15 | self.particle(p_loc, Particle.SQUID_INK, 8, .5, 2, .5, .2) 16 | 17 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK if self.clone else Sound.ENTITY_PLAYER_ATTACK_CRIT, .3, .6) 18 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_LAUNCH, .8, 1) 19 | self.sound(Sound.ENTITY_BLAZE_SHOOT, 1, 1.1) 20 | 21 | if self.player.isOnGround(): 22 | self.ground_start = True 23 | #else: 24 | # self.player.playSound(self.player.getLocation(), Sound.ITEM_ELYTRA_FLYING, 1, .9) 25 | 26 | self.player.setVelocity(self.player.getEyeLocation().getDirection().setY(1) if self.ground_start else self.player.getEyeLocation().getDirection().multiply(2).setY(.2)) 27 | 28 | if self.t <= 5: 29 | self.particle(self.player.getLocation(), Particle.CLOUD if self.clone else Particle.SQUID_INK, 3, .2, .2, .2, .6) 30 | 31 | elif self.t < 10: 32 | if not self.player.isOnGround(): 33 | self.player.setVelocity(self.player.getEyeLocation().getDirection().multiply(2).setY(-.3)) 34 | self.particle(self.player.getLocation(), Particle.FIREWORKS_SPARK if self.clone else Particle.LAVA, 5 if self.clone else 2, .1, .1, .1, .4) 35 | else: 36 | self.particle(self.player.getLocation().clone().add(0, 2, 0), Particle.VILLAGER_HAPPY if self.clone else Particle.FLAME, 1, 0, 0, 0, .05) 37 | 38 | self.sound(Sound.ENTITY_GENERIC_EXPLODE, 1, 1.3) 39 | self.sound(Sound.BLOCK_STONE_STEP, 1, 1.3) 40 | if self.clone: 41 | self.sound(Sound.ENTITY_FIREWORK_ROCKET_BLAST, 1, 1.3) 42 | self.sound(Sound.ENTITY_BLAZE_AMBIENT, .2, 1.3) 43 | 44 | #self.player.stopSound(Sound.ITEM_ELYTRA_FLYING) 45 | 46 | self.cancel() 47 | 48 | else: 49 | self.sound(Sound.ENTITY_GENERIC_EXPLODE, 1, 1.3) 50 | self.sound(Sound.BLOCK_STONE_STEP, 1, 1.3) 51 | 52 | #self.player.stopSound(Sound.ITEM_ELYTRA_FLYING) 53 | 54 | hit_count = 0 55 | for e in self.nearbyMobs(1.5, 2, 1.5): 56 | self.damage(e, False, 1.5, .6, 0, 0, 0, .4, 0) 57 | PySpell.knockback(e, e.getLocation().clone().subtract(self.player.getLocation()).toVector(), 1) 58 | hit_count += 1 59 | 60 | self.player.addPotionEffect(PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, hit_count * 20, 1, True, False, True)) 61 | -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/uppercut.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Material, Particle, Sound 2 | from org.bukkit.util import Vector 3 | 4 | from com.wynnlab.spells import PySpell 5 | from com.wynnlab.util import BukkitUtils 6 | 7 | class Spell(PySpell): 8 | def __init__(self): 9 | self.ripple_loc = None 10 | self.ripple_dir = None 11 | 12 | self.hit = set() 13 | 14 | self.has_hit = False 15 | self.shift = False 16 | 17 | def init(self): 18 | self.ripple_loc = self.player.getLocation().clone().add(0, .1, 0) 19 | self.ripple_dir = BukkitUtils.normalizeOnXZ(self.player.getEyeLocation().getDirection()) 20 | self.shift = self.player.isSneaking() 21 | 22 | def tick(self): 23 | if self.t == 0 and self.clone: 24 | self.sound(Sound.ENTITY_EVOKER_CAST_SPELL, .7, .7) 25 | 26 | if self.t <= 5: 27 | self.ripple_loc.add(self.ripple_dir) 28 | 29 | self.sound(self.ripple_loc, Sound.BLOCK_GLASS_BREAK if self.clone else Sound.ENTITY_WITHER_BREAK_BLOCK, 1 if self.clone else .2, 1) 30 | if self.clone: 31 | self.sound(self.ripple_loc, Sound.BLOCK_LAVA_EXTINGUISH, .6, 1.2) 32 | 33 | self.particle(self.ripple_loc, Particle.BLOCK_CRACK, 10, .5, .5, .5, .5, (Material.GLOWSTONE if self.clone else Material.DIRT).createBlockData()) 34 | 35 | for e in self.nearbyMobs(self.ripple_loc, 3, 3, 3): 36 | if e in self.hit: 37 | continue 38 | self.hit.add(e) 39 | 40 | self.castSpell('WARRIOR', 5, e) 41 | self.has_hit = True 42 | 43 | if self.t == 5 and self.has_hit and self.shift: 44 | self.player.setVelocity(Vector(0, 1.5, 0)) -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/uppercut_throw.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.util import Vector 3 | 4 | from com.wynnlab.spells import PySpell 5 | 6 | class Spell(PySpell): 7 | def __init__(self, e): 8 | self.e = e 9 | 10 | def tick(self): 11 | if self.t == 0: 12 | self.e.setVelocity(Vector(0, 1.75, 0)) 13 | self.damage(self.e, False, 3, .7, .2, .1, 0, 0, 0) 14 | self.sound(self.e.getLocation(), Sound.ENTITY_ENDER_DRAGON_HURT, 1 if self.clone else .5, 1) 15 | 16 | elif self.t < 8: 17 | self.particle(self.e.getLocation(), Particle.CLOUD if self.clone else Particle.LAVA, 3 if self.clone else 1, .6, .1, .6, 0) 18 | if self.clone: 19 | self.particle(self.e.getLocation(), Particle.FIREWORKS_SPARK, 1, .6, .1, .6, .5) 20 | 21 | elif self.t == 8: 22 | self.e.setVelocity(Vector(0, 0, 0)) 23 | self.damage(self.e, False, .5, .6, 0, .4, 0, 0, 0) 24 | 25 | self.explode() 26 | 27 | self.sound(self.e.getLocation(), Sound.ENTITY_GENERIC_EXPLODE, 1, .9) 28 | if self.clone: 29 | self.sound(self.e.getLocation(), Sound.ENTITY_BLAZE_AMBIENT, .2, .8) 30 | 31 | elif self.t == 10: 32 | self.e.setVelocity(Vector(0, -2, 0)) 33 | 34 | elif (not self.e.isOnGround()) and self.t < 20: 35 | self.particle(self.e.getLocation(), Particle.FIREWORKS_SPARK if self.clone else Particle.SMOKE_LARGE, 10 if self.clone else 2, .6, .6, .6, .5 if self.clone else 0) 36 | 37 | else: 38 | self.damage(self.e, False, .5, .8, 0, .2, 0, 0, 0) 39 | self.explode() 40 | self.cancel() 41 | 42 | def explode(self): 43 | self.particle(self.e.getLocation(), Particle.LAVA, 10, .5, .5, .5, 0) 44 | self.particle(self.e.getLocation(), Particle.FIREWORKS_SPARK if self.clone else Particle.SMOKE_LARGE, 10 if self.clone else 2, .6, .6, .6, .5 if self.clone else 0) 45 | self.particle(self.e.getLocation(), Particle.SQUID_INK, 5 if self.clone else 10, .4, .4, .4, .3) 46 | self.particle(self.e.getLocation(), Particle.CLOUD, 10, 1, 1, 1, 1) -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/war_scream.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | from org.bukkit.entity import Player 3 | from org.bukkit.potion import PotionEffect, PotionEffectType 4 | 5 | from com.wynnlab.spells import PySpell 6 | from com.wynnlab.util import BukkitUtils 7 | 8 | from java.lang import Math 9 | 10 | class Spell(PySpell): 11 | def __init__(self): 12 | self.scream_loc = None 13 | self.scream_dir = None 14 | 15 | def init(self): 16 | self.scream_loc = self.player.getEyeLocation().clone() 17 | self.scream_dir = BukkitUtils.normalizeOnXZ(self.player.getEyeLocation().getDirection()) 18 | 19 | def tick(self): 20 | if self.t == 0: 21 | self.sound(Sound.ENTITY_PLAYER_ATTACK_KNOCKBACK, .5, .5) 22 | self.sound(Sound.ENTITY_ENDER_DRAGON_FLAP, 1, 1) 23 | self.sound(Sound.ENTITY_ENDER_DRAGON_GROWL, .4, 1) 24 | 25 | for p in self.player.getWorld().getNearbyEntities(self.player.getLocation(), 8, 8, 8): 26 | if not isinstance(p, Player): 27 | continue 28 | 29 | p.addPotionEffect(PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 4800, 2, True, False, True)) 30 | p.addPotionEffect(PotionEffect(PotionEffectType.INCREASE_DAMAGE, 4800, 1, True, False, True)) 31 | 32 | if self.t <= 8: 33 | for i in range(0, 360, 45): 34 | l = self.player.getLocation().clone().add(Math.sin(i * DEG2RAD) * (self.t + 1), .2, Math.cos(i * DEG2RAD) * (self.t + 1)) 35 | self.particle(l, Particle.CLOUD if self.clone else Particle.SQUID_INK, 3, .1, 0, .1, .1) 36 | self.particle(l, Particle.CRIT, 3, .1, 0, .1, .1) 37 | self.particle(l, Particle.SPELL_MOB if self.clone else Particle.LAVA, 5 if self.clone else 1, .2, .2, .2, .5) 38 | 39 | self.scream_loc.add(self.scream_dir) 40 | 41 | if self.t >= 2: 42 | self.particle(self.scream_loc, Particle.EXPLOSION_LARGE, 1, 0, 0, 0, 0) 43 | 44 | for e in self.nearbyMobs(self.scream_loc, 3, 3, 3): 45 | self.damage(e, False, .3, 0, 0, 0, 0, .75, .25) -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/warrior.yml: -------------------------------------------------------------------------------- 1 | class: 2 | ==: com.wynnlab.WynnClass 3 | id: WARRIOR 4 | item: IRON_SHOVEL 5 | metaStats: 6 | damage: 2 7 | defence: 3 8 | range: 3 9 | spells: 5 10 | invertedControls: false 11 | spells: 12 | - ==: com.wynnlab.spells.PythonSpell 13 | maxTick: 0 14 | script: warrior_main.py 15 | - ==: com.wynnlab.spells.PythonSpell 16 | cost: 6 17 | maxTick: 10 18 | script: bash.py 19 | - ==: com.wynnlab.spells.PythonSpell 20 | cost: 4 21 | maxTick: 10 22 | script: charge.py 23 | - ==: com.wynnlab.spells.PythonSpell 24 | cost: 8 25 | maxTick: 5 26 | script: uppercut.py 27 | - ==: com.wynnlab.spells.PythonSpell 28 | cost: 4 29 | maxTick: 20 30 | script: war_scream.py 31 | - ==: com.wynnlab.spells.PythonSpell 32 | maxTick: 20 33 | script: uppercut_throw.py -------------------------------------------------------------------------------- /src/main/resources/classes/warrior/warrior_main.py: -------------------------------------------------------------------------------- 1 | from org.bukkit import Particle, Sound 2 | 3 | from com.wynnlab.spells import PySpell 4 | 5 | class Spell(PySpell): 6 | def tick(self): 7 | self.sound(Sound.ENTITY_PLAYER_ATTACK_SWEEP, 1, .8) 8 | l = self.player.getEyeLocation().clone().add(self.player.getEyeLocation().getDirection().multiply(2)) 9 | self.particle(l, Particle.SWEEP_ATTACK, 1, 0, 0, 0, 0) 10 | 11 | for e in self.nearbyMobs(l, 3, 3, 3): 12 | self.damage(e, True, 1) 13 | self.knockback(e, 1) -------------------------------------------------------------------------------- /src/main/resources/lang/ar_SA.yml: -------------------------------------------------------------------------------- 1 | classes: 2 | MAGE: 3 | className: 'ساحر' 4 | cloneName: 'ساحر اسود' 5 | lore: | 6 | &7Mages are naturally talented 7 | &7in the magical arts. While 8 | &7their raw damage may be 9 | &7considered weaker, they 10 | &7offer a great amount of 11 | &7utility and versatility 12 | &7with their spells. 13 | ARCHER: 14 | className: رامي اسهم 15 | cloneName: صياد 16 | lore: | 17 | &7Benefiting from the highest 18 | &7range in the game, Archers 19 | &7can comfortably keep their 20 | &7distance from enemies while 21 | &7dishing out high levels 22 | &7of damage. But they must 23 | &7be wary of attacks, as their 24 | &7defence is low. 25 | ASSASSIN: 26 | className: مغتال 27 | cloneName: نينجا 28 | lore: | 29 | &7The Assassin is the deadliest 30 | &7of all the classes, exploiting 31 | &7enemies weak spots to deal 32 | &7massive amounts of damage 33 | &7from the shadows, however 34 | &7they endanger themselves 35 | &7by having to get extremely 36 | &7close to the enemy. 37 | gui: 38 | class: 39 | select: 'انت الان &3[%s]' 40 | item: 41 | title: '&fحدد &6&l%s' 42 | damage: '&6⚔ الدمج %s' 43 | defence: '&c❤ الدفاع %s' 44 | range: '&a➸ النطاق %s' 45 | spells: '&d✺ التعويذات %s' 46 | clone: '&8اظغط الزر الايمن لـ &b&l%s' 47 | -------------------------------------------------------------------------------- /src/main/resources/locations.yml: -------------------------------------------------------------------------------- 1 | locations: 2 | - ==: com.wynnlab.locations.Location 3 | name: Insunis 4 | pos1: 5 | ==: org.bukkit.Location 6 | world: neww 7 | x: 2041 8 | y: 56 9 | z: 1819 10 | pos2: 11 | ==: org.bukkit.Location 12 | world: neww 13 | x: 2102 14 | y: 111 15 | z: 1884 16 | announce: true -------------------------------------------------------------------------------- /src/main/resources/mobs/dummy.yml: -------------------------------------------------------------------------------- 1 | mob: 2 | ==: com.wynnlab.entities.WynnMob 3 | name: '&cDummy' 4 | mob_type: VINDICATOR 5 | ai: MELEE 6 | level: 0 7 | health: 100000 8 | regen: 0 9 | damage: 0-0 10 | attack_speed: 1 11 | speed: .2 12 | vision: 10 13 | defense: 0 14 | equipment: 15 | ==: com.wynnlab.entities.WynnMob$Equipment 16 | main_hand: 17 | ==: org.bukkit.inventory.ItemStack 18 | type: IRON_AXE 19 | spells: 20 | - ==: com.wynnlab.spells.MobSpell 21 | name: Pull 22 | max_tick: 0 23 | script: pull.ws2 24 | - ==: com.wynnlab.spells.MobSpell 25 | name: BBPull 26 | max_tick: 0 27 | has_boss_bar: true 28 | script: pull.ws2 -------------------------------------------------------------------------------- /src/main/resources/mobs/scripts/pull.ws2: -------------------------------------------------------------------------------- 1 | # MobSpell 2 | 3 | function tick(t, caster, target) { 4 | target.player.velocity = caster.location.clone().subtract(target.location).toVector(); 5 | } -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: WynnLab 2 | version: @VERSION@ 3 | main: com.wynnlab.Main 4 | depend: [ KBukkit, WynnLabAPI, WynnScript2, PyBukkit ] 5 | authors: [ Siinus ] 6 | description: Wynncraft systematic recreation @API@ 7 | api-version: @API@ 8 | prefix: WynnLab 9 | website: wynnlab.com 10 | commands: 11 | class: 12 | description: Select your Wynncraft class 13 | usage: /class [] 14 | item: 15 | description: Give yourself a Wynncraft item 16 | usage: /item ... 17 | cast: 18 | description: Cast a spell 19 | usage: /cast 20 | rank: 21 | description: Apply the rank to the player 22 | usage: /rank [] 23 | itemdata: 24 | description: Get the metadata of an item 25 | usage: /itemdata [] 26 | getid: 27 | description: Get the identification sum of a player 28 | usage: /getid [] 29 | script: 30 | description: Executes a script 31 | usage: /script 32 | msg: 33 | description: Message a single player 34 | usage: /msg 35 | r: 36 | description: Reply to your current conversation 37 | usage: /r 38 | party: 39 | description: Manage a party 40 | usage: /party create|invite|join|leave 41 | p: 42 | description: Send a message to your party 43 | usage: /p 44 | dummy: 45 | description: Spawns a dummy 46 | usage: /dummy 47 | upload: 48 | description: Uploads a file 49 | usage: /upload item|mob|mob_spell|music/*|file*/ 50 | wlrl: 51 | description: WynnLab reload 52 | usage: /wlrl (mobs|mob |classes|class ) 53 | mob: 54 | description: Spawn a WynnLab mob 55 | usage: /mob 56 | pvp: 57 | description: Toggle pvp 58 | usage: /pvp 59 | hub: 60 | description: Go to the hub 61 | usage: /hub 62 | leave: 63 | description: Leave the game you're in 64 | usage: /leave 65 | aliases: [ l ] 66 | stats: 67 | description: Show your stats in the current game mode 68 | usage: /stats [] 69 | build: 70 | description: Builds actions 71 | usage: /build (save |equip |delete |publish ...|show) -------------------------------------------------------------------------------- /src/test/kotlin/Optional performance.kt: -------------------------------------------------------------------------------- 1 | fun main() { 2 | val o = Optional("Hi") 3 | val t1 = System.nanoTime() 4 | repeat(100) { 5 | val l = o.ifSome1 { it.length } 6 | } 7 | val t2 = System.nanoTime() 8 | repeat(100) { 9 | val l = o.ifSome2 { it.length } 10 | } 11 | val t3 = System.nanoTime() 12 | println(t2 - t1) 13 | println(t3 - t2) 14 | } 15 | 16 | sealed class Optional { 17 | class Some(val value: T) : Optional() { 18 | override fun ifSome1(block: (T) -> R) = Some(block(value)) 19 | override infix fun or1(block: () -> T): T = value 20 | override fun toString(): String = value.toString() 21 | } 22 | 23 | class None : Optional() { 24 | override fun ifSome1(block: (T) -> R): Optional = None() 25 | override infix fun or1(block: () -> T): T = block() 26 | override fun toString(): String = "NONE" 27 | } 28 | 29 | abstract fun ifSome1(block: (T) -> R): Optional 30 | 31 | inline fun ifSome2(block: (T) -> R): Optional = when (this) { 32 | is Some -> Some(block(value)) 33 | is None -> None() 34 | } 35 | 36 | abstract infix fun or1(block: () -> T): T 37 | 38 | inline infix fun or2(block: () -> T): T = when (this) { 39 | is Some -> value 40 | is None -> block() 41 | } 42 | 43 | companion object { 44 | operator fun invoke(nullable: T?): Optional = nullable?.let { Some(it) } ?: None() 45 | } 46 | } -------------------------------------------------------------------------------- /src/test/kotlin/Optional test.kt: -------------------------------------------------------------------------------- 1 | import com.wynnlab.util.Optional 2 | import com.wynnlab.util.optionalAs 3 | 4 | fun main() { 5 | val some: Optional = Optional("Hello") 6 | val none: Optional = Optional(null) 7 | 8 | println(some) 9 | println(none) 10 | 11 | val l1 = some.ifSome { it.length } 12 | val l2 = none.ifSome { it.length } 13 | 14 | println(l1) 15 | println(l2) 16 | 17 | val any1: Any = "Any" 18 | val any2: Any? = null 19 | val a1Opt = any1.optionalAs() 20 | val a2Opt = any2.optionalAs() 21 | 22 | println(a1Opt) 23 | println(a2Opt) 24 | } -------------------------------------------------------------------------------- /src/test/kotlin/api test.kt: -------------------------------------------------------------------------------- 1 | import com.wynnlab.items.getAPIResults 2 | 3 | fun main() { 4 | val items = getAPIResults("Crusade") 5 | print(items) 6 | 7 | //val wynnItem = WynnItem.parse(items[0]) 8 | //print(wynnItem) 9 | } -------------------------------------------------------------------------------- /src/test/kotlin/jstest.kt: -------------------------------------------------------------------------------- 1 | import javax.script.ScriptEngineManager 2 | 3 | fun main() { 4 | val js = ScriptEngineManager().getEngineByName("javascript") 5 | //js.eval("var a = Java.type(\"p.IC\");") 6 | println(js.get("Java")::class.java) 7 | /*js.eval(""" 8 | function tick() { 9 | print(this.str); 10 | } 11 | """.trimIndent()) 12 | val tick1 = js.get("tick").also { println(it::class.java.name) } 13 | js.eval(""" 14 | function tick() { 15 | print("2: "+this.str); 16 | } 17 | """.trimIndent()) 18 | val tick2 = js.get("tick").also { println(it::class.java.name) } 19 | js.eval("tick()") 20 | (tick1 as ScriptObjectMirror).call(null) 21 | println(js["no"])*/ 22 | /*val obj = TestT("1") { 23 | tick.call(this) 24 | } 25 | obj.start() 26 | val obj2 = TestT("2") { 27 | tick.call(this) 28 | } 29 | obj2.start()*/ 30 | /*js.put("coll", listOf("a", "b", "c") as Collection) 31 | js.eval(""" 32 | coll.forEach(function (it) { 33 | print(it); 34 | }); 35 | """.trimIndent())*/ 36 | /*js.put("IC", p.IC::class.java) 37 | js.eval("print(IC)")*/ 38 | /*js.put("_ac", ::acceptClass) 39 | js.eval("function ac(clazz) { _ac.invoke(clazz); }") 40 | js.eval("ac(Java.type(\"p.IC\"))")*/ 41 | } 42 | 43 | fun acceptClass(c: Class<*>) { 44 | print("Class: ${c.name}") 45 | } 46 | 47 | class TestT(val str: String, val runnable: TestT.() -> Unit) : Thread() { 48 | override fun run() { 49 | repeat(10) { 50 | this.runnable() 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/test/kotlin/p/IC.kt: -------------------------------------------------------------------------------- 1 | package p 2 | 3 | data class IC(var i: Int) { 4 | data class U(val a: String) 5 | } 6 | 7 | data class FC(var f: Float) 8 | 9 | fun acceptClass(clazz: Class) { 10 | println(clazz.interfaces.contentToString()) 11 | } 12 | 13 | class Predicate(test: (T) -> Boolean): java.util.function.Predicate by java.util.function.Predicate(test) -------------------------------------------------------------------------------- /src/test/kotlin/scripting.kt: -------------------------------------------------------------------------------- 1 | import org.python.util.PythonInterpreter 2 | import java.util.function.Predicate 3 | 4 | fun main() { 5 | val pythonInterpreter = PythonInterpreter() 6 | pythonInterpreter.use { py -> 7 | py.setOut(System.out) 8 | 9 | val code = py.compile(""" 10 | def doSth(ic): 11 | print(ic) 12 | True 13 | 14 | #s = S(Predicate(lambda a: doSth(a))) 15 | 16 | #s.fn.invoke('Hi') 17 | """.trimIndent()) 18 | 19 | py.set("S", S::class.java) 20 | py.set("Predicate", p.Predicate::class.java) 21 | 22 | py.exec(code) 23 | println(py.get("doSth")::class.java) 24 | } 25 | } 26 | 27 | fun PythonInterpreter.print(name: String) { 28 | val value = get(name) 29 | println("${value::class.simpleName} $name = $value") 30 | } 31 | 32 | class S(val fn: Predicate) 33 | 34 | fun echo(it: String) = println(it) 35 | 36 | data class IC(val i: Int) 37 | 38 | fun interface Tick { 39 | fun tick() 40 | } --------------------------------------------------------------------------------