mirror of
https://github.com/Auxilor/EcoMobs.git
synced 2025-12-19 23:19:17 +00:00
Compare commits
274 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a7e6e9ff1 | ||
|
|
b59e54be01 | ||
|
|
d26f0294cc | ||
|
|
150433d46b | ||
|
|
7de4d75c93 | ||
|
|
9790459a26 | ||
|
|
666a80b401 | ||
|
|
59810059aa | ||
|
|
7b604c7812 | ||
|
|
81eab18e42 | ||
|
|
fa54c7022b | ||
|
|
26f976a7ca | ||
|
|
4fa070dabe | ||
|
|
f73327b204 | ||
|
|
d9b702f2f1 | ||
|
|
7692e84a60 | ||
|
|
ffd6037e73 | ||
|
|
7c959d7221 | ||
|
|
91ad33334d | ||
|
|
c1b8ed5b48 | ||
|
|
2f3c5f60a4 | ||
|
|
f3387668e6 | ||
|
|
b62e79d904 | ||
|
|
d7afeecc27 | ||
|
|
72e61940c5 | ||
|
|
245445473b | ||
|
|
46772ac97a | ||
|
|
29a1e541a2 | ||
|
|
89a6bc97b7 | ||
|
|
c59707e6ac | ||
|
|
99bc2a04ab | ||
|
|
b4e90d9bda | ||
|
|
72c3722429 | ||
|
|
c14b2f0a80 | ||
|
|
0b6c7152e8 | ||
|
|
6e551eeaeb | ||
|
|
d5610ae804 | ||
|
|
79c8ed4992 | ||
|
|
947a0f3c6d | ||
|
|
ce8b0af155 | ||
|
|
a41e5b702d | ||
|
|
f04bf3aeea | ||
|
|
08941461c9 | ||
|
|
743dbac656 | ||
|
|
2e8d1ea4cc | ||
|
|
d31a98fd99 | ||
|
|
f7244a7d7f | ||
|
|
268ed76951 | ||
|
|
d0ccb78c17 | ||
|
|
34de040849 | ||
|
|
6b01f8e64a | ||
|
|
2a4d5a8fd2 | ||
|
|
f9d7315fd3 | ||
|
|
497f42ccc6 | ||
|
|
d149eb7907 | ||
|
|
47277d0dd8 | ||
|
|
f307f13d1e | ||
|
|
ac3370c0be | ||
|
|
4f616ac8c8 | ||
|
|
24256e9789 | ||
|
|
bbf20e77d0 | ||
|
|
8a506c015b | ||
|
|
744883630d | ||
|
|
8519f4fc23 | ||
|
|
d1cb11ef79 | ||
|
|
edcc185b58 | ||
|
|
ab6d297222 | ||
|
|
9626588c66 | ||
|
|
c4eda19d78 | ||
|
|
691326577a | ||
|
|
e2086387e7 | ||
|
|
13a72f849d | ||
|
|
6346975e77 | ||
|
|
0d846d9dff | ||
|
|
31610383c4 | ||
|
|
d7c16ad3cc | ||
|
|
afe9095276 | ||
|
|
31a782581f | ||
|
|
8aad221450 | ||
|
|
b0bff24263 | ||
|
|
04b00fa01b | ||
|
|
276ba4616a | ||
|
|
d8e5fb9cd0 | ||
|
|
9f05a6504a | ||
|
|
322a6bb41b | ||
|
|
4dbc8afdf4 | ||
|
|
7ffa6ff4f4 | ||
|
|
3769684bb0 | ||
|
|
7bb931e027 | ||
|
|
879d6dd72d | ||
|
|
0a4aff45ad | ||
|
|
5929da1f48 | ||
|
|
6db5de581b | ||
|
|
9ce1bb7ddf | ||
|
|
351d34de9f | ||
|
|
4d2b726aa0 | ||
|
|
ff20b70784 | ||
|
|
f31cd20200 | ||
|
|
0ad2d3cfc7 | ||
|
|
ccc7c5797a | ||
|
|
a218fa96c0 | ||
|
|
13c0a4d83a | ||
|
|
62e7177b1b | ||
|
|
752b30b4a2 | ||
|
|
be4d6156e3 | ||
|
|
fed6dcafd7 | ||
|
|
36f944c58c | ||
|
|
1bc35656fe | ||
|
|
1216e83a39 | ||
|
|
4723c7982c | ||
|
|
8ba3c7834c | ||
|
|
76530a1617 | ||
|
|
bf41554846 | ||
|
|
a741c78b6b | ||
|
|
0f8dce74da | ||
|
|
0d31556b84 | ||
|
|
f8544c284e | ||
|
|
512a477fc6 | ||
|
|
8a1b473837 | ||
|
|
7464133c74 | ||
|
|
1e00b28a8b | ||
|
|
b152313f87 | ||
|
|
ec6d7175b9 | ||
|
|
804a0e88b9 | ||
|
|
ff2de5aebe | ||
|
|
990ad363eb | ||
|
|
d958b94fb0 | ||
|
|
e4f2a91968 | ||
|
|
f1d50d6222 | ||
|
|
035550db06 | ||
|
|
f4bd64c192 | ||
|
|
4b8e1c0579 | ||
|
|
d8cf08eb25 | ||
|
|
a94c96e5d4 | ||
|
|
dddf2d8a20 | ||
|
|
7e67620c8c | ||
|
|
8c44303cdc | ||
|
|
97c1045243 | ||
|
|
c47019f3c5 | ||
|
|
1ffedfcb2e | ||
|
|
17705e9fdb | ||
|
|
7087feefbc | ||
|
|
31504975ce | ||
|
|
142894c0f4 | ||
|
|
1babbcb377 | ||
|
|
87ca7e3718 | ||
|
|
aee2b376c4 | ||
|
|
6ca3441f3b | ||
|
|
af1eb8d27c | ||
|
|
db3bc38e9c | ||
|
|
f7961ba7f3 | ||
|
|
4765b20d20 | ||
|
|
64b22a17d6 | ||
|
|
b1ad28eee4 | ||
|
|
f6f9fb3c1d | ||
|
|
4093fa92bd | ||
|
|
96a6c3d700 | ||
|
|
61de345aec | ||
|
|
68b5886505 | ||
|
|
f768890e46 | ||
|
|
8f12af5d49 | ||
|
|
28c0162a5e | ||
|
|
3360ceddca | ||
|
|
e575df9f37 | ||
|
|
474b9bcffd | ||
|
|
d583167dbb | ||
|
|
baa2b6718e | ||
|
|
03efa137f4 | ||
|
|
765b65343a | ||
|
|
172a345b87 | ||
|
|
b1a3c03181 | ||
|
|
e39c01a4a2 | ||
|
|
24e5b6d2f4 | ||
|
|
4ff099ab45 | ||
|
|
055d792168 | ||
|
|
a355b55ff2 | ||
|
|
6ac3001e52 | ||
|
|
0f04ca86d9 | ||
|
|
f7422b012d | ||
|
|
d95de6926e | ||
|
|
ab13053987 | ||
|
|
ab23e19804 | ||
|
|
c4a04ed048 | ||
|
|
b6941baa50 | ||
|
|
0a1cc72afc | ||
|
|
086f50b0b6 | ||
|
|
bd51eb9d7d | ||
|
|
95462086d2 | ||
|
|
39df2c9c6d | ||
|
|
a6713661a2 | ||
|
|
a995568485 | ||
|
|
470f39da09 | ||
|
|
b13bcdd14c | ||
|
|
97a07f31bf | ||
|
|
d4134b4443 | ||
|
|
770ee369e5 | ||
|
|
978022df6e | ||
|
|
58a05b41c6 | ||
|
|
ec2bed91c4 | ||
|
|
041ec1c79e | ||
|
|
f0b09c035e | ||
|
|
4c6ac852aa | ||
|
|
9772081d7b | ||
|
|
cea2d96819 | ||
|
|
9dbba3f751 | ||
|
|
9cecb33b04 | ||
|
|
7b60749b88 | ||
|
|
e0d03cc8ed | ||
|
|
80109fc061 | ||
|
|
c1fc918757 | ||
|
|
955a378b98 | ||
|
|
a1875933c8 | ||
|
|
cf3c302513 | ||
|
|
2acdc4a74e | ||
|
|
0e2cdb71cb | ||
|
|
f1c26763e0 | ||
|
|
b75b83aebf | ||
|
|
ea2b14fbec | ||
|
|
0747a0a3d4 | ||
|
|
260aec8ba4 | ||
|
|
77985e5a23 | ||
|
|
201ec4161b | ||
|
|
468b0b4292 | ||
|
|
203bec560e | ||
|
|
a2c8b73dbc | ||
|
|
31ccdf2589 | ||
|
|
7ea1f8938b | ||
|
|
436e833213 | ||
|
|
60b4c1c246 | ||
|
|
c5f5032e17 | ||
|
|
310ace62b3 | ||
|
|
0af79cfc27 | ||
|
|
a107d78937 | ||
|
|
d8c229d4fa | ||
|
|
406601a193 | ||
|
|
fb9fdacb9f | ||
|
|
45bbc668dc | ||
|
|
b5f222976b | ||
|
|
10d297e0da | ||
|
|
76df0fd2ef | ||
|
|
56b76f70c6 | ||
|
|
30e0ed02a4 | ||
|
|
2795fa8220 | ||
|
|
cbeff28dbf | ||
|
|
38dd7ea604 | ||
|
|
af72bfbbb6 | ||
|
|
de675b49be | ||
|
|
3df4cfaae7 | ||
|
|
32ac455720 | ||
|
|
89a7d37d37 | ||
|
|
04eff9d3f3 | ||
|
|
c3c96a6892 | ||
|
|
d135922dc1 | ||
|
|
1569d12b44 | ||
|
|
aea6e5c2f1 | ||
|
|
d837311ae2 | ||
|
|
c66b914104 | ||
|
|
1f73b9acf7 | ||
|
|
cafb41567f | ||
|
|
8f912abf31 | ||
|
|
2fe8c9197d | ||
|
|
46eccfc345 | ||
|
|
7804cebd53 | ||
|
|
1918a46678 | ||
|
|
99de824b04 | ||
|
|
b18eb3942a | ||
|
|
7434bbb38e | ||
|
|
7bf88ed09a | ||
|
|
d8f54cb9f6 | ||
|
|
3bc5ed6f6a | ||
|
|
ab759afe56 | ||
|
|
3ae961c9c5 | ||
|
|
b6754c6d5c | ||
|
|
846b03d8bc |
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Auxilor Community Discord
|
||||
url: https://discord.gg/ZcwpSsE/
|
||||
about: Join the Auxilor discord to get help from support staff and the general community!
|
||||
- name: The most common issues people have
|
||||
url: https://github.com/Auxilor/eco/issues/78
|
||||
about: Check the list of known common issues to see if your issue has already been solved
|
||||
31
.github/ISSUE_TEMPLATE/report-a-bug.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/report-a-bug.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Report a Bug
|
||||
about: Report an issue with the plugin
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Server Information (please complete the following information):**
|
||||
- Version: (output of `/ver` command)
|
||||
- Version of plugin and eco (`/ver eco`, `/ver <plugin>`)
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/request-a-feature.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/request-a-feature.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Request a Feature
|
||||
about: Suggest an idea for this plugin
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
17
README.md
17
README.md
@@ -1,14 +1,14 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<img src="https://i.imgur.com/I74yjwu.png" alt="EcoBosses logo" width="256">
|
||||
<img src="https://i.imgur.com/3n3ssb4.png" alt="EcoBosses logo" width="256">
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<h4 align="center">Source code for EcoBosses, a premium spigot plugin.</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.spigotmc.org/resources/ecobosses.79573/">
|
||||
<img alt="spigot" src="https://img.shields.io/badge/spigot-ecobosses-blue?style=for-the-badge"/>
|
||||
<a href="https://polymart.org/resource/1-16-1-17-ecobosses.525">
|
||||
<img alt="spigot" src="https://img.shields.io/badge/polymart-ecobosses-blue?style=for-the-badge"/>
|
||||
</a>
|
||||
<a href="https://bstats.org/plugin/bukkit/EcoBosses" alt="bstats servers">
|
||||
<img src="https://img.shields.io/bstats/servers/10635?color=blue&style=for-the-badge"/>
|
||||
@@ -29,3 +29,14 @@
|
||||
|
||||
## License
|
||||
*Click here to read [the entire license](https://github.com/Auxilor/EcoBosses/blob/master/LICENSE.md).*
|
||||
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="http://gamersupps.gg/discount/Auxilor?afmc=Auxilor" target="_blank">
|
||||
<img src="https://i.imgur.com/uFDpBAC.png" alt="supps banner">
|
||||
</a>
|
||||
<a href="https://dedimc.promo/Auxilor" target="_blank">
|
||||
<img src="https://i.imgur.com/zdDLhFA.png" alt="dedimc banner">
|
||||
</a>
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
55
build.gradle
55
build.gradle
@@ -1,3 +1,13 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
@@ -11,6 +21,7 @@ dependencies {
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
@@ -45,16 +56,19 @@ allprojects {
|
||||
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate('com.willfp.libreforge', 'com.willfp.ecobosses.libreforge')
|
||||
relocate('org.joml', 'com.willfp.ecobosses.libreforge.joml')
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'com.willfp:eco:6.0.0'
|
||||
compileOnly 'com.willfp:eco:6.35.1'
|
||||
implementation 'com.willfp:libreforge:3.72.0'
|
||||
implementation 'org.joml:joml:1.10.4'
|
||||
|
||||
compileOnly 'org.jetbrains:annotations:19.0.0'
|
||||
compileOnly 'org.jetbrains:annotations:23.0.0'
|
||||
|
||||
compileOnly 'org.projectlombok:lombok:1.18.20'
|
||||
annotationProcessor 'org.projectlombok:lombok:1.18.20'
|
||||
|
||||
testCompileOnly 'org.projectlombok:lombok:1.18.20'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'
|
||||
compileOnly 'org.jetbrains.kotlin:kotlin-stdlib:1.6.21'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
@@ -63,13 +77,24 @@ allprojects {
|
||||
}
|
||||
|
||||
processResources {
|
||||
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**"]) {
|
||||
filesNotMatching(["**/*.png", "**/models/**", "**/textures/**", "**lang.yml"]) {
|
||||
expand projectVersion: project.version
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
|
||||
java.sourceCompatibility = JavaVersion.VERSION_17
|
||||
java.targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
compileJava.dependsOn clean
|
||||
|
||||
build.dependsOn shadowJar
|
||||
}
|
||||
|
||||
tasks.withType(Jar) {
|
||||
@@ -91,8 +116,20 @@ jar {
|
||||
group = 'com.willfp'
|
||||
archivesBaseName = project.name
|
||||
version = findProperty("version")
|
||||
java.sourceCompatibility = JavaVersion.VERSION_16
|
||||
|
||||
compileJava.options.encoding = 'UTF-8'
|
||||
|
||||
build.dependsOn shadowJar
|
||||
build.dependsOn publishToMavenLocal
|
||||
|
||||
task buyThePlugins {
|
||||
dependsOn subprojects.build
|
||||
|
||||
doLast {
|
||||
println 'If you like the plugin, please consider buying it on Spigot or Polymart!'
|
||||
println 'Spigot: https://www.spigotmc.org/resources/authors/auxilor.507394/'
|
||||
println 'Polymart: https://polymart.org/user/auxilor.1107/'
|
||||
println 'Buying gives you access to support and the plugin auto-updater, and it allows me to keep developing plugins.'
|
||||
}
|
||||
}
|
||||
build.finalizedBy buyThePlugins
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
version rootProject.version
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
subprojects {
|
||||
dependencies {
|
||||
compileOnly project(':eco-core:core-proxy')
|
||||
compileOnly project(':eco-core:core-plugin')
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.spigotmc:spigot:1.16.1-R0.1-SNAPSHOT'
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_16_R1;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
|
||||
@Override
|
||||
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
|
||||
@NotNull final Location location) {
|
||||
if (entityClass.equals(CustomIllusionerProxy.class)) {
|
||||
return (T) CustomIllusioner.spawn(location);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_16_R1;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import net.minecraft.server.v1_16_R1.EntityHuman;
|
||||
import net.minecraft.server.v1_16_R1.EntityIllagerIllusioner;
|
||||
import net.minecraft.server.v1_16_R1.EntityIllagerWizard;
|
||||
import net.minecraft.server.v1_16_R1.EntityInsentient;
|
||||
import net.minecraft.server.v1_16_R1.EntityIronGolem;
|
||||
import net.minecraft.server.v1_16_R1.EntityRaider;
|
||||
import net.minecraft.server.v1_16_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R1.EntityVillagerAbstract;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalBowShoot;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalFloat;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalHurtByTarget;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalLookAtPlayer;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalMeleeAttack;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalNearestAttackableTarget;
|
||||
import net.minecraft.server.v1_16_R1.PathfinderGoalRandomStroll;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.entity.Illusioner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
|
||||
/**
|
||||
* Instantiate a new custom illusioner entity.
|
||||
*
|
||||
* @param location The location to spawn it at.
|
||||
*/
|
||||
public CustomIllusioner(@NotNull final Location location) {
|
||||
super(EntityTypes.ILLUSIONER, ((CraftWorld) location.getWorld()).getHandle());
|
||||
|
||||
this.setPosition(location.getX(), location.getY(), location.getZ());
|
||||
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(1, new EntityIllagerWizard.b());
|
||||
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
|
||||
this.goalSelector.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
|
||||
this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
|
||||
this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
|
||||
this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
|
||||
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
|
||||
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn illusioner.
|
||||
*
|
||||
* @param location The location.
|
||||
* @return The illusioner.
|
||||
*/
|
||||
public static Illusioner spawn(@NotNull final Location location) {
|
||||
CustomIllusioner illusioner = new CustomIllusioner(location);
|
||||
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
|
||||
return (Illusioner) illusioner.getBukkitEntity();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.spigotmc:spigot:1.16.3-R0.1-SNAPSHOT'
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_16_R2;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
|
||||
@Override
|
||||
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
|
||||
@NotNull final Location location) {
|
||||
if (entityClass.equals(CustomIllusionerProxy.class)) {
|
||||
return (T) CustomIllusioner.spawn(location);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_16_R2;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import net.minecraft.server.v1_16_R2.EntityHuman;
|
||||
import net.minecraft.server.v1_16_R2.EntityIllagerIllusioner;
|
||||
import net.minecraft.server.v1_16_R2.EntityIllagerWizard;
|
||||
import net.minecraft.server.v1_16_R2.EntityInsentient;
|
||||
import net.minecraft.server.v1_16_R2.EntityIronGolem;
|
||||
import net.minecraft.server.v1_16_R2.EntityRaider;
|
||||
import net.minecraft.server.v1_16_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R2.EntityVillagerAbstract;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalBowShoot;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalFloat;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalHurtByTarget;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalLookAtPlayer;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalMeleeAttack;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalNearestAttackableTarget;
|
||||
import net.minecraft.server.v1_16_R2.PathfinderGoalRandomStroll;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.entity.Illusioner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
|
||||
/**
|
||||
* Instantiate a new custom illusioner entity.
|
||||
*
|
||||
* @param location The location to spawn it at.
|
||||
*/
|
||||
public CustomIllusioner(@NotNull final Location location) {
|
||||
super(EntityTypes.ILLUSIONER, ((CraftWorld) location.getWorld()).getHandle());
|
||||
|
||||
this.setPosition(location.getX(), location.getY(), location.getZ());
|
||||
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(1, new EntityIllagerWizard.b());
|
||||
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
|
||||
this.goalSelector.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
|
||||
this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
|
||||
this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
|
||||
this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
|
||||
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
|
||||
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn illusioner.
|
||||
*
|
||||
* @param location The location.
|
||||
* @return The illusioner.
|
||||
*/
|
||||
public static Illusioner spawn(@NotNull final Location location) {
|
||||
CustomIllusioner illusioner = new CustomIllusioner(location);
|
||||
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
|
||||
return (Illusioner) illusioner.getBukkitEntity();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.spigotmc:spigot:1.16.4-R0.1-SNAPSHOT'
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_16_R3;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
|
||||
@Override
|
||||
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
|
||||
@NotNull final Location location) {
|
||||
if (entityClass.equals(CustomIllusionerProxy.class)) {
|
||||
return (T) CustomIllusioner.spawn(location);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_16_R3;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import net.minecraft.server.v1_16_R3.EntityHuman;
|
||||
import net.minecraft.server.v1_16_R3.EntityIllagerIllusioner;
|
||||
import net.minecraft.server.v1_16_R3.EntityIllagerWizard;
|
||||
import net.minecraft.server.v1_16_R3.EntityInsentient;
|
||||
import net.minecraft.server.v1_16_R3.EntityIronGolem;
|
||||
import net.minecraft.server.v1_16_R3.EntityRaider;
|
||||
import net.minecraft.server.v1_16_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R3.EntityVillagerAbstract;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalBowShoot;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalFloat;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalHurtByTarget;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalLookAtPlayer;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalMeleeAttack;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalNearestAttackableTarget;
|
||||
import net.minecraft.server.v1_16_R3.PathfinderGoalRandomStroll;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.entity.Illusioner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
|
||||
/**
|
||||
* Instantiate a new custom illusioner entity.
|
||||
*
|
||||
* @param location The location to spawn it at.
|
||||
*/
|
||||
public CustomIllusioner(@NotNull final Location location) {
|
||||
super(EntityTypes.ILLUSIONER, ((CraftWorld) location.getWorld()).getHandle());
|
||||
|
||||
this.setPosition(location.getX(), location.getY(), location.getZ());
|
||||
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(1, new EntityIllagerWizard.b());
|
||||
this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
|
||||
this.goalSelector.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.goalSelector.a(0, new PathfinderGoalFloat(this));
|
||||
this.goalSelector.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
|
||||
this.goalSelector.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.goalSelector.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
|
||||
this.goalSelector.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
|
||||
this.targetSelector.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
|
||||
this.targetSelector.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
|
||||
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
|
||||
this.targetSelector.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn illusioner.
|
||||
*
|
||||
* @param location The location.
|
||||
* @return The illusioner.
|
||||
*/
|
||||
public static Illusioner spawn(@NotNull final Location location) {
|
||||
CustomIllusioner illusioner = new CustomIllusioner(location);
|
||||
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
|
||||
return (Illusioner) illusioner.getBukkitEntity();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.spigotmc:spigot:1.17-R0.1-SNAPSHOT'
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_17_R1;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CustomEntitySpawner implements CustomEntitySpawnerProxy {
|
||||
@Override
|
||||
public <T extends LivingEntity> @Nullable T spawnCustomEntity(final Class<? extends CustomEntity<? extends LivingEntity>> entityClass,
|
||||
@NotNull final Location location) {
|
||||
if (entityClass.equals(CustomIllusionerProxy.class)) {
|
||||
return (T) CustomIllusioner.spawn(location);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package com.willfp.ecobosses.proxy.v1_17_R1;
|
||||
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomIllusionerProxy;
|
||||
import net.minecraft.world.entity.EntityInsentient;
|
||||
import net.minecraft.world.entity.EntityTypes;
|
||||
import net.minecraft.world.entity.ai.goal.PathfinderGoalBowShoot;
|
||||
import net.minecraft.world.entity.ai.goal.PathfinderGoalFloat;
|
||||
import net.minecraft.world.entity.ai.goal.PathfinderGoalLookAtPlayer;
|
||||
import net.minecraft.world.entity.ai.goal.PathfinderGoalMeleeAttack;
|
||||
import net.minecraft.world.entity.ai.goal.PathfinderGoalRandomStroll;
|
||||
import net.minecraft.world.entity.ai.goal.target.PathfinderGoalHurtByTarget;
|
||||
import net.minecraft.world.entity.ai.goal.target.PathfinderGoalNearestAttackableTarget;
|
||||
import net.minecraft.world.entity.animal.EntityIronGolem;
|
||||
import net.minecraft.world.entity.monster.EntityIllagerIllusioner;
|
||||
import net.minecraft.world.entity.monster.EntityIllagerWizard;
|
||||
import net.minecraft.world.entity.npc.EntityVillagerAbstract;
|
||||
import net.minecraft.world.entity.player.EntityHuman;
|
||||
import net.minecraft.world.entity.raid.EntityRaider;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
||||
import org.bukkit.entity.Illusioner;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CustomIllusioner extends EntityIllagerIllusioner implements CustomIllusionerProxy {
|
||||
/**
|
||||
* Instantiate a new custom illusioner entity.
|
||||
*
|
||||
* @param location The location to spawn it at.
|
||||
*/
|
||||
public CustomIllusioner(@NotNull final Location location) {
|
||||
super(EntityTypes.O, ((CraftWorld) location.getWorld()).getHandle());
|
||||
|
||||
this.setPosition(location.getX(), location.getY(), location.getZ());
|
||||
|
||||
this.bO.a(0, new PathfinderGoalFloat(this));
|
||||
this.bO.a(1, new EntityIllagerWizard.b());
|
||||
this.bO.a(2, new PathfinderGoalMeleeAttack(this, 1.0D, false));
|
||||
this.bO.a(2, new PathfinderGoalBowShoot<>(this, 1.0D, 20, 15.0F));
|
||||
this.bO.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.bO.a(0, new PathfinderGoalFloat(this));
|
||||
this.bO.a(6, new PathfinderGoalBowShoot<>(this, 0.5D, 20, 15.0F));
|
||||
this.bO.a(8, new PathfinderGoalRandomStroll(this, 0.6D));
|
||||
this.bO.a(9, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 3.0F, 1.0F));
|
||||
this.bO.a(10, new PathfinderGoalLookAtPlayer(this, EntityInsentient.class, 8.0F));
|
||||
this.bP.a(1, (new PathfinderGoalHurtByTarget(this, new Class[]{EntityRaider.class})).a(new Class[0]));
|
||||
this.bP.a(2, (new PathfinderGoalNearestAttackableTarget<>(this, EntityHuman.class, true)).a(300));
|
||||
this.bP.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityVillagerAbstract.class, false)).a(300));
|
||||
this.bP.a(3, (new PathfinderGoalNearestAttackableTarget<>(this, EntityIronGolem.class, false)).a(300));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn illusioner.
|
||||
*
|
||||
* @param location The location.
|
||||
* @return The illusioner.
|
||||
*/
|
||||
public static Illusioner spawn(@NotNull final Location location) {
|
||||
CustomIllusioner illusioner = new CustomIllusioner(location);
|
||||
((CraftWorld) location.getWorld()).getHandle().addEntity(illusioner);
|
||||
return (Illusioner) illusioner.getBukkitEntity();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,7 @@ group 'com.willfp'
|
||||
version rootProject.version
|
||||
|
||||
dependencies {
|
||||
compileOnly project(":eco-core:core-proxy")
|
||||
compileOnly 'org.spigotmc:spigot-api:1.16.4-R0.1-SNAPSHOT'
|
||||
compileOnly 'commons-io:commons-io:2.8.0'
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.16.3-R0.1-SNAPSHOT'
|
||||
}
|
||||
compileOnly 'org.spigotmc:spigot-api:1.17.1-R0.1-SNAPSHOT'
|
||||
compileOnly 'com.github.lokka30:LevelledMobs:3.1.4'
|
||||
compileOnly 'net.kyori:adventure-api:4.9.3'
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.willfp.ecobosses;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.command.impl.PluginCommand;
|
||||
import com.willfp.ecobosses.bosses.listeners.AttackListeners;
|
||||
import com.willfp.ecobosses.bosses.listeners.AutoSpawnTimer;
|
||||
import com.willfp.ecobosses.bosses.listeners.DeathListeners;
|
||||
import com.willfp.ecobosses.bosses.listeners.PassiveListeners;
|
||||
import com.willfp.ecobosses.bosses.listeners.SpawnListeners;
|
||||
import com.willfp.ecobosses.bosses.util.BossUtils;
|
||||
import com.willfp.ecobosses.commands.CommandEcobosses;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class EcoBossesPlugin extends EcoPlugin {
|
||||
/**
|
||||
* Instance of the plugin.
|
||||
*/
|
||||
@Getter
|
||||
private static EcoBossesPlugin instance;
|
||||
|
||||
/**
|
||||
* Internal constructor called by bukkit on plugin load.
|
||||
*/
|
||||
public EcoBossesPlugin() {
|
||||
super(86576, 10635, "com.willfp.ecobosses.proxy", "&9");
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleDisable() {
|
||||
BossUtils.killAllBosses();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleReload() {
|
||||
this.getScheduler().runTimer(new AutoSpawnTimer(), 5, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<PluginCommand> loadPluginCommands() {
|
||||
return Arrays.asList(
|
||||
new CommandEcobosses(this)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Listener> loadListeners() {
|
||||
return Arrays.asList(
|
||||
new AttackListeners(this),
|
||||
new DeathListeners(this),
|
||||
new SpawnListeners(this),
|
||||
new PassiveListeners(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,539 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.eco.core.config.interfaces.Config;
|
||||
import com.willfp.eco.core.tuples.Pair;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import com.willfp.ecobosses.bosses.effects.Effects;
|
||||
import com.willfp.ecobosses.bosses.util.bosstype.BossEntityUtils;
|
||||
import com.willfp.ecobosses.bosses.util.bosstype.BossType;
|
||||
import com.willfp.ecobosses.bosses.util.obj.BossbarProperties;
|
||||
import com.willfp.ecobosses.bosses.util.obj.ExperienceOptions;
|
||||
import com.willfp.ecobosses.bosses.util.obj.ImmunityOptions;
|
||||
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
|
||||
import com.willfp.ecobosses.bosses.util.obj.SpawnTotem;
|
||||
import com.willfp.ecobosses.bosses.util.obj.TargetMode;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EcoBoss extends PluginDependent<EcoPlugin> {
|
||||
/**
|
||||
* The name of the boss.
|
||||
*/
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The config of the set.
|
||||
*/
|
||||
@Getter(AccessLevel.PRIVATE)
|
||||
private final Config config;
|
||||
|
||||
/**
|
||||
* The display name of the boss.
|
||||
*/
|
||||
@Getter
|
||||
private final String displayName;
|
||||
|
||||
/**
|
||||
* The base entity spawner.
|
||||
*/
|
||||
private final BossType bossType;
|
||||
|
||||
/**
|
||||
* If the boss bar is enabled.
|
||||
*/
|
||||
@Getter
|
||||
private final boolean bossbarEnabled;
|
||||
|
||||
/**
|
||||
* The BossBar properties.
|
||||
*/
|
||||
@Getter
|
||||
private final BossbarProperties bossbarProperties;
|
||||
|
||||
/**
|
||||
* If spawn totem is enabled.
|
||||
*/
|
||||
@Getter
|
||||
private final boolean spawnTotemEnabled;
|
||||
|
||||
/**
|
||||
* The spawn totem.
|
||||
*/
|
||||
@Getter
|
||||
private final SpawnTotem spawnTotem;
|
||||
|
||||
/**
|
||||
* Disabled world names for spawn totem.
|
||||
*/
|
||||
@Getter
|
||||
private final List<String> spawnTotemDisabledWorldNames;
|
||||
|
||||
/**
|
||||
* The max health.
|
||||
*/
|
||||
@Getter
|
||||
private final int maxHealth;
|
||||
|
||||
/**
|
||||
* The attack damage.
|
||||
*/
|
||||
@Getter
|
||||
private final int attackDamage;
|
||||
|
||||
|
||||
/**
|
||||
* The follow range.
|
||||
*/
|
||||
@Getter
|
||||
private final double followRange;
|
||||
|
||||
/**
|
||||
* The movement speed multiplier.
|
||||
*/
|
||||
@Getter
|
||||
private final double movementSpeedMultiplier;
|
||||
|
||||
/**
|
||||
* The immunity options.
|
||||
*/
|
||||
@Getter
|
||||
private final ImmunityOptions immunityOptions;
|
||||
|
||||
/**
|
||||
* The drops.
|
||||
*/
|
||||
@Getter
|
||||
private final Map<ItemStack, Double> drops;
|
||||
|
||||
/**
|
||||
* The exp to drop.
|
||||
*/
|
||||
@Getter
|
||||
private final ExperienceOptions experienceOptions;
|
||||
|
||||
/**
|
||||
* If attacks should be called on injury.
|
||||
*/
|
||||
@Getter
|
||||
private final boolean attackOnInjure;
|
||||
|
||||
/**
|
||||
* Sounds played on injure.
|
||||
*/
|
||||
@Getter
|
||||
private final List<OptionedSound> injureSounds;
|
||||
|
||||
/**
|
||||
* Spawn sounds.
|
||||
*/
|
||||
@Getter
|
||||
private final List<OptionedSound> spawnSounds;
|
||||
|
||||
/**
|
||||
* Death sounds.
|
||||
*/
|
||||
@Getter
|
||||
private final List<OptionedSound> deathSounds;
|
||||
|
||||
/**
|
||||
* Summon sounds.
|
||||
*/
|
||||
@Getter
|
||||
private final List<OptionedSound> summonSounds;
|
||||
|
||||
/**
|
||||
* Spawn messages.
|
||||
*/
|
||||
@Getter
|
||||
private final List<String> spawnMessages;
|
||||
|
||||
/**
|
||||
* Death messages.
|
||||
*/
|
||||
@Getter
|
||||
private final List<String> deathMessages;
|
||||
|
||||
/**
|
||||
* Nearby players radius.
|
||||
*/
|
||||
@Getter
|
||||
private final double nearbyRadius;
|
||||
|
||||
/**
|
||||
* Nearby players commands.
|
||||
*/
|
||||
@Getter
|
||||
private final Map<String, Double> nearbyPlayersCommands;
|
||||
|
||||
/**
|
||||
* Top damager commands.
|
||||
*/
|
||||
@Getter
|
||||
private final Map<Integer, List<Pair<Double, String>>> topDamagerCommands;
|
||||
|
||||
/**
|
||||
* Incoming damage multipliers.
|
||||
*/
|
||||
@Getter
|
||||
private final Map<EntityDamageEvent.DamageCause, Double> incomingMultipliers;
|
||||
|
||||
/**
|
||||
* The currently living bosses of this type.
|
||||
*/
|
||||
private final Map<LivingEntity, LivingEcoBoss> livingBosses;
|
||||
|
||||
/**
|
||||
* The effect names and arguments.
|
||||
*/
|
||||
private final Map<String, List<String>> effectNames;
|
||||
|
||||
/**
|
||||
* The target distance.
|
||||
*/
|
||||
@Getter
|
||||
private final double targetDistance;
|
||||
|
||||
/**
|
||||
* The targeting mode.
|
||||
*/
|
||||
@Getter
|
||||
private final TargetMode targetMode;
|
||||
|
||||
/**
|
||||
* If the boss shouldn't get into boats and minecarts.
|
||||
*/
|
||||
@Getter
|
||||
private final boolean disableBoats;
|
||||
|
||||
/**
|
||||
* The time between auto spawns.
|
||||
*/
|
||||
@Getter
|
||||
private final int autoSpawnInterval;
|
||||
|
||||
/**
|
||||
* Locations that the boss can auto spawn at.
|
||||
*/
|
||||
@Getter
|
||||
private final List<Location> autoSpawnLocations;
|
||||
|
||||
/**
|
||||
* Create a new Boss.
|
||||
*
|
||||
* @param name The name of the set.
|
||||
* @param config The set's config.
|
||||
* @param plugin Instance of EcoBosses.
|
||||
*/
|
||||
public EcoBoss(@NotNull final String name,
|
||||
@NotNull final Config config,
|
||||
@NotNull final EcoPlugin plugin) {
|
||||
super(plugin);
|
||||
this.config = config;
|
||||
this.name = name;
|
||||
this.livingBosses = new HashMap<>();
|
||||
|
||||
this.displayName = this.getConfig().getString("name");
|
||||
|
||||
// Boss Type
|
||||
this.bossType = BossEntityUtils.getBossType(this.getConfig().getString("base-mob"));
|
||||
|
||||
// Boss Bar
|
||||
this.bossbarEnabled = this.getConfig().getBool("bossbar.enabled");
|
||||
this.bossbarProperties = new BossbarProperties(
|
||||
BarColor.valueOf(this.getConfig().getString("bossbar.color").toUpperCase()),
|
||||
BarStyle.valueOf(this.getConfig().getString("bossbar.style").toUpperCase())
|
||||
);
|
||||
|
||||
// Attributes
|
||||
this.attackDamage = this.getConfig().getInt("attack-damage");
|
||||
this.maxHealth = this.getConfig().getInt("max-health");
|
||||
this.followRange = this.getConfig().getInt("follow-range");
|
||||
this.movementSpeedMultiplier = this.getConfig().getInt("movement-speed");
|
||||
|
||||
// Spawn Totem
|
||||
this.spawnTotemEnabled = this.getConfig().getBool("spawn-totem.enabled");
|
||||
this.spawnTotem = new SpawnTotem(
|
||||
Material.getMaterial(this.getConfig().getString("spawn-totem.bottom").toUpperCase()),
|
||||
Material.getMaterial(this.getConfig().getString("spawn-totem.middle").toUpperCase()),
|
||||
Material.getMaterial(this.getConfig().getString("spawn-totem.top").toUpperCase())
|
||||
);
|
||||
this.spawnTotemDisabledWorldNames = this.getConfig().getStrings("spawn-totem.world-blacklist").stream().map(String::toLowerCase).collect(Collectors.toList());
|
||||
|
||||
// Rewards
|
||||
this.drops = new HashMap<>();
|
||||
for (String string : this.getConfig().getStrings("rewards.drops")) {
|
||||
YamlConfiguration tempConfig = new YamlConfiguration();
|
||||
double chance = 100;
|
||||
if (string.contains("::")) {
|
||||
String[] split = string.split("::");
|
||||
chance = Double.parseDouble(split[0]);
|
||||
string = split[1];
|
||||
}
|
||||
String tempConfigString = new String(Base64.getDecoder().decode(string));
|
||||
try {
|
||||
tempConfig.loadFromString(tempConfigString);
|
||||
} catch (InvalidConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ItemStack itemStack = tempConfig.getItemStack("drop-key");
|
||||
this.drops.put(itemStack, chance);
|
||||
}
|
||||
|
||||
this.experienceOptions = new ExperienceOptions(
|
||||
this.getConfig().getInt("rewards.xp.minimum"),
|
||||
this.getConfig().getInt("rewards.xp.maximum")
|
||||
);
|
||||
|
||||
// Immunities
|
||||
this.immunityOptions = new ImmunityOptions(
|
||||
this.getConfig().getBool("defence.immunities.fire"),
|
||||
this.getConfig().getBool("defence.immunities.suffocation"),
|
||||
this.getConfig().getBool("defence.immunities.drowning"),
|
||||
this.getConfig().getBool("defence.immunities.projectiles"),
|
||||
this.getConfig().getBool("defence.immunities.explosion")
|
||||
);
|
||||
|
||||
// Multipliers
|
||||
this.incomingMultipliers = new HashMap<>();
|
||||
double melee = this.getConfig().getDouble("defence.incoming-multipliers.melee");
|
||||
this.incomingMultipliers.put(EntityDamageEvent.DamageCause.ENTITY_ATTACK, melee);
|
||||
this.incomingMultipliers.put(EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK, melee);
|
||||
|
||||
double projectile = this.getConfig().getDouble("defence.incoming-multipliers.projectile");
|
||||
this.incomingMultipliers.put(EntityDamageEvent.DamageCause.PROJECTILE, projectile);
|
||||
|
||||
// Attack on injure
|
||||
this.attackOnInjure = this.getConfig().getBool("attacks.on-injure");
|
||||
|
||||
// Sounds
|
||||
this.injureSounds = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("sounds.injure")) {
|
||||
String[] split = string.split(":");
|
||||
this.injureSounds.add(new OptionedSound(
|
||||
Sound.valueOf(split[0].toUpperCase()),
|
||||
Float.parseFloat(split[1]) / 16,
|
||||
Float.parseFloat(split[2])
|
||||
));
|
||||
}
|
||||
|
||||
this.deathSounds = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("sounds.death")) {
|
||||
String[] split = string.split(":");
|
||||
this.deathSounds.add(new OptionedSound(
|
||||
Sound.valueOf(split[0].toUpperCase()),
|
||||
Float.parseFloat(split[1]) / 16,
|
||||
Float.parseFloat(split[2])
|
||||
));
|
||||
}
|
||||
|
||||
this.summonSounds = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("sounds.summon")) {
|
||||
String[] split = string.split(":");
|
||||
this.summonSounds.add(new OptionedSound(
|
||||
Sound.valueOf(split[0].toUpperCase()),
|
||||
Float.parseFloat(split[1]) / 16,
|
||||
Float.parseFloat(split[2])
|
||||
));
|
||||
}
|
||||
|
||||
this.spawnSounds = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("sounds.spawn")) {
|
||||
String[] split = string.split(":");
|
||||
this.spawnSounds.add(new OptionedSound(
|
||||
Sound.valueOf(split[0].toUpperCase()),
|
||||
Float.parseFloat(split[1]) / 16,
|
||||
Float.parseFloat(split[2])
|
||||
));
|
||||
}
|
||||
|
||||
// Messages
|
||||
this.spawnMessages = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("broadcast.spawn")) {
|
||||
this.spawnMessages.add(StringUtils.format(string));
|
||||
}
|
||||
this.deathMessages = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("broadcast.death")) {
|
||||
this.deathMessages.add(StringUtils.format(string));
|
||||
}
|
||||
|
||||
// Top Damager Commands
|
||||
this.topDamagerCommands = new HashMap<>();
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
this.topDamagerCommands.put(i, new ArrayList<>());
|
||||
for (String string : this.getConfig().getStrings("rewards.top-damager-commands." + i, false)) {
|
||||
double chance = 100;
|
||||
if (string.contains("::")) {
|
||||
String[] split = string.split("::");
|
||||
chance = Double.parseDouble(split[0]);
|
||||
string = split[1];
|
||||
}
|
||||
List<Pair<Double, String>> commands = this.topDamagerCommands.get(i) == null ? new ArrayList<>() : this.topDamagerCommands.get(i);
|
||||
commands.add(new Pair<>(chance, string));
|
||||
this.topDamagerCommands.put(i, commands);
|
||||
}
|
||||
}
|
||||
|
||||
// Nearby Rewards
|
||||
this.nearbyRadius = this.getConfig().getDouble("rewards.nearby-player-commands.radius");
|
||||
this.nearbyPlayersCommands = new HashMap<>();
|
||||
for (String string : this.getConfig().getStrings("rewards.nearby-player-commands.commands", false)) {
|
||||
double chance = 100;
|
||||
if (string.contains("::")) {
|
||||
String[] split = string.split("::");
|
||||
chance = Double.parseDouble(split[0]);
|
||||
string = split[1];
|
||||
}
|
||||
this.nearbyPlayersCommands.put(string, chance);
|
||||
}
|
||||
|
||||
// Effects
|
||||
this.effectNames = new HashMap<>();
|
||||
for (String string : this.getConfig().getStrings("effects")) {
|
||||
String effectName = string.split(":")[0];
|
||||
List<String> args = Arrays.asList(string.replace(effectName + ":", "").split(":"));
|
||||
this.effectNames.put(effectName, args);
|
||||
}
|
||||
|
||||
new HashMap<>(this.effectNames).forEach((string, args) -> {
|
||||
if (Effects.getEffect(string, args) == null) {
|
||||
this.effectNames.remove(string);
|
||||
Bukkit.getLogger().warning("Invalid effect specified in " + this.name);
|
||||
}
|
||||
});
|
||||
|
||||
// Targeting
|
||||
this.targetDistance = this.getConfig().getDouble("attacks.target.range");
|
||||
this.targetMode = TargetMode.getByName(this.getConfig().getString("attacks.target.mode"));
|
||||
|
||||
// Boat + Minecarts
|
||||
this.disableBoats = this.getConfig().getBool("defence.no-boats");
|
||||
|
||||
// Auto Spawn
|
||||
this.autoSpawnInterval = this.getConfig().getInt("auto-spawn-interval");
|
||||
this.autoSpawnLocations = new ArrayList<>();
|
||||
for (String string : this.getConfig().getStrings("auto-spawn-locations")) {
|
||||
String[] split = string.split(":");
|
||||
World world = Bukkit.getWorld(split[0]);
|
||||
double x = Double.parseDouble(split[1]);
|
||||
double y = Double.parseDouble(split[2]);
|
||||
double z = Double.parseDouble(split[3]);
|
||||
autoSpawnLocations.add(new Location(world, x, y, z));
|
||||
}
|
||||
|
||||
if (this.getConfig().getBool("enabled")) {
|
||||
EcoBosses.addBoss(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create effect tickers for Living Boss.
|
||||
*
|
||||
* @return The effects.
|
||||
*/
|
||||
public List<Effect> createEffects() {
|
||||
List<Effect> effects = new ArrayList<>();
|
||||
this.effectNames.forEach((string, args) -> {
|
||||
effects.add(Effects.getEffect(string, args));
|
||||
});
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn the boss.
|
||||
*
|
||||
* @param location The location.
|
||||
*/
|
||||
public void spawn(@NotNull final Location location) {
|
||||
location.getChunk().load();
|
||||
|
||||
LivingEntity entity = bossType.spawnBossEntity(location);
|
||||
this.livingBosses.put(entity, new LivingEcoBoss(
|
||||
this.getPlugin(),
|
||||
entity,
|
||||
this
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link LivingEcoBoss} from an entity.
|
||||
*
|
||||
* @param entity The entity.
|
||||
* @return The living boss, or null if not a boss.
|
||||
*/
|
||||
public LivingEcoBoss getLivingBoss(@NotNull final LivingEntity entity) {
|
||||
return this.livingBosses.get(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove living boss.
|
||||
*
|
||||
* @param entity The entity.
|
||||
*/
|
||||
public void removeLivingBoss(@Nullable final LivingEntity entity) {
|
||||
this.livingBosses.remove(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all living bosses.
|
||||
*
|
||||
* @return The living bosses.
|
||||
*/
|
||||
public Map<LivingEntity, LivingEcoBoss> getLivingBosses() {
|
||||
return ImmutableMap.copyOf(this.livingBosses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof EcoBoss boss)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.getName().equals(boss.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EcoBoss{"
|
||||
+ this.getName()
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.willfp.eco.core.config.updating.ConfigUpdater;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import com.willfp.ecobosses.config.BaseBossConfig;
|
||||
import com.willfp.ecobosses.config.CustomConfig;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@UtilityClass
|
||||
public class EcoBosses {
|
||||
/**
|
||||
* Registered armor sets.
|
||||
*/
|
||||
private static final BiMap<String, EcoBoss> BY_NAME = HashBiMap.create();
|
||||
|
||||
/**
|
||||
* Sets that exist by default.
|
||||
*/
|
||||
private static final List<String> DEFAULT_BOSSES = Arrays.asList(
|
||||
"illusioner",
|
||||
"tarantula",
|
||||
"steel_golem",
|
||||
"alpha_wolf"
|
||||
);
|
||||
|
||||
/**
|
||||
* Get all registered {@link EcoBoss}es.
|
||||
*
|
||||
* @return A list of all {@link EcoBoss}es.
|
||||
*/
|
||||
public static List<EcoBoss> values() {
|
||||
return ImmutableList.copyOf(BY_NAME.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link EcoBoss} matching name.
|
||||
*
|
||||
* @param name The name to search for.
|
||||
* @return The matching {@link EcoBoss}, or null if not found.
|
||||
*/
|
||||
public static EcoBoss getByName(@NotNull final String name) {
|
||||
return BY_NAME.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all {@link EcoBoss}s.
|
||||
*/
|
||||
@ConfigUpdater
|
||||
public static void update() {
|
||||
for (EcoBoss boss : values()) {
|
||||
removeBoss(boss);
|
||||
}
|
||||
|
||||
for (String defaultSetName : DEFAULT_BOSSES) {
|
||||
new EcoBoss(defaultSetName, new BaseBossConfig(defaultSetName), EcoBossesPlugin.getInstance());
|
||||
}
|
||||
|
||||
try {
|
||||
Files.walk(Paths.get(new File(EcoBossesPlugin.getInstance().getDataFolder(), "bosses/").toURI()))
|
||||
.filter(Files::isRegularFile)
|
||||
.forEach(path -> {
|
||||
String name = path.getFileName().toString().replace(".yml", "");
|
||||
new EcoBoss(
|
||||
name,
|
||||
new CustomConfig(name, YamlConfiguration.loadConfiguration(path.toFile())),
|
||||
EcoBossesPlugin.getInstance()
|
||||
);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new {@link EcoBoss} to EcoBosses.
|
||||
*
|
||||
* @param set The {@link EcoBoss} to add.
|
||||
*/
|
||||
public static void addBoss(@NotNull final EcoBoss set) {
|
||||
BY_NAME.remove(set.getName());
|
||||
BY_NAME.put(set.getName(), set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove {@link EcoBoss} from EcoBosses.
|
||||
*
|
||||
* @param set The {@link EcoBoss} to remove.
|
||||
*/
|
||||
public static void removeBoss(@NotNull final EcoBoss set) {
|
||||
BY_NAME.remove(set.getName());
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.eco.core.scheduling.RunnableTask;
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import com.willfp.ecobosses.bosses.tick.BossTicker;
|
||||
import com.willfp.ecobosses.bosses.tick.tickers.BossBarTicker;
|
||||
import com.willfp.ecobosses.bosses.tick.tickers.HealthPlaceholderTicker;
|
||||
import com.willfp.ecobosses.bosses.tick.tickers.TargetTicker;
|
||||
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.attribute.AttributeInstance;
|
||||
import org.bukkit.attribute.AttributeModifier;
|
||||
import org.bukkit.boss.BarFlag;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class LivingEcoBoss extends PluginDependent<EcoPlugin> {
|
||||
/**
|
||||
* The entity.
|
||||
*/
|
||||
@Getter
|
||||
private LivingEntity entity;
|
||||
|
||||
/**
|
||||
* The boss.
|
||||
*/
|
||||
private final EcoBoss boss;
|
||||
|
||||
/**
|
||||
* The boss tickers.
|
||||
*/
|
||||
private final List<BossTicker> tickers;
|
||||
|
||||
/**
|
||||
* The effects.
|
||||
*/
|
||||
private final List<Effect> effects;
|
||||
|
||||
/**
|
||||
* Create new living EcoBoss.
|
||||
*
|
||||
* @param plugin Instance of EcoBosses.
|
||||
* @param entity The entity.
|
||||
* @param boss The boss.
|
||||
*/
|
||||
public LivingEcoBoss(@NotNull final EcoPlugin plugin,
|
||||
@NotNull final LivingEntity entity,
|
||||
@NotNull final EcoBoss boss) {
|
||||
super(plugin);
|
||||
this.entity = entity;
|
||||
this.boss = boss;
|
||||
|
||||
this.onSpawn();
|
||||
|
||||
// Tickers
|
||||
this.tickers = new ArrayList<>();
|
||||
this.tickers.add(new HealthPlaceholderTicker());
|
||||
this.tickers.add(new TargetTicker(boss.getTargetMode(), boss.getTargetDistance()));
|
||||
if (boss.isBossbarEnabled()) {
|
||||
this.tickers.add(
|
||||
new BossBarTicker(
|
||||
Bukkit.getServer().createBossBar(
|
||||
plugin.getNamespacedKeyFactory().create("boss_" + NumberUtils.randInt(0, 1000000)),
|
||||
entity.getCustomName(),
|
||||
boss.getBossbarProperties().color(),
|
||||
boss.getBossbarProperties().style(),
|
||||
(BarFlag) null
|
||||
),
|
||||
this.getPlugin().getConfigYml().getInt("bossbar-radius")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Effects
|
||||
this.effects = new ArrayList<>();
|
||||
this.effects.addAll(boss.createEffects());
|
||||
|
||||
AtomicLong currentTick = new AtomicLong(0);
|
||||
this.getPlugin().getRunnableFactory().create(runnable -> this.tick(currentTick.getAndAdd(1), runnable)).runTaskTimer(0, 1);
|
||||
}
|
||||
|
||||
private void onSpawn() {
|
||||
entity.getPersistentDataContainer().set(this.getPlugin().getNamespacedKeyFactory().create("boss"), PersistentDataType.STRING, boss.getName());
|
||||
entity.setPersistent(true);
|
||||
entity.setRemoveWhenFarAway(false);
|
||||
|
||||
entity.setCustomName(boss.getDisplayName());
|
||||
entity.setCustomNameVisible(true);
|
||||
|
||||
AttributeInstance movementSpeed = entity.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
|
||||
assert movementSpeed != null;
|
||||
movementSpeed.addModifier(new AttributeModifier(entity.getUniqueId(), "ecobosses-movement-multiplier", boss.getMovementSpeedMultiplier() - 1, AttributeModifier.Operation.MULTIPLY_SCALAR_1));
|
||||
|
||||
AttributeInstance maxHealth = entity.getAttribute(Attribute.GENERIC_MAX_HEALTH);
|
||||
assert maxHealth != null;
|
||||
maxHealth.setBaseValue(boss.getMaxHealth());
|
||||
|
||||
entity.setHealth(maxHealth.getValue());
|
||||
|
||||
AttributeInstance followRange = entity.getAttribute(Attribute.GENERIC_FOLLOW_RANGE);
|
||||
assert followRange != null;
|
||||
followRange.setBaseValue(boss.getFollowRange());
|
||||
|
||||
AttributeInstance attackDamage = entity.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE);
|
||||
assert attackDamage != null;
|
||||
attackDamage.setBaseValue(boss.getAttackDamage());
|
||||
|
||||
for (OptionedSound sound : boss.getSpawnSounds()) {
|
||||
entity.getWorld().playSound(entity.getLocation(), sound.sound(), sound.volume(), sound.pitch());
|
||||
}
|
||||
|
||||
for (String spawnMessage : boss.getSpawnMessages()) {
|
||||
Bukkit.broadcastMessage(spawnMessage
|
||||
.replace("%x%", StringUtils.internalToString(entity.getLocation().getBlockX()))
|
||||
.replace("%y%", StringUtils.internalToString(entity.getLocation().getBlockY()))
|
||||
.replace("%z%", StringUtils.internalToString(entity.getLocation().getBlockZ()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void tick(final long tick,
|
||||
@NotNull final RunnableTask runnable) {
|
||||
if (entity == null || entity.isDead()) {
|
||||
for (BossTicker ticker : tickers) {
|
||||
ticker.onDeath(boss, entity, tick);
|
||||
}
|
||||
for (Effect effect : effects) {
|
||||
effect.onDeath(boss, entity, tick);
|
||||
}
|
||||
boss.removeLivingBoss(entity);
|
||||
runnable.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
for (BossTicker ticker : tickers) {
|
||||
ticker.tick(boss, entity, tick);
|
||||
}
|
||||
for (Effect effect : effects) {
|
||||
effect.tick(boss, entity, tick);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an attack to the player.
|
||||
*
|
||||
* @param player The player.
|
||||
*/
|
||||
public void handleAttack(@NotNull final Player player) {
|
||||
for (OptionedSound sound : boss.getInjureSounds()) {
|
||||
player.getWorld().playSound(entity.getLocation(), sound.sound(), sound.volume(), sound.pitch());
|
||||
}
|
||||
|
||||
for (Effect effect : effects) {
|
||||
effect.onAttack(boss, entity, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.tick.BossTicker;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class Effect implements BossTicker {
|
||||
/**
|
||||
* The effect args.
|
||||
*/
|
||||
@Getter
|
||||
private final List<String> args;
|
||||
|
||||
/**
|
||||
* Create a new effect.
|
||||
*
|
||||
* @param args The args.
|
||||
*/
|
||||
protected Effect(@NotNull final List<String> args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a config error.
|
||||
*
|
||||
* @param message The error message.
|
||||
*/
|
||||
public void showConfigError(@NotNull final String message) {
|
||||
Bukkit.getLogger().warning("An effect is configured incorrectly!");
|
||||
Bukkit.getLogger().warning(message);
|
||||
Bukkit.getLogger().warning("Usage: " + getUsage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get effect usage.
|
||||
*
|
||||
* @return The usage.
|
||||
*/
|
||||
public abstract String getUsage();
|
||||
|
||||
/**
|
||||
* Handle the boss attacking a player.
|
||||
*
|
||||
* @param boss The boss.
|
||||
* @param entity The boss entity.
|
||||
* @param player The player.
|
||||
*/
|
||||
public void onAttack(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
@NotNull final Player player) {
|
||||
// Override when needed.
|
||||
}
|
||||
|
||||
/**
|
||||
* Tick the effect.
|
||||
*
|
||||
* @param boss The boss.
|
||||
* @param entity The boss entity.
|
||||
* @param tick The current tick: counts up from zero.
|
||||
*/
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
// Override when needed.
|
||||
}
|
||||
|
||||
/**
|
||||
* On boss death.
|
||||
*
|
||||
* @param boss The boss.
|
||||
* @param entity The boss entity.
|
||||
* @param tick The current tick: counts up from zero.
|
||||
*/
|
||||
@Override
|
||||
public void onDeath(@NotNull final EcoBoss boss,
|
||||
@Nullable final LivingEntity entity,
|
||||
final long tick) {
|
||||
// Override when needed.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Effect effect)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(getArgs(), effect.getArgs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getArgs());
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects;
|
||||
|
||||
import com.willfp.ecobosses.bosses.effects.effects.*;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@UtilityClass
|
||||
public class Effects {
|
||||
/**
|
||||
* Registered effects.
|
||||
*/
|
||||
private static final Map<String, Function<List<String>, Effect>> EFFECTS = new HashMap<>();
|
||||
|
||||
static {
|
||||
register("damage-nearby-players", EffectDamageNearbyPlayers::new);
|
||||
register("lightning-nearby-entities", EffectLightningNearbyEntities::new);
|
||||
register("summon", EffectSummon::new);
|
||||
register("give-potion-effect", EffectGivePotionEffect::new);
|
||||
register("shuffle-hotbar", EffectShuffleHotbar::new);
|
||||
register("teleport", EffectTeleport::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new effect.
|
||||
*
|
||||
* @param name The effect name.
|
||||
* @param creator Function to create an instance of the effect given args.
|
||||
*/
|
||||
public void register(@NotNull final String name,
|
||||
@NotNull final Function<List<String>, Effect> creator) {
|
||||
EFFECTS.put(name, creator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get effect matching name.
|
||||
*
|
||||
* @param name The effect name.
|
||||
* @param args The args.
|
||||
* @return The found effect, or null.
|
||||
*/
|
||||
@Nullable
|
||||
public Effect getEffect(@NotNull final String name,
|
||||
@NotNull final List<String> args) {
|
||||
Function<List<String>, Effect> found = EFFECTS.get(name.toLowerCase());
|
||||
return found == null ? null : found.apply(args);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects.effects;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EffectDamageNearbyPlayers extends Effect {
|
||||
private final int frequency;
|
||||
private final double damage;
|
||||
private final double radius;
|
||||
|
||||
public EffectDamageNearbyPlayers(@NotNull final List<String> args) {
|
||||
super(args);
|
||||
|
||||
if (args.size() < 3) {
|
||||
showConfigError("Incorrect amount of arguments!");
|
||||
}
|
||||
|
||||
frequency = Integer.parseInt(args.get(0));
|
||||
radius = Double.parseDouble(args.get(1));
|
||||
damage = Double.parseDouble(args.get(2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "damage-nearby-players:<frequency>:<damage>:<radius>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
if (tick % frequency == 0) {
|
||||
for (Entity nearbyEntity : entity.getNearbyEntities(radius, radius, radius)) {
|
||||
if (nearbyEntity instanceof Player) {
|
||||
((Player) nearbyEntity).damage(damage, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects.effects;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EffectGivePotionEffect extends Effect {
|
||||
private final PotionEffectType type;
|
||||
private final double chance;
|
||||
private final int duration;
|
||||
private final int strength;
|
||||
|
||||
public EffectGivePotionEffect(@NotNull final List<String> args) {
|
||||
super(args);
|
||||
|
||||
if (args.size() < 4) {
|
||||
showConfigError("Incorrect amount of arguments!");
|
||||
}
|
||||
|
||||
type = PotionEffectType.getByName(args.get(0).toUpperCase());
|
||||
chance = Double.parseDouble(args.get(1));
|
||||
duration = Integer.parseInt(args.get(2));
|
||||
strength = Integer.parseInt(args.get(3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "give-potion-effect:<effect>:<chance>:<duration>:<strength>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttack(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
@NotNull final Player player) {
|
||||
if (NumberUtils.randFloat(0, 100) > this.chance) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.addPotionEffect(new PotionEffect(type, duration, strength - 1));
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects.effects;
|
||||
|
||||
import com.willfp.eco.util.LightningUtils;
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EffectLightningNearbyEntities extends Effect {
|
||||
private final int frequency;
|
||||
private final double chance;
|
||||
private final double damage;
|
||||
private final double radius;
|
||||
|
||||
public EffectLightningNearbyEntities(@NotNull final List<String> args) {
|
||||
super(args);
|
||||
|
||||
if (args.size() < 4) {
|
||||
showConfigError("Incorrect amount of arguments!");
|
||||
}
|
||||
|
||||
frequency = Integer.parseInt(args.get(0));
|
||||
chance = Double.parseDouble(args.get(1));
|
||||
radius = Double.parseDouble(args.get(2));
|
||||
damage = Double.parseDouble(args.get(3));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "lightning-nearby-entities:<frequency>:<chance>:<damage>:<radius>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
if (tick % frequency == 0) {
|
||||
for (Entity nearbyEntity : entity.getNearbyEntities(radius, radius, radius)) {
|
||||
if (NumberUtils.randFloat(0, 100) < chance) {
|
||||
if (nearbyEntity instanceof LivingEntity) {
|
||||
LightningUtils.strike((LivingEntity) nearbyEntity, damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects.effects;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class EffectShuffleHotbar extends Effect {
|
||||
private final double chance;
|
||||
|
||||
public EffectShuffleHotbar(@NotNull final List<String> args) {
|
||||
super(args);
|
||||
|
||||
if (args.size() < 1) {
|
||||
showConfigError("Incorrect amount of arguments!");
|
||||
}
|
||||
|
||||
chance = Double.parseDouble(args.get(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "shuffle-hotbar:<chance>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttack(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
@NotNull final Player player) {
|
||||
if (NumberUtils.randFloat(0, 100) > this.chance) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ItemStack> hotbar = new ArrayList<>();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
hotbar.add(player.getInventory().getItem(i));
|
||||
}
|
||||
Collections.shuffle(hotbar);
|
||||
int i2 = 0;
|
||||
for (ItemStack item : hotbar) {
|
||||
player.getInventory().setItem(i2, item);
|
||||
i2++;
|
||||
}
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ENDER_PEARL_THROW, 1, 0.5f);
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects.effects;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import com.willfp.ecobosses.bosses.util.bosstype.BossEntityUtils;
|
||||
import com.willfp.ecobosses.bosses.util.bosstype.BossType;
|
||||
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Mob;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EffectSummon extends Effect {
|
||||
private final BossType type;
|
||||
private final double chance;
|
||||
|
||||
public EffectSummon(@NotNull final List<String> args) {
|
||||
super(args);
|
||||
|
||||
if (args.size() < 2) {
|
||||
showConfigError("Incorrect amount of arguments!");
|
||||
}
|
||||
|
||||
type = BossEntityUtils.getBossType(args.get(0));
|
||||
chance = Double.parseDouble(args.get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "summon:<entity>:<chance>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttack(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
@NotNull final Player player) {
|
||||
if (NumberUtils.randFloat(0, 100) > this.chance) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location loc = player.getLocation().add(NumberUtils.randInt(2, 6), 0, NumberUtils.randInt(2, 6));
|
||||
for (int i = 0; i < 15; i++) {
|
||||
if (loc.getBlock().getType() == Material.AIR) {
|
||||
break;
|
||||
}
|
||||
|
||||
loc.add(0, 1, 0);
|
||||
}
|
||||
|
||||
Entity summonedEntity = type.spawnBossEntity(loc);
|
||||
if (summonedEntity instanceof Mob) {
|
||||
((Mob) summonedEntity).setTarget(player);
|
||||
}
|
||||
|
||||
for (OptionedSound sound : boss.getSummonSounds()) {
|
||||
player.getWorld().playSound(entity.getLocation(), sound.sound(), sound.volume(), sound.pitch());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.effects.effects;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.effects.Effect;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class EffectTeleport extends Effect {
|
||||
private final int range;
|
||||
private final double chance;
|
||||
|
||||
public EffectTeleport(@NotNull final List<String> args) {
|
||||
super(args);
|
||||
|
||||
if (args.size() < 2) {
|
||||
showConfigError("Incorrect amount of arguments!");
|
||||
}
|
||||
|
||||
range = Integer.parseInt(args.get(0));
|
||||
chance = Double.parseDouble(args.get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
return "teleport:<range>:<chance>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttack(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
@NotNull final Player player) {
|
||||
if (NumberUtils.randFloat(0, 100) > this.chance) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Location> valid = new ArrayList<>();
|
||||
for (int x = -range; x <= range; x++) {
|
||||
for (int y = -range; y <= range; y++) {
|
||||
for (int z = -range; z <= range; z++) {
|
||||
Location location = entity.getLocation().clone();
|
||||
location.setX(location.getX() + x);
|
||||
location.setY(location.getY() + y);
|
||||
location.setZ(location.getZ() + z);
|
||||
|
||||
Block block = location.getBlock();
|
||||
|
||||
if (block.getType() == Material.AIR
|
||||
&& block.getRelative(BlockFace.UP).getType() == Material.AIR
|
||||
&& !(block.getRelative(BlockFace.DOWN).isLiquid() || block.getRelative(BlockFace.DOWN).getType() == Material.AIR)) {
|
||||
valid.add(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valid.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collections.shuffle(valid);
|
||||
Location location = valid.get(0);
|
||||
|
||||
entity.teleport(location);
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.listeners;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss;
|
||||
import com.willfp.ecobosses.bosses.util.BossUtils;
|
||||
import com.willfp.ecobosses.bosses.util.obj.DamagerProperty;
|
||||
import com.willfp.ecobosses.bosses.util.obj.ImmunityOptions;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AttackListeners extends PluginDependent<EcoPlugin> implements Listener {
|
||||
/**
|
||||
* Create new attack listeners.
|
||||
*
|
||||
* @param plugin Instance of EcoBosses.
|
||||
*/
|
||||
public AttackListeners(@NotNull final EcoPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player attacks a boss.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onAttackBoss(@NotNull final EntityDamageByEntityEvent event) {
|
||||
if (!(event.getEntity() instanceof LivingEntity entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = BossUtils.getPlayerFromEntity(event.getDamager());
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LivingEcoBoss livingEcoBoss = boss.getLivingBoss(entity);
|
||||
|
||||
BossUtils.warnIfNull(livingEcoBoss);
|
||||
|
||||
if (boss.isAttackOnInjure()) {
|
||||
livingEcoBoss.handleAttack(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track top damage players.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void topDamageTracker(@NotNull final EntityDamageByEntityEvent event) {
|
||||
if (!(event.getEntity() instanceof LivingEntity entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = BossUtils.getPlayerFromEntity(event.getDamager());
|
||||
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DamagerProperty> topDamagers = BossUtils.getTopDamagers(entity);
|
||||
|
||||
double playerDamage;
|
||||
|
||||
Optional<DamagerProperty> damager = topDamagers.stream().filter(damagerProperty -> damagerProperty.playerUUID().equals(player.getUniqueId())).findFirst();
|
||||
playerDamage = damager.map(DamagerProperty::damage).orElse(0.0);
|
||||
|
||||
playerDamage += event.getFinalDamage();
|
||||
topDamagers.removeIf(damagerProperty -> damagerProperty.playerUUID().equals(player.getUniqueId()));
|
||||
topDamagers.add(new DamagerProperty(player.getUniqueId(), playerDamage));
|
||||
|
||||
entity.removeMetadata("ecobosses-top-damagers", this.getPlugin());
|
||||
entity.setMetadata("ecobosses-top-damagers", this.getPlugin().getMetadataValueFactory().create(topDamagers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a boss attacks a player.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onAttackPlayer(@NotNull final EntityDamageByEntityEvent event) {
|
||||
if (!(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getDamager() instanceof LivingEntity entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
LivingEcoBoss livingEcoBoss = boss.getLivingBoss(entity);
|
||||
|
||||
BossUtils.warnIfNull(livingEcoBoss);
|
||||
|
||||
livingEcoBoss.handleAttack(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a boss is damaged.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGH)
|
||||
public void defenceListener(@NotNull final EntityDamageEvent event) {
|
||||
if (!(event.getEntity() instanceof LivingEntity entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImmunityOptions immunities = boss.getImmunityOptions();
|
||||
|
||||
if (immunities.immuneToFire()
|
||||
&& (event.getCause() == EntityDamageEvent.DamageCause.FIRE
|
||||
|| event.getCause() == EntityDamageEvent.DamageCause.FIRE_TICK
|
||||
|| event.getCause() == EntityDamageEvent.DamageCause.HOT_FLOOR)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
if (immunities.immuneToSuffocation()&& event.getCause() == EntityDamageEvent.DamageCause.SUFFOCATION) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
if (immunities.immuneToDrowning() && event.getCause() == EntityDamageEvent.DamageCause.DROWNING) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
if (immunities.immuneToExplosions() && (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION || event.getCause() == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
if (immunities.immuneToProjectiles() && (event.getCause() == EntityDamageEvent.DamageCause.PROJECTILE)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
for (Map.Entry<EntityDamageEvent.DamageCause, Double> entry : boss.getIncomingMultipliers().entrySet()) {
|
||||
if (event.getCause() == entry.getKey()) {
|
||||
event.setDamage(event.getDamage() * entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.listeners;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.EcoBosses;
|
||||
import com.willfp.ecobosses.bosses.util.BossUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class AutoSpawnTimer implements Runnable {
|
||||
private int tick = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
tick++;
|
||||
|
||||
for (EcoBoss boss : EcoBosses.values()) {
|
||||
if (boss.getAutoSpawnInterval() < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (boss.getAutoSpawnLocations().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<World> worlds = new HashSet<>();
|
||||
|
||||
for (Entity entity : boss.getLivingBosses().keySet()) {
|
||||
BossUtils.warnIfNull(entity);
|
||||
assert entity != null;
|
||||
|
||||
worlds.add(entity.getWorld());
|
||||
}
|
||||
|
||||
List<Location> locations = new ArrayList<>(boss.getAutoSpawnLocations());
|
||||
locations.removeIf(location -> worlds.contains(location.getWorld()));
|
||||
|
||||
if (locations.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tick % boss.getAutoSpawnInterval() == 0) {
|
||||
Location location = locations.get(NumberUtils.randInt(0, locations.size() - 1));
|
||||
boss.spawn(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.listeners;
|
||||
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.eco.core.events.EntityDeathByEntityEvent;
|
||||
import com.willfp.eco.core.tuples.Pair;
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.util.BossUtils;
|
||||
import com.willfp.ecobosses.bosses.util.obj.DamagerProperty;
|
||||
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDeathEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DeathListeners extends PluginDependent<EcoPlugin> implements Listener {
|
||||
/**
|
||||
* Create new death listeners.
|
||||
*
|
||||
* @param plugin Instance of EcoBosses.
|
||||
*/
|
||||
public DeathListeners(@NotNull final EcoPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a boss dies.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler
|
||||
public void onBossDeath(@NotNull final EntityDeathByEntityEvent event) {
|
||||
LivingEntity entity = event.getVictim();
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (OptionedSound sound : boss.getDeathSounds()) {
|
||||
entity.getWorld().playSound(entity.getLocation(), sound.sound(), sound.volume(), sound.pitch());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle drops and experience.
|
||||
*
|
||||
* @param event The event.
|
||||
*/
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
public void onOtherDeath(@NotNull final EntityDeathEvent event) {
|
||||
LivingEntity entity = event.getEntity();
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<DamagerProperty> topDamagers = BossUtils.getTopDamagers(entity);
|
||||
|
||||
DamagerProperty top = null;
|
||||
DamagerProperty second = null;
|
||||
DamagerProperty third = null;
|
||||
|
||||
if (topDamagers.size() >= 1) {
|
||||
top = topDamagers.get(0);
|
||||
}
|
||||
if (topDamagers.size() >= 2) {
|
||||
second = topDamagers.get(1);
|
||||
}
|
||||
if (topDamagers.size() >= 3) {
|
||||
third = topDamagers.get(2);
|
||||
}
|
||||
|
||||
String na = this.getPlugin().getLangYml().getString("na");
|
||||
|
||||
String topDamager = top == null ? na : Bukkit.getPlayer(top.playerUUID()).getDisplayName();
|
||||
String topDamage = top == null ? na : StringUtils.internalToString(top.damage());
|
||||
|
||||
String secondDamager = second == null ? na : Bukkit.getPlayer(second.playerUUID()).getDisplayName();
|
||||
String secondDamage = second == null ? na : StringUtils.internalToString(second.damage());
|
||||
|
||||
String thirdDamager = third == null ? na : Bukkit.getPlayer(third.playerUUID()).getDisplayName();
|
||||
String thirdDamage = third == null ? na : StringUtils.internalToString(third.damage());
|
||||
|
||||
for (String spawnMessage : boss.getDeathMessages()) {
|
||||
Bukkit.broadcastMessage(spawnMessage
|
||||
.replace("%top%", topDamager)
|
||||
.replace("%top_damage%", topDamage)
|
||||
.replace("%second%", secondDamager)
|
||||
.replace("%second_damage%", secondDamage)
|
||||
.replace("%third%", thirdDamager)
|
||||
.replace("%third_damage%", thirdDamage)
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
List<Pair<Double, String>> topDamagerCommands = boss.getTopDamagerCommands().get(i);
|
||||
for (Pair<Double, String> pair : topDamagerCommands) {
|
||||
if (top != null && i == 1) {
|
||||
if (NumberUtils.randFloat(0, 100) < pair.getFirst()) {
|
||||
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), pair.getSecond().replace("%player%", Bukkit.getOfflinePlayer(top.playerUUID()).getName()));
|
||||
}
|
||||
}
|
||||
if (second != null && i == 2) {
|
||||
if (NumberUtils.randFloat(0, 100) < pair.getFirst()) {
|
||||
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), pair.getSecond().replace("%player%", Bukkit.getOfflinePlayer(second.playerUUID()).getName()));
|
||||
}
|
||||
}
|
||||
if (third != null && i == 3) {
|
||||
if (NumberUtils.randFloat(0, 100) < pair.getFirst()) {
|
||||
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), pair.getSecond().replace("%player%", Bukkit.getOfflinePlayer(third.playerUUID()).getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ItemStack> drops = new ArrayList<>();
|
||||
for (Map.Entry<ItemStack, Double> entry : boss.getDrops().entrySet()) {
|
||||
if (NumberUtils.randFloat(0, 100) < entry.getValue()) {
|
||||
drops.add(entry.getKey().clone());
|
||||
}
|
||||
}
|
||||
|
||||
for (Entity nearby : entity.getNearbyEntities(boss.getNearbyRadius(), boss.getNearbyRadius(), boss.getNearbyRadius())) {
|
||||
if (nearby instanceof Player) {
|
||||
String playerName = nearby.getName();
|
||||
for (Map.Entry<String, Double> entry : boss.getNearbyPlayersCommands().entrySet()) {
|
||||
if (NumberUtils.randFloat(0, 100) < entry.getValue()) {
|
||||
Bukkit.dispatchCommand(Bukkit.getServer().getConsoleSender(), entry.getKey().replace("%player%", playerName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
event.getDrops().addAll(drops);
|
||||
event.setDroppedExp(boss.getExperienceOptions().generateXp());
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.listeners;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.util.BossUtils;
|
||||
import org.bukkit.entity.Boat;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Minecart;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.spigotmc.event.entity.EntityMountEvent;
|
||||
|
||||
public class PassiveListeners extends PluginDependent<EcoPlugin> implements Listener {
|
||||
/**
|
||||
* Create new attack listeners.
|
||||
*
|
||||
* @param plugin Instance of EcoBosses.
|
||||
*/
|
||||
public PassiveListeners(@NotNull final EcoPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player attacks a boss.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onAttackBoss(@NotNull final EntityMountEvent event) {
|
||||
if (!(event.getEntity() instanceof LivingEntity entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getMount() instanceof Boat || event.getMount() instanceof Minecart)) {
|
||||
return;
|
||||
}
|
||||
|
||||
EcoBoss boss = BossUtils.getBoss(entity);
|
||||
|
||||
if (boss == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (boss.isDisableBoats()) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.listeners;
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin;
|
||||
import com.willfp.eco.core.PluginDependent;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.EcoBosses;
|
||||
import com.willfp.ecobosses.bosses.util.obj.SpawnTotem;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SpawnListeners extends PluginDependent<EcoPlugin> implements Listener {
|
||||
/**
|
||||
* Create new spawn listeners and link them to a plugin.
|
||||
*
|
||||
* @param plugin The plugin to link to.
|
||||
*/
|
||||
public SpawnListeners(@NotNull final EcoPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on block place.
|
||||
*
|
||||
* @param event The event to listen for.
|
||||
*/
|
||||
@EventHandler
|
||||
public void spawnTotem(@NotNull final BlockPlaceEvent event) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Block block1;
|
||||
Block block2;
|
||||
Block block3;
|
||||
|
||||
if (i == 0) {
|
||||
block3 = event.getBlock();
|
||||
block2 = event.getBlock().getRelative(0, -1, 0);
|
||||
block1 = event.getBlock().getRelative(0, -2, 0);
|
||||
} else if (i == 1) {
|
||||
block1 = event.getBlock();
|
||||
block2 = event.getBlock().getRelative(0, 1, 0);
|
||||
block3 = event.getBlock().getRelative(0, 2, 0);
|
||||
} else {
|
||||
block2 = event.getBlock();
|
||||
block1 = event.getBlock().getRelative(0, -1, 0);
|
||||
block3 = event.getBlock().getRelative(0, 1, 0);
|
||||
}
|
||||
|
||||
SpawnTotem placedTotem = new SpawnTotem(block1.getType(), block2.getType(), block3.getType());
|
||||
|
||||
for (EcoBoss boss : EcoBosses.values()) {
|
||||
if (boss.isSpawnTotemEnabled()) {
|
||||
if (!boss.getSpawnTotemDisabledWorldNames().contains(event.getBlock().getWorld().getName().toLowerCase())) {
|
||||
if (boss.getSpawnTotem().equals(placedTotem)) {
|
||||
block1.setType(Material.AIR);
|
||||
block2.setType(Material.AIR);
|
||||
block3.setType(Material.AIR);
|
||||
|
||||
boss.spawn(event.getBlock().getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface BossTicker {
|
||||
/**
|
||||
* Run on boss tick.
|
||||
*
|
||||
* @param boss The boss.
|
||||
* @param entity The boss entity.
|
||||
* @param tick The current tick: counts up from zero.
|
||||
*/
|
||||
void tick(@NotNull EcoBoss boss,
|
||||
@NotNull LivingEntity entity,
|
||||
long tick);
|
||||
|
||||
/**
|
||||
* Run on boss death.
|
||||
*
|
||||
* @param boss The boss.
|
||||
* @param entity The boss entity.
|
||||
* @param tick The current tick: counts up from zero.
|
||||
*/
|
||||
default void onDeath(@NotNull EcoBoss boss,
|
||||
@Nullable LivingEntity entity,
|
||||
long tick) {
|
||||
// Can be overridden when needed.
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick.tickers;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.tick.BossTicker;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.boss.KeyedBossBar;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class BossBarTicker implements BossTicker {
|
||||
/**
|
||||
* The boss bar.
|
||||
*/
|
||||
private final BossBar bossBar;
|
||||
|
||||
/**
|
||||
* The radius that the boss bar should be visible in.
|
||||
*/
|
||||
private final double radius;
|
||||
|
||||
/**
|
||||
* Create new boss bar ticker.
|
||||
* @param bossBar The boss bar.
|
||||
* @param radius The radius.
|
||||
*/
|
||||
public BossBarTicker(@NotNull final BossBar bossBar,
|
||||
final double radius) {
|
||||
this.bossBar = bossBar;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
bossBar.setTitle(entity.getCustomName());
|
||||
bossBar.setProgress(entity.getHealth() / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
|
||||
|
||||
if (tick % 40 == 0) {
|
||||
bossBar.removeAll();
|
||||
entity.getNearbyEntities(radius, radius, radius).forEach(entity1 -> {
|
||||
if (entity1 instanceof Player) {
|
||||
bossBar.addPlayer((Player) entity1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(@NotNull final EcoBoss boss,
|
||||
@Nullable final LivingEntity entity,
|
||||
final long tick) {
|
||||
bossBar.removeAll();
|
||||
bossBar.setVisible(false);
|
||||
Bukkit.removeBossBar(((KeyedBossBar) bossBar).getKey());
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick.tickers;
|
||||
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.tick.BossTicker;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class HealthPlaceholderTicker implements BossTicker {
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
entity.setCustomName(boss.getDisplayName().replace("%health%", StringUtils.internalToString(entity.getHealth())));
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick.tickers;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.tick.BossTicker;
|
||||
import com.willfp.ecobosses.bosses.util.obj.TargetMode;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Mob;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TargetTicker implements BossTicker {
|
||||
/**
|
||||
* The targeting mode.
|
||||
*/
|
||||
private final TargetMode mode;
|
||||
|
||||
/**
|
||||
* The maximum range.
|
||||
*/
|
||||
private final double range;
|
||||
|
||||
/**
|
||||
* Create new target ticker.
|
||||
*
|
||||
* @param mode The targeting mode.
|
||||
* @param range The range.
|
||||
*/
|
||||
public TargetTicker(@NotNull final TargetMode mode,
|
||||
final double range) {
|
||||
this.mode = mode;
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
Mob mob = (Mob) entity;
|
||||
if (tick % 10 == 0) {
|
||||
List<Player> nearbyPlayers = new ArrayList<>();
|
||||
for (Entity nearbyEntity : entity.getNearbyEntities(range, range, range)) {
|
||||
if (nearbyEntity instanceof Player) {
|
||||
nearbyPlayers.add((Player) nearbyEntity);
|
||||
}
|
||||
}
|
||||
|
||||
if (nearbyPlayers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mob.setTarget(mode.getTarget(nearbyPlayers, entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util;
|
||||
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.EcoBosses;
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss;
|
||||
import com.willfp.ecobosses.bosses.util.obj.DamagerProperty;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.boss.KeyedBossBar;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@UtilityClass
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BossUtils {
|
||||
/**
|
||||
* Instance of EcoBosses.
|
||||
*/
|
||||
private static final EcoBossesPlugin PLUGIN = EcoBossesPlugin.getInstance();
|
||||
|
||||
/**
|
||||
* Get {@link EcoBoss} from an entity.
|
||||
*
|
||||
* @param entity The entity.
|
||||
* @return The boss, or null if not a boss.
|
||||
*/
|
||||
@Nullable
|
||||
public EcoBoss getBoss(@NotNull final LivingEntity entity) {
|
||||
if (!entity.getPersistentDataContainer().has(PLUGIN.getNamespacedKeyFactory().create("boss"), PersistentDataType.STRING)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String bossName = entity.getPersistentDataContainer().get(PLUGIN.getNamespacedKeyFactory().create("boss"), PersistentDataType.STRING);
|
||||
|
||||
if (bossName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return EcoBosses.getByName(bossName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get top damagers for a boss.
|
||||
*
|
||||
* @param entity The boss entity.
|
||||
* @return A list of the top damagers, sorted.
|
||||
*/
|
||||
public List<DamagerProperty> getTopDamagers(@NotNull final LivingEntity entity) {
|
||||
if (getBoss(entity) == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<DamagerProperty> topDamagers;
|
||||
if (entity.hasMetadata("ecobosses-top-damagers")) {
|
||||
topDamagers = (List<DamagerProperty>) entity.getMetadata("ecobosses-top-damagers").get(0).value();
|
||||
} else {
|
||||
topDamagers = new ArrayList<>();
|
||||
}
|
||||
assert topDamagers != null;
|
||||
|
||||
topDamagers.sort(Comparator.comparingDouble(DamagerProperty::damage));
|
||||
Collections.reverse(topDamagers);
|
||||
|
||||
return topDamagers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill all bosses.
|
||||
*
|
||||
* @return The amount of bosses killed.
|
||||
*/
|
||||
public int killAllBosses() {
|
||||
return killAllBosses(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill all bosses.
|
||||
*
|
||||
* @param force If all entities should be checked for being bosses.
|
||||
* @return The amount of bosses killed.
|
||||
*/
|
||||
public int killAllBosses(final boolean force) {
|
||||
int amount = 0;
|
||||
for (EcoBoss boss : EcoBosses.values()) {
|
||||
for (LivingEntity entity : boss.getLivingBosses().keySet()) {
|
||||
assert entity != null;
|
||||
entity.damage(10000000);
|
||||
amount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (force) {
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
for (Entity entity : world.getEntities()) {
|
||||
if (!(entity instanceof LivingEntity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BossUtils.getBoss((LivingEntity) entity) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<KeyedBossBar> bars = new ArrayList<>();
|
||||
Bukkit.getBossBars().forEachRemaining(bars::add);
|
||||
for (KeyedBossBar bar : bars) {
|
||||
if (bar.getKey().toString().startsWith("ecobosses:boss")) {
|
||||
BossBar bossBar = Bukkit.getBossBar(bar.getKey());
|
||||
assert bossBar != null;
|
||||
bossBar.removeAll();
|
||||
bossBar.setVisible(false);
|
||||
Bukkit.removeBossBar(bar.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get player from entity if player or projectile.
|
||||
*
|
||||
* @param entity The entity.
|
||||
* @return The player, or null if not a player.
|
||||
*/
|
||||
@Nullable
|
||||
public Player getPlayerFromEntity(@NotNull final Entity entity) {
|
||||
Player player = null;
|
||||
|
||||
if (entity instanceof Player) {
|
||||
player = (Player) entity;
|
||||
} else if (entity instanceof Projectile) {
|
||||
if (((Projectile) entity).getShooter() instanceof Player) {
|
||||
player = (Player) ((Projectile) entity).getShooter();
|
||||
}
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn if a boss is null.
|
||||
*
|
||||
* @param boss The boss.
|
||||
*/
|
||||
public void warnIfNull(@Nullable final LivingEcoBoss boss) {
|
||||
if (boss != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PLUGIN.getLogger().severe("Boss is null! Report this to Auxilor (https://discord.gg/ZcwpSsE)");
|
||||
PLUGIN.getLogger().severe("Send this stack-trace in the relevant channel.");
|
||||
throw new NullPointerException("Boss is null!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn if an entity is null.
|
||||
*/
|
||||
public void warnIfNull(@Nullable final Entity entity) {
|
||||
if (entity != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
PLUGIN.getLogger().severe("Entity is null! Report this to Auxilor (https://discord.gg/ZcwpSsE)");
|
||||
PLUGIN.getLogger().severe("Send this stack-trace in the relevant channel.");
|
||||
throw new NullPointerException("Entity is null!");
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.bosstype;
|
||||
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntities;
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntity;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@UtilityClass
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BossEntityUtils {
|
||||
/**
|
||||
* Get boss type.
|
||||
*
|
||||
* @param id The name.
|
||||
* @return The boss type.
|
||||
*/
|
||||
public static BossType getBossType(@NotNull final String id) {
|
||||
try {
|
||||
Class<? extends LivingEntity> type = (Class<? extends LivingEntity>) EntityType.valueOf(id.toUpperCase()).getEntityClass();
|
||||
assert type != null;
|
||||
return new VanillaBossType(type);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Class<? extends CustomEntity<? extends LivingEntity>> proxy = CustomEntities.getEntityClass(id.toLowerCase());
|
||||
if (proxy != null) {
|
||||
return new CustomBossType(proxy);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.bosstype;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class BossType {
|
||||
/**
|
||||
* Spawn boss entity.
|
||||
*
|
||||
* @param location The location.
|
||||
* @return The entity.
|
||||
*/
|
||||
public abstract LivingEntity spawnBossEntity(@NotNull Location location);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.bosstype;
|
||||
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import com.willfp.ecobosses.proxy.proxies.CustomEntitySpawnerProxy;
|
||||
import com.willfp.ecobosses.proxy.util.CustomEntity;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class CustomBossType extends BossType {
|
||||
/**
|
||||
* The entity type.
|
||||
*/
|
||||
private final Class<? extends CustomEntity<? extends LivingEntity>> entityClass;
|
||||
|
||||
/**
|
||||
* Create new vanilla boss type.
|
||||
*
|
||||
* @param entityClass The entity class.
|
||||
*/
|
||||
CustomBossType(@NotNull final Class<? extends CustomEntity<? extends LivingEntity>> entityClass) {
|
||||
this.entityClass = entityClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity spawnBossEntity(@NotNull final Location location) {
|
||||
return EcoBossesPlugin.getInstance().getProxy(CustomEntitySpawnerProxy.class).spawnCustomEntity(entityClass, location);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.bosstype;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class VanillaBossType extends BossType {
|
||||
/**
|
||||
* The entity type.
|
||||
*/
|
||||
private final Class<? extends LivingEntity> entityClass;
|
||||
|
||||
/**
|
||||
* Create new vanilla boss type.
|
||||
*
|
||||
* @param entityClass The entity class.
|
||||
*/
|
||||
VanillaBossType(@NotNull final Class<? extends LivingEntity> entityClass) {
|
||||
this.entityClass = entityClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity spawnBossEntity(@NotNull final Location location) {
|
||||
return Objects.requireNonNull(location.getWorld()).spawn(location, entityClass);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import lombok.Data;
|
||||
import org.bukkit.boss.BarColor;
|
||||
import org.bukkit.boss.BarStyle;
|
||||
|
||||
public record BossbarProperties(BarColor color, BarStyle style) {
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record DamagerProperty(UUID playerUUID, double damage) {
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
|
||||
public record ExperienceOptions(int minimum, int maximum) {
|
||||
/**
|
||||
* Generate an exp amount.
|
||||
*
|
||||
* @return The amount.
|
||||
*/
|
||||
public int generateXp() {
|
||||
return NumberUtils.randInt(minimum, maximum);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
public record ImmunityOptions(boolean immuneToFire,
|
||||
boolean immuneToSuffocation,
|
||||
boolean immuneToDrowning,
|
||||
boolean immuneToProjectiles,
|
||||
boolean immuneToExplosions) {
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import org.bukkit.Sound;
|
||||
|
||||
public record OptionedSound(Sound sound,
|
||||
float volume,
|
||||
float pitch) {
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import lombok.Data;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public record SpawnTotem(Material bottom,
|
||||
Material middle,
|
||||
Material top) {
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import com.willfp.eco.util.NumberUtils;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class TargetMode {
|
||||
/**
|
||||
* All registered target modes.
|
||||
*/
|
||||
private static final Map<String, TargetMode> VALUES = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Random nearby player.
|
||||
*/
|
||||
public static final TargetMode RANDOM = new TargetMode("random", (list, entity) -> {
|
||||
return list.get(NumberUtils.randInt(0, list.size() - 1));
|
||||
});
|
||||
|
||||
/**
|
||||
* Closest player.
|
||||
*/
|
||||
public static final TargetMode CLOSEST = new TargetMode("closest", (list, entity) -> {
|
||||
Player player = null;
|
||||
double nearestD2 = 10000;
|
||||
for (Player nearbyPlayer : list) {
|
||||
double d2 = nearbyPlayer.getLocation().distanceSquared(entity.getLocation());
|
||||
if (d2 < nearestD2) {
|
||||
player = nearbyPlayer;
|
||||
}
|
||||
}
|
||||
return player;
|
||||
});
|
||||
|
||||
/**
|
||||
* Player with lowest health.
|
||||
*/
|
||||
public static final TargetMode LOWEST_HEALTH = new TargetMode("lowest-health", (list, entity) -> {
|
||||
Player player = null;
|
||||
double lowest = 100;
|
||||
for (Player nearbyPlayer : list) {
|
||||
double health = nearbyPlayer.getHealth();
|
||||
if (health < lowest) {
|
||||
player = nearbyPlayer;
|
||||
}
|
||||
}
|
||||
return player;
|
||||
});
|
||||
|
||||
/**
|
||||
* Player with highest health.
|
||||
*/
|
||||
public static final TargetMode HIGHEST_HEALTH = new TargetMode("highest-health", (list, entity) -> {
|
||||
Player player = null;
|
||||
double highest = 0;
|
||||
for (Player nearbyPlayer : list) {
|
||||
double health = nearbyPlayer.getHealth();
|
||||
if (health > highest) {
|
||||
player = nearbyPlayer;
|
||||
}
|
||||
}
|
||||
return player;
|
||||
});
|
||||
|
||||
/**
|
||||
* The name of the target mode.
|
||||
*/
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The function to find a player out of a list.
|
||||
*/
|
||||
private final BiFunction<List<Player>, LivingEntity, Player> function;
|
||||
|
||||
protected TargetMode(@NotNull final String name,
|
||||
@NotNull final BiFunction<List<Player>, LivingEntity, Player> function) {
|
||||
this.name = name;
|
||||
this.function = function;
|
||||
|
||||
VALUES.put(name, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get target from list of players.
|
||||
*
|
||||
* @param list The list.
|
||||
* @param entity The boss.
|
||||
* @return The target.
|
||||
*/
|
||||
public Player getTarget(@NotNull final List<Player> list,
|
||||
@NotNull final LivingEntity entity) {
|
||||
return function.apply(list, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get target mode by name.
|
||||
*
|
||||
* @param name The name.
|
||||
* @return The target mode, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
public static TargetMode getByName(@NotNull final String name) {
|
||||
return VALUES.get(name);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.willfp.ecobosses.commands;
|
||||
|
||||
import com.willfp.eco.core.command.CommandHandler;
|
||||
import com.willfp.eco.core.command.impl.Subcommand;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
public class CommandBase64 extends Subcommand {
|
||||
/**
|
||||
* Instantiate a new executor for /ebdrop.
|
||||
*
|
||||
* @param plugin The plugin to manage the execution for.
|
||||
*/
|
||||
public CommandBase64(@NotNull final EcoBossesPlugin plugin) {
|
||||
super(plugin, "base64", "ecobosses.command.base64", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandHandler getHandler() {
|
||||
return (sender, args) -> {
|
||||
Player player = (Player) sender;
|
||||
ItemStack itemStack = player.getInventory().getItemInMainHand();
|
||||
String key = "drop-key";
|
||||
YamlConfiguration jank = new YamlConfiguration();
|
||||
jank.set(key, itemStack);
|
||||
String configString = jank.saveToString();
|
||||
String dropString = Base64.getEncoder().encodeToString(configString.getBytes());
|
||||
|
||||
Bukkit.getLogger().info("Copy this into the drops section of your boss yml!");
|
||||
Bukkit.getLogger().info("\n" + dropString);
|
||||
|
||||
player.sendMessage(this.getPlugin().getLangYml().getMessage("sent-drop"));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.willfp.ecobosses.commands;
|
||||
|
||||
import com.willfp.eco.core.command.CommandHandler;
|
||||
import com.willfp.eco.core.command.impl.PluginCommand;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CommandEcobosses extends PluginCommand {
|
||||
/**
|
||||
* Instantiate a new executor for /ebdrop.
|
||||
*
|
||||
* @param plugin The plugin to manage the execution for.
|
||||
*/
|
||||
public CommandEcobosses(@NotNull final EcoBossesPlugin plugin) {
|
||||
super(plugin, "ecobosses", "ecobosses.command.ecobosses", false);
|
||||
this.addSubcommand(new CommandReload(plugin))
|
||||
.addSubcommand(new CommandKillall(plugin))
|
||||
.addSubcommand(new CommandSpawn(plugin))
|
||||
.addSubcommand(new CommandBase64(plugin));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandHandler getHandler() {
|
||||
return (sender, args) -> {
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-command"));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.willfp.ecobosses.commands;
|
||||
|
||||
import com.willfp.eco.core.command.CommandHandler;
|
||||
import com.willfp.eco.core.command.impl.Subcommand;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import com.willfp.ecobosses.bosses.util.BossUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CommandKillall extends Subcommand {
|
||||
/**
|
||||
* Instantiate a new executor for /ebspawn.
|
||||
*
|
||||
* @param plugin The plugin to manage the execution for.
|
||||
*/
|
||||
public CommandKillall(@NotNull final EcoBossesPlugin plugin) {
|
||||
super(plugin, "killall", "ecobosses.command.killall", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandHandler getHandler() {
|
||||
return (sender, args) -> {
|
||||
boolean force = false;
|
||||
if (args.size() == 1) {
|
||||
force = args.get(0).equalsIgnoreCase("force");
|
||||
}
|
||||
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("killall").replace("%amount%", String.valueOf(BossUtils.killAllBosses(force))));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.willfp.ecobosses.commands;
|
||||
|
||||
import com.willfp.eco.core.command.CommandHandler;
|
||||
import com.willfp.eco.core.command.impl.Subcommand;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CommandReload extends Subcommand {
|
||||
/**
|
||||
* Instantiate a new executor for /ebreload.
|
||||
*
|
||||
* @param plugin The plugin to manage the execution for.
|
||||
*/
|
||||
public CommandReload(@NotNull final EcoBossesPlugin plugin) {
|
||||
super(plugin, "reload", "ecobosses.command.reload", false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandHandler getHandler() {
|
||||
return (sender, args) -> {
|
||||
this.getPlugin().reload();
|
||||
this.getPlugin().reload();
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("reloaded"));
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package com.willfp.ecobosses.commands;
|
||||
|
||||
import com.willfp.eco.core.command.CommandHandler;
|
||||
import com.willfp.eco.core.command.TabCompleteHandler;
|
||||
import com.willfp.eco.core.command.impl.Subcommand;
|
||||
import com.willfp.eco.core.config.updating.ConfigUpdater;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.EcoBosses;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CommandSpawn extends Subcommand {
|
||||
/**
|
||||
* The cached names.
|
||||
*/
|
||||
private static final List<String> BOSS_NAMES = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The cached numbers.
|
||||
*/
|
||||
private static final List<String> TILDE = Arrays.asList(
|
||||
"~"
|
||||
);
|
||||
|
||||
/**
|
||||
* Instantiate a new executor for /ebspawn.
|
||||
*
|
||||
* @param plugin The plugin to manage the execution for.
|
||||
*/
|
||||
public CommandSpawn(@NotNull final EcoBossesPlugin plugin) {
|
||||
super(plugin, "spawn", "ecobosses.command.spawn", false);
|
||||
reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on reload.
|
||||
*/
|
||||
@ConfigUpdater
|
||||
public static void reload() {
|
||||
BOSS_NAMES.clear();
|
||||
BOSS_NAMES.addAll(EcoBosses.values().stream().map(EcoBoss::getName).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandHandler getHandler() {
|
||||
return (sender, args) -> {
|
||||
if (args.isEmpty()) {
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("specify-boss"));
|
||||
return;
|
||||
}
|
||||
|
||||
String bossName = args.get(0);
|
||||
|
||||
EcoBoss boss = EcoBosses.getByName(bossName.toLowerCase());
|
||||
|
||||
if (boss == null) {
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("specify-boss"));
|
||||
return;
|
||||
}
|
||||
|
||||
Location location = null;
|
||||
|
||||
if (sender instanceof Player) {
|
||||
location = ((Player) sender).getLocation();
|
||||
}
|
||||
|
||||
if (args.size() >= 4) {
|
||||
String xString = args.get(1);
|
||||
String yString = args.get(2);
|
||||
String zString = args.get(3);
|
||||
|
||||
double xPos;
|
||||
double yPos;
|
||||
double zPos;
|
||||
|
||||
if (xString.startsWith("~") && sender instanceof Player) {
|
||||
String xDiff = xString.replace("~", "");
|
||||
String yDiff = yString.replace("~", "");
|
||||
String zDiff = zString.replace("~", "");
|
||||
|
||||
if (xDiff.isEmpty()) {
|
||||
xPos = ((Player) sender).getLocation().getX();
|
||||
} else {
|
||||
try {
|
||||
xPos = ((Player) sender).getLocation().getX() + Double.parseDouble(xDiff);
|
||||
} catch (NumberFormatException e) {
|
||||
xPos = ((Player) sender).getLocation().getX();
|
||||
}
|
||||
}
|
||||
|
||||
if (yDiff.isEmpty()) {
|
||||
yPos = ((Player) sender).getLocation().getY();
|
||||
} else {
|
||||
try {
|
||||
yPos = ((Player) sender).getLocation().getY() + Double.parseDouble(yDiff);
|
||||
} catch (NumberFormatException e) {
|
||||
yPos = ((Player) sender).getLocation().getY();
|
||||
}
|
||||
}
|
||||
|
||||
if (zDiff.isEmpty()) {
|
||||
zPos = ((Player) sender).getLocation().getZ();
|
||||
} else {
|
||||
try {
|
||||
zPos = ((Player) sender).getLocation().getZ() + Double.parseDouble(yDiff);
|
||||
} catch (NumberFormatException e) {
|
||||
zPos = ((Player) sender).getLocation().getZ();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
xPos = Double.parseDouble(xString);
|
||||
yPos = Double.parseDouble(yString);
|
||||
zPos = Double.parseDouble(zString);
|
||||
} catch (NumberFormatException e) {
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-location"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
location = new Location(null, xPos, yPos, zPos);
|
||||
}
|
||||
|
||||
World world = null;
|
||||
if (sender instanceof Player) {
|
||||
world = ((Player) sender).getWorld();
|
||||
}
|
||||
|
||||
if (args.size() >= 5) {
|
||||
world = Bukkit.getWorld(args.get(4));
|
||||
}
|
||||
|
||||
if (location == null) {
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-location"));
|
||||
return;
|
||||
}
|
||||
|
||||
location.setWorld(world);
|
||||
|
||||
if (world == null) {
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("invalid-world"));
|
||||
return;
|
||||
}
|
||||
|
||||
boss.spawn(location);
|
||||
sender.sendMessage(this.getPlugin().getLangYml().getMessage("spawned"));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabCompleteHandler getTabCompleter() {
|
||||
return (sender, args) -> {
|
||||
|
||||
List<String> completions = new ArrayList<>();
|
||||
|
||||
if (args.isEmpty()) {
|
||||
// Currently, this case is not ever reached
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
if (args.size() == 1) {
|
||||
StringUtil.copyPartialMatches(args.get(0), BOSS_NAMES, completions);
|
||||
|
||||
Collections.sort(completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
if (args.size() == 2) {
|
||||
StringUtil.copyPartialMatches(args.get(1), TILDE, completions);
|
||||
|
||||
Collections.sort(completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
if (args.size() == 3) {
|
||||
StringUtil.copyPartialMatches(args.get(2), TILDE, completions);
|
||||
|
||||
Collections.sort(completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
if (args.size() == 4) {
|
||||
StringUtil.copyPartialMatches(args.get(3), TILDE, completions);
|
||||
|
||||
Collections.sort(completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
if (args.size() == 5) {
|
||||
StringUtil.copyPartialMatches(args.get(4), Bukkit.getWorlds().stream().map(World::getName).collect(Collectors.toList()), completions);
|
||||
|
||||
Collections.sort(completions);
|
||||
return completions;
|
||||
}
|
||||
|
||||
return new ArrayList<>(0);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.willfp.ecobosses.config;
|
||||
|
||||
import com.willfp.eco.core.config.yaml.YamlExtendableConfig;
|
||||
import com.willfp.ecobosses.EcoBossesPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BaseBossConfig extends YamlExtendableConfig {
|
||||
/**
|
||||
* Create new EcoBoss config.
|
||||
*
|
||||
* @param configName The name of the config.
|
||||
*/
|
||||
public BaseBossConfig(@NotNull final String configName) {
|
||||
super(configName, true, EcoBossesPlugin.getInstance(), EcoBossesPlugin.class, "bosses/");
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package com.willfp.ecobosses.config;
|
||||
|
||||
import com.willfp.eco.core.config.yaml.YamlTransientConfig;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CustomConfig extends YamlTransientConfig {
|
||||
/**
|
||||
* The name of the config.
|
||||
*/
|
||||
@Getter
|
||||
private final String configName;
|
||||
|
||||
/**
|
||||
* Create new custom config.
|
||||
*
|
||||
* @param configName The name of the config.
|
||||
* @param config The config.
|
||||
*/
|
||||
public CustomConfig(@NotNull final String configName,
|
||||
@NotNull final YamlConfiguration config) {
|
||||
super(config);
|
||||
this.configName = configName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.willfp.ecobosses
|
||||
|
||||
import com.willfp.eco.core.command.impl.PluginCommand
|
||||
import com.willfp.eco.core.display.DisplayModule
|
||||
import com.willfp.eco.core.integrations.IntegrationLoader
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import com.willfp.ecobosses.bosses.EggDisplay
|
||||
import com.willfp.ecobosses.bosses.bossHolders
|
||||
import com.willfp.ecobosses.commands.CommandEcobosses
|
||||
import com.willfp.ecobosses.config.EcoBossesYml
|
||||
import com.willfp.ecobosses.defence.DamageMultiplierHandler
|
||||
import com.willfp.ecobosses.defence.ImmunitiesHandler
|
||||
import com.willfp.ecobosses.defence.MountHandler
|
||||
import com.willfp.ecobosses.defence.PickupHandler
|
||||
import com.willfp.ecobosses.integrations.levelledmobs.IntegrationLevelledMobs
|
||||
import com.willfp.ecobosses.lifecycle.CompatibilityListeners
|
||||
import com.willfp.ecobosses.lifecycle.ConsoleLoggers
|
||||
import com.willfp.ecobosses.lifecycle.DeathListeners
|
||||
import com.willfp.ecobosses.lifecycle.LifecycleHandlers
|
||||
import com.willfp.ecobosses.spawn.AutospawnHandler
|
||||
import com.willfp.ecobosses.spawn.SpawnEggHandler
|
||||
import com.willfp.ecobosses.spawn.SpawnTotemHandler
|
||||
import com.willfp.ecobosses.util.DiscoverRecipeListener
|
||||
import com.willfp.ecobosses.util.TopDamagerListener
|
||||
import com.willfp.libreforge.LibReforgePlugin
|
||||
import org.bukkit.event.Listener
|
||||
|
||||
class EcoBossesPlugin : LibReforgePlugin() {
|
||||
val ecoBossesYml: EcoBossesYml
|
||||
|
||||
init {
|
||||
instance = this
|
||||
ecoBossesYml = EcoBossesYml(this)
|
||||
registerHolderProvider { it.bossHolders }
|
||||
}
|
||||
|
||||
override fun handleReloadAdditional() {
|
||||
Bosses.getAllAlive().forEach { it.remove() }
|
||||
|
||||
logger.info(Bosses.values().size.toString() + " Bosses Loaded")
|
||||
|
||||
AutospawnHandler.startSpawning(this)
|
||||
}
|
||||
|
||||
override fun handleDisableAdditional() {
|
||||
Bosses.getAllAlive().forEach { it.remove() }
|
||||
}
|
||||
|
||||
override fun createDisplayModule(): DisplayModule {
|
||||
return EggDisplay(this)
|
||||
}
|
||||
|
||||
override fun loadPluginCommands(): List<PluginCommand> {
|
||||
return listOf(
|
||||
CommandEcobosses(this)
|
||||
)
|
||||
}
|
||||
|
||||
override fun loadListeners(): List<Listener> {
|
||||
return listOf(
|
||||
DiscoverRecipeListener(this),
|
||||
TopDamagerListener(),
|
||||
LifecycleHandlers(),
|
||||
SpawnEggHandler(),
|
||||
DamageMultiplierHandler(),
|
||||
MountHandler(),
|
||||
PickupHandler(),
|
||||
ImmunitiesHandler(),
|
||||
CompatibilityListeners(),
|
||||
SpawnTotemHandler(),
|
||||
DeathListeners(),
|
||||
ConsoleLoggers(this)
|
||||
)
|
||||
}
|
||||
|
||||
override fun loadAdditionalIntegrations(): List<IntegrationLoader> {
|
||||
return listOf(
|
||||
IntegrationLoader("LevelledMobs") { this.eventManager.registerListener(IntegrationLevelledMobs()) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun getMinimumEcoVersion(): String {
|
||||
return "6.35.1"
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
lateinit var instance: EcoBossesPlugin
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.willfp.eco.core.fast.fast
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import com.willfp.libreforge.Holder
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import kotlin.math.pow
|
||||
|
||||
val Player.bossHolders: Iterable<Holder>
|
||||
get() {
|
||||
val holders = mutableListOf<Holder>()
|
||||
|
||||
for (boss in Bosses.values()) {
|
||||
for (livingBoss in boss.getAllAlive()) {
|
||||
val entity = livingBoss.entity ?: continue
|
||||
|
||||
if (entity.world != this.world) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (entity.location.distanceSquared(this.location) <= boss.influence.pow(2)) {
|
||||
holders.add(boss)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return holders
|
||||
}
|
||||
|
||||
private val spawnEggKey = EcoBossesPlugin.instance.namespacedKeyFactory.create("spawn_egg")
|
||||
|
||||
var ItemStack.bossEgg: EcoBoss?
|
||||
set(value) {
|
||||
val meta = this.itemMeta ?: return
|
||||
val pdc = meta.persistentDataContainer
|
||||
if (value == null) {
|
||||
pdc.remove(spawnEggKey)
|
||||
} else {
|
||||
pdc.set(spawnEggKey, PersistentDataType.STRING, value.id)
|
||||
}
|
||||
this.itemMeta = meta
|
||||
}
|
||||
get() {
|
||||
val pdc = this.fast().persistentDataContainer
|
||||
val id = pdc.get(spawnEggKey, PersistentDataType.STRING) ?: return null
|
||||
return Bosses.getByID(id)
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.google.common.collect.BiMap
|
||||
import com.google.common.collect.HashBiMap
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.willfp.eco.core.config.updating.ConfigUpdater
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import com.willfp.libreforge.chains.EffectChains
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import java.util.UUID
|
||||
|
||||
object Bosses {
|
||||
/**
|
||||
* Registered bosses.
|
||||
*/
|
||||
private val BY_ID: BiMap<String, EcoBoss> = HashBiMap.create()
|
||||
|
||||
/**
|
||||
* Get all registered [EcoBoss]s.
|
||||
*
|
||||
* @return A list of all [EcoBoss]s.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun values(): List<EcoBoss> {
|
||||
return ImmutableList.copyOf(BY_ID.values)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get [EcoBoss] matching ID.
|
||||
*
|
||||
* @param name The name to search for.
|
||||
* @return The matching [EcoBoss], or null if not found.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getByID(name: String): EcoBoss? {
|
||||
return BY_ID[name]
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all [EcoBoss]s.
|
||||
*
|
||||
* @param plugin Instance of EcoBosses.
|
||||
*/
|
||||
@ConfigUpdater
|
||||
@JvmStatic
|
||||
fun update(plugin: EcoBossesPlugin) {
|
||||
plugin.ecoBossesYml.getSubsections("chains").mapNotNull {
|
||||
EffectChains.compile(it, "Effect Chains")
|
||||
}
|
||||
|
||||
for (boss in values()) {
|
||||
removeBoss(boss)
|
||||
}
|
||||
|
||||
for (bossConfig in plugin.ecoBossesYml.getSubsections("bosses")) {
|
||||
addNewBoss(EcoBoss(bossConfig, plugin))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new [EcoBoss] to EcoBosses.
|
||||
*
|
||||
* @param set The [EcoBoss] to add.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun addNewBoss(set: EcoBoss) {
|
||||
BY_ID.remove(set.id)
|
||||
BY_ID[set.id] = set
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove [EcoBoss] from EcoBosses.
|
||||
*
|
||||
* @param set The [EcoBoss] to remove.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun removeBoss(set: EcoBoss) {
|
||||
BY_ID.remove(set.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all currently alive [EcoBoss]es.
|
||||
*
|
||||
* @return All living bosses.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getAllAlive(): Set<LivingEcoBoss> {
|
||||
val entities = mutableSetOf<LivingEcoBoss>()
|
||||
|
||||
for (boss in values()) {
|
||||
entities.addAll(boss.getAllAlive())
|
||||
}
|
||||
|
||||
return entities
|
||||
}
|
||||
|
||||
/**
|
||||
* Get [LivingEcoBoss].
|
||||
*
|
||||
* @return The boss, or null if not a boss.
|
||||
*/
|
||||
operator fun get(uuid: UUID): LivingEcoBoss? {
|
||||
for (boss in values()) {
|
||||
val found = boss[uuid]
|
||||
|
||||
if (found != null) {
|
||||
return found
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get [LivingEcoBoss].
|
||||
*
|
||||
* @return The boss, or null if not a boss.
|
||||
*/
|
||||
operator fun get(entity: LivingEntity): LivingEcoBoss? {
|
||||
return get(entity.uniqueId)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.willfp.eco.core.entities.ai.Goal
|
||||
|
||||
data class ConfiguredGoal<T : Goal<*>>(
|
||||
val priority: Int,
|
||||
val goal: T
|
||||
)
|
||||
@@ -0,0 +1,440 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
import com.willfp.eco.core.entities.CustomEntity
|
||||
import com.willfp.eco.core.entities.Entities
|
||||
import com.willfp.eco.core.entities.TestableEntity
|
||||
import com.willfp.eco.core.entities.ai.*
|
||||
import com.willfp.eco.core.items.CustomItem
|
||||
import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.core.items.builder.ItemStackBuilder
|
||||
import com.willfp.eco.core.recipe.Recipes
|
||||
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
|
||||
import com.willfp.eco.core.recipe.recipes.CraftingRecipe
|
||||
import com.willfp.eco.util.NamespacedKeyUtils
|
||||
import com.willfp.eco.util.toComponent
|
||||
import com.willfp.ecobosses.events.BossKillEvent
|
||||
import com.willfp.ecobosses.lifecycle.BossLifecycle
|
||||
import com.willfp.ecobosses.tick.*
|
||||
import com.willfp.ecobosses.util.*
|
||||
import com.willfp.libreforge.Holder
|
||||
import com.willfp.libreforge.conditions.Conditions
|
||||
import com.willfp.libreforge.effects.Effects
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.entity.Mob
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.persistence.PersistentDataType
|
||||
import java.util.*
|
||||
|
||||
class EcoBoss(
|
||||
val config: Config,
|
||||
private val plugin: EcoPlugin
|
||||
) : Holder {
|
||||
override val id: String = config.getString("id")
|
||||
|
||||
val displayName: String = config.getString("displayName")
|
||||
|
||||
val lifespan = config.getInt("lifespan")
|
||||
|
||||
val influence = config.getDouble("influence")
|
||||
|
||||
val targetRange = config.getDouble("target.range")
|
||||
|
||||
val targetMode = TargetMode.getByID(config.getString("target.mode"))!!
|
||||
|
||||
val isBossBarEnabled = config.getBool("bossBar.enabled")
|
||||
|
||||
val bossBarRadius = config.getDouble("bossBar.radius")
|
||||
|
||||
val isPreventingMounts = config.getBool("defence.preventMounts")
|
||||
|
||||
val isImmuneToExplosions = config.getBool("defence.explosionImmune")
|
||||
|
||||
val isImmuneToFire = config.getBool("defence.fireImmune")
|
||||
|
||||
val isImmuneToDrowning = config.getBool("defence.drowningImmune")
|
||||
|
||||
val isImmuneToSuffocation = config.getBool("defence.suffocationImmune")
|
||||
|
||||
val meleeDamageMultiplier = config.getDouble("defence.meleeDamageMultiplier")
|
||||
|
||||
val projectileDamageMultiplier = config.getDouble("defence.projectileDamageMultiplier")
|
||||
|
||||
val canTeleport = config.getBool("defence.teleportation.enabled")
|
||||
|
||||
val teleportRange = config.getInt("defence.teleportation.range")
|
||||
|
||||
val teleportInterval = config.getInt("defence.teleportation.interval")
|
||||
|
||||
private val spawnEggBacker: ItemStack? = run {
|
||||
val enabled = config.getBool("spawn.egg.enabled")
|
||||
if (!enabled) {
|
||||
return@run null
|
||||
}
|
||||
|
||||
val lookup = Items.lookup(config.getString("spawn.egg.item"))
|
||||
|
||||
if (lookup is EmptyTestableItem) {
|
||||
return@run null
|
||||
}
|
||||
|
||||
val name = config.getFormattedStringOrNull("spawn.egg.name")
|
||||
|
||||
val item = ItemStackBuilder(lookup)
|
||||
.addLoreLines(config.getFormattedStrings("spawn.egg.lore"))
|
||||
.apply {
|
||||
if (name != null) {
|
||||
setDisplayName(name)
|
||||
}
|
||||
}
|
||||
.build().apply { bossEgg = this@EcoBoss }
|
||||
|
||||
val key = plugin.namespacedKeyFactory.create("${this.id}_spawn_egg")
|
||||
|
||||
Items.registerCustomItem(
|
||||
key,
|
||||
CustomItem(
|
||||
key,
|
||||
{ it.bossEgg == this },
|
||||
item
|
||||
)
|
||||
)
|
||||
|
||||
item
|
||||
}
|
||||
|
||||
val spawnEgg: ItemStack?
|
||||
get() = this.spawnEggBacker?.clone()
|
||||
|
||||
val recipe: CraftingRecipe? = run {
|
||||
if (spawnEggBacker == null || !config.getBool("spawn.egg.craftable")) {
|
||||
return@run null
|
||||
}
|
||||
|
||||
val recipe = Recipes.createAndRegisterRecipe(
|
||||
this@EcoBoss.plugin,
|
||||
"${this.id}_spawn_egg",
|
||||
spawnEggBacker,
|
||||
config.getStrings("spawn.egg.recipe")
|
||||
)
|
||||
|
||||
recipe
|
||||
}
|
||||
|
||||
val totem: SpawnTotem? = run {
|
||||
if (!config.getBool("spawn.totem.enabled")) {
|
||||
return@run null
|
||||
}
|
||||
|
||||
SpawnTotem(
|
||||
Material.getMaterial(config.getString("spawn.totem.top").uppercase()) ?: return@run null,
|
||||
Material.getMaterial(config.getString("spawn.totem.middle").uppercase()) ?: return@run null,
|
||||
Material.getMaterial(config.getString("spawn.totem.bottom").uppercase()) ?: return@run null
|
||||
)
|
||||
}
|
||||
|
||||
val disabledTotemWorlds: List<String> = config.getStrings("spawn.totem.notInWorlds")
|
||||
|
||||
val autoSpawnInterval = config.getInt("spawn.autospawn.interval")
|
||||
|
||||
val autoSpawnLocations: List<Location> = run {
|
||||
val locations = mutableListOf<Location>()
|
||||
|
||||
for (config in config.getSubsections("spawn.autospawn.locations")) {
|
||||
val world = Bukkit.getWorld(config.getString("world")) ?: continue
|
||||
val x = config.getDouble("x")
|
||||
val y = config.getDouble("y")
|
||||
val z = config.getDouble("z")
|
||||
locations.add(
|
||||
Location(
|
||||
world, x, y, z
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
locations
|
||||
}
|
||||
|
||||
val hasCustomAI = config.getBool("customai.enabled")
|
||||
|
||||
val targetGoals = config.getSubsections("customai.target-goals").mapNotNull {
|
||||
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
|
||||
val deserializer = TargetGoals.getByKey(key) ?: return@mapNotNull null
|
||||
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
|
||||
ConfiguredGoal(it.getInt("priority"), goal)
|
||||
}
|
||||
|
||||
val entityGoals = config.getSubsections("customai.ai-goals").mapNotNull {
|
||||
val key = NamespacedKeyUtils.fromStringOrNull(it.getString("key")) ?: return@mapNotNull null
|
||||
val deserializer = EntityGoals.getByKey(key) ?: return@mapNotNull null
|
||||
val goal = deserializer.deserialize(it.getSubsection("args")) ?: return@mapNotNull null
|
||||
ConfiguredGoal(it.getInt("priority"), goal)
|
||||
}
|
||||
|
||||
val spawnConditions = config.getSubsections("spawn.conditions").mapNotNull {
|
||||
Conditions.compile(it, "$id Spawn Conditions")
|
||||
}
|
||||
|
||||
private val bossBarColor = BossBar.Color.valueOf(config.getString("bossBar.color").uppercase())
|
||||
|
||||
private val bossBarStyle = BossBar.Overlay.valueOf(config.getString("bossBar.style").uppercase())
|
||||
|
||||
private val sounds: Map<BossLifecycle, PlayableSound> = run {
|
||||
val map = mutableMapOf<BossLifecycle, PlayableSound>()
|
||||
|
||||
for (value in BossLifecycle.values()) {
|
||||
map[value] = PlayableSound(config.getSubsections("sounds.${value.name.lowercase()}").map {
|
||||
ConfiguredSound.fromConfig(it)
|
||||
})
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
private val messages: Map<BossLifecycle, Iterable<LocalBroadcast>> = run {
|
||||
val map = mutableMapOf<BossLifecycle, Iterable<LocalBroadcast>>()
|
||||
|
||||
for (value in BossLifecycle.values()) {
|
||||
map[value] = config.getSubsections("messages.${value.name.lowercase()}").map {
|
||||
LocalBroadcast.fromConfig(it)
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
private val commands: Map<BossLifecycle, LocalCommands> = run {
|
||||
val map = mutableMapOf<BossLifecycle, LocalCommands>()
|
||||
|
||||
for (value in BossLifecycle.values()) {
|
||||
map[value] = LocalCommands(config.getStrings("commands.${value.name.lowercase()}"))
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
private val commandRewards: Map<Int, Iterable<CommandReward>> = run {
|
||||
val map = mutableMapOf<Int, Iterable<CommandReward>>()
|
||||
|
||||
for (rank in config.getSubsection("rewards.topDamagerCommands").getKeys(false)) {
|
||||
val rankRewards = mutableListOf<CommandReward>()
|
||||
|
||||
for (config in config.getSubsections("rewards.topDamagerCommands.$rank")) {
|
||||
rankRewards.add(
|
||||
CommandReward(
|
||||
config.getDouble("chance"),
|
||||
config.getStrings("commands")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
map[rank.toInt()] = rankRewards
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
|
||||
private val nearbyCommandRewardRadius = config.getDouble("rewards.nearbyPlayerCommands.radius")
|
||||
|
||||
private val nearbyCommands: Iterable<CommandReward> = run {
|
||||
val list = mutableListOf<CommandReward>()
|
||||
|
||||
for (config in config.getSubsections("rewards.nearbyPlayerCommands.commands")) {
|
||||
list.add(
|
||||
CommandReward(
|
||||
config.getDouble("chance"),
|
||||
config.getStrings("commands")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
|
||||
private val xp = XpReward(
|
||||
config.getInt("rewards.xp.minimum"),
|
||||
config.getInt("rewards.xp.maximum")
|
||||
)
|
||||
|
||||
|
||||
private val drops: Iterable<BossDrop> = run {
|
||||
val list = mutableListOf<BossDrop>()
|
||||
|
||||
for (config in config.getSubsections("rewards.drops")) {
|
||||
list.add(
|
||||
BossDrop(
|
||||
config.getDouble("chance"),
|
||||
config.getStrings("items")
|
||||
.map { Items.lookup(it) }
|
||||
.filter { it !is EmptyTestableItem }
|
||||
.map { it.item }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
|
||||
private val mob: TestableEntity = Entities.lookup(config.getString("mob"))
|
||||
|
||||
private val currentlyAlive = mutableMapOf<UUID, LivingEcoBoss>()
|
||||
|
||||
override val conditions = config.getSubsections("conditions").mapNotNull {
|
||||
Conditions.compile(it, "Boss ID $id")
|
||||
}.toSet()
|
||||
|
||||
override val effects = config.getSubsections("effects").mapNotNull {
|
||||
Effects.compile(it, "Boss ID $id")
|
||||
}.toSet()
|
||||
|
||||
fun markDead(uuid: UUID) {
|
||||
currentlyAlive.remove(uuid)
|
||||
}
|
||||
|
||||
operator fun get(uuid: UUID): LivingEcoBoss? {
|
||||
return currentlyAlive[uuid]
|
||||
}
|
||||
|
||||
operator fun get(entity: LivingEntity): LivingEcoBoss? {
|
||||
return currentlyAlive[entity.uniqueId]
|
||||
}
|
||||
|
||||
fun getAllAlive(): Set<LivingEcoBoss> {
|
||||
return currentlyAlive.values.toSet()
|
||||
}
|
||||
|
||||
fun spawn(location: Location): LivingEcoBoss {
|
||||
val mob = mob.spawn(location) as Mob
|
||||
mob.isPersistent = true
|
||||
mob.isCustomNameVisible = true
|
||||
mob.removeWhenFarAway = false
|
||||
mob.persistentDataContainer.set(
|
||||
plugin.namespacedKeyFactory.create("boss"),
|
||||
PersistentDataType.STRING,
|
||||
this.id
|
||||
)
|
||||
|
||||
if (hasCustomAI) {
|
||||
val controller = EntityController.getFor(mob)
|
||||
.clearAllGoals()
|
||||
|
||||
@Suppress("UNCHECKED_CAST") // What could go wrong?
|
||||
targetGoals.forEach { controller.addTargetGoal(it.priority, it.goal as TargetGoal<in Mob>) }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
entityGoals.forEach { controller.addEntityGoal(it.priority, it.goal as EntityGoal<in Mob>) }
|
||||
}
|
||||
|
||||
val boss = LivingEcoBoss(
|
||||
plugin,
|
||||
mob.uniqueId,
|
||||
this,
|
||||
createTickers()
|
||||
)
|
||||
currentlyAlive[mob.uniqueId] = boss
|
||||
return boss
|
||||
}
|
||||
|
||||
private fun createTickers(): Set<BossTicker> {
|
||||
val tickers = mutableSetOf(
|
||||
LifespanTicker(),
|
||||
DisplayNameTicker(),
|
||||
TargetTicker(),
|
||||
TeleportHandler()
|
||||
)
|
||||
|
||||
if (isBossBarEnabled) {
|
||||
tickers.add(
|
||||
BossBarTicker(
|
||||
BossBar.bossBar(
|
||||
this.displayName.toComponent(),
|
||||
1.0f,
|
||||
bossBarColor,
|
||||
bossBarStyle
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return tickers
|
||||
}
|
||||
|
||||
fun handleLifecycle(lifecycle: BossLifecycle, location: Location, entity: LivingEntity?) {
|
||||
sounds[lifecycle]?.play(location)
|
||||
messages[lifecycle]?.forEach { it.broadcast(location, entity?.topDamagers ?: emptyList()) }
|
||||
commands[lifecycle]?.dispatch(location, entity?.topDamagers ?: emptyList())
|
||||
}
|
||||
|
||||
fun processRewards(event: BossKillEvent) {
|
||||
val entity = event.boss.entity ?: return
|
||||
val location = entity.location
|
||||
val player = event.killer
|
||||
|
||||
for (drop in drops) {
|
||||
drop.drop(this, location, player)
|
||||
}
|
||||
|
||||
xp.modify(event.event)
|
||||
|
||||
for ((index, damager) in entity.topDamagers.withIndex()) {
|
||||
val rewards = commandRewards[index + 1] ?: continue
|
||||
val damagerPlayer = Bukkit.getPlayer(damager.uuid) ?: continue
|
||||
for (reward in rewards) {
|
||||
reward.reward(damagerPlayer)
|
||||
}
|
||||
}
|
||||
|
||||
for (nearbyPlayer in entity.getNearbyEntities(
|
||||
nearbyCommandRewardRadius,
|
||||
nearbyCommandRewardRadius,
|
||||
nearbyCommandRewardRadius
|
||||
).filterIsInstance<Player>()) {
|
||||
for (command in nearbyCommands) {
|
||||
command.reward(nearbyPlayer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
Entities.registerCustomEntity(
|
||||
plugin.namespacedKeyFactory.create(id),
|
||||
CustomEntity(
|
||||
plugin.namespacedKeyFactory.create(id),
|
||||
{
|
||||
if (it !is LivingEntity) {
|
||||
return@CustomEntity false
|
||||
}
|
||||
|
||||
return@CustomEntity Bosses[it]?.boss == this
|
||||
},
|
||||
{
|
||||
this.spawn(it).entity
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is EcoBoss) {
|
||||
return false
|
||||
}
|
||||
|
||||
return id == other.id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return Objects.hash(id)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return ("EcoBoss{"
|
||||
+ id
|
||||
+ "}")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.display.Display
|
||||
import com.willfp.eco.core.display.DisplayModule
|
||||
import com.willfp.eco.core.display.DisplayPriority
|
||||
import com.willfp.eco.core.fast.fast
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class EggDisplay(
|
||||
plugin: EcoPlugin
|
||||
) : DisplayModule(
|
||||
plugin,
|
||||
DisplayPriority.LOW
|
||||
) {
|
||||
override fun display(itemStack: ItemStack, player: Player?, vararg args: Any) {
|
||||
if (player == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val fis = itemStack.fast()
|
||||
|
||||
val lore = fis.lore.toMutableList()
|
||||
|
||||
val egg = itemStack.bossEgg ?: return
|
||||
|
||||
val lines = egg.spawnConditions
|
||||
.filterNot { it.isMet(player) }
|
||||
.mapNotNull { it.notMetLines?.map { line -> Display.PREFIX + line } }
|
||||
.flatten()
|
||||
|
||||
|
||||
if (lines.isNotEmpty()) {
|
||||
lore.add(Display.PREFIX)
|
||||
lore.addAll(lines)
|
||||
}
|
||||
|
||||
fis.lore = lore
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.ecobosses.tick.BossTicker
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.entity.Mob
|
||||
import java.util.UUID
|
||||
|
||||
class LivingEcoBoss(
|
||||
plugin: EcoPlugin,
|
||||
private val uuid: UUID,
|
||||
val boss: EcoBoss,
|
||||
private val tickers: Set<BossTicker>
|
||||
) {
|
||||
private val ticker = plugin.runnableFactory.create {
|
||||
if (tick()) {
|
||||
it.cancel()
|
||||
}
|
||||
}.apply { runTaskTimer(1, 1) }
|
||||
|
||||
val entity: Mob?
|
||||
get() = Bukkit.getEntity(uuid) as? Mob
|
||||
|
||||
val deathTime = System.currentTimeMillis() + (boss.lifespan * 1000)
|
||||
|
||||
private var currentTick = 1 // Start at 1 as 0 is divisible by everything
|
||||
|
||||
private fun tick(): Boolean {
|
||||
if (entity == null || entity?.isDead == true) {
|
||||
remove()
|
||||
return true
|
||||
}
|
||||
|
||||
for (ticker in tickers) {
|
||||
ticker.tick(this, currentTick)
|
||||
}
|
||||
currentTick++
|
||||
return false
|
||||
}
|
||||
|
||||
fun remove() {
|
||||
ticker.cancel()
|
||||
entity?.remove()
|
||||
tickers.forEach { it.onDeath(this, currentTick) }
|
||||
|
||||
boss.markDead(uuid)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "LivingEcoBoss{boss=${boss}, uuid=${uuid}}"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.willfp.ecobosses.bosses
|
||||
|
||||
import com.google.common.collect.BiMap
|
||||
import com.google.common.collect.HashBiMap
|
||||
import com.google.common.collect.ImmutableList
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.entity.Entity
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class TargetMode(
|
||||
val id: String,
|
||||
private val function: (Collection<LivingEntity>, Entity) -> LivingEntity?
|
||||
) {
|
||||
init {
|
||||
BY_ID[this.id] = this
|
||||
}
|
||||
|
||||
fun getTarget(boss: LivingEcoBoss): LivingEntity? {
|
||||
val entity = boss.entity ?: return null
|
||||
|
||||
return function(
|
||||
entity.getNearbyEntities(
|
||||
boss.boss.targetRange,
|
||||
boss.boss.targetRange,
|
||||
boss.boss.targetRange
|
||||
).filterIsInstance<Player>()
|
||||
.filter { listOf(GameMode.SURVIVAL, GameMode.ADVENTURE).contains(it.gameMode) }
|
||||
.ifEmpty { return null },
|
||||
entity
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val BY_ID: BiMap<String, TargetMode> = HashBiMap.create()
|
||||
|
||||
val RANDOM = TargetMode("random") { entities, _ ->
|
||||
entities.random()
|
||||
}
|
||||
|
||||
val CLOSEST = TargetMode("closest") { entities, boss ->
|
||||
entities.minByOrNull { it.location.distanceSquared(boss.location) }
|
||||
}
|
||||
|
||||
val LOWEST_HEALTH = TargetMode("lowest_health") { entities, _ ->
|
||||
entities.minByOrNull { it.health }
|
||||
}
|
||||
|
||||
val HIGHEST_HEALTH = TargetMode("highest_health") { entities, _ ->
|
||||
entities.maxByOrNull { it.health }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun values(): List<TargetMode> {
|
||||
return ImmutableList.copyOf(BY_ID.values)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getByID(id: String): TargetMode? {
|
||||
return BY_ID[id]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.willfp.ecobosses.commands
|
||||
|
||||
import com.willfp.eco.core.command.impl.PluginCommand
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CommandEcobosses(plugin: EcoBossesPlugin) : PluginCommand(
|
||||
plugin,
|
||||
"ecobosses",
|
||||
"ecobosses.command.ecobosses",
|
||||
false
|
||||
) {
|
||||
override fun onExecute(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-command"))
|
||||
}
|
||||
|
||||
init {
|
||||
addSubcommand(CommandReload(plugin))
|
||||
.addSubcommand(CommandKillall(plugin))
|
||||
.addSubcommand(CommandSpawn(plugin))
|
||||
.addSubcommand(CommandGive(plugin))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.willfp.ecobosses.commands
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.command.impl.Subcommand
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.util.StringUtil
|
||||
import java.util.stream.Collectors
|
||||
|
||||
class CommandGive(plugin: EcoPlugin) : Subcommand(
|
||||
plugin,
|
||||
"give",
|
||||
"ecobosses.command.give",
|
||||
false
|
||||
) {
|
||||
override fun onExecute(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
) {
|
||||
if (args.isEmpty()) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("needs-player"))
|
||||
return
|
||||
}
|
||||
if (args.size == 1) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("needs-boss"))
|
||||
return
|
||||
}
|
||||
var amount = 1
|
||||
if (args.size > 2) {
|
||||
amount = args[2].toIntOrNull() ?: amount
|
||||
}
|
||||
|
||||
val recieverName = args[0]
|
||||
val reciever = Bukkit.getPlayer(recieverName)
|
||||
if (reciever == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-player"))
|
||||
return
|
||||
}
|
||||
val key = args[1]
|
||||
val boss = Bosses.getByID(key)
|
||||
|
||||
if (boss?.spawnEgg == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-boss"))
|
||||
return
|
||||
}
|
||||
|
||||
var message = plugin.langYml.getMessage("give-success")
|
||||
message = message.replace("%boss%", boss.id).replace("%recipient%", reciever.name)
|
||||
sender.sendMessage(message)
|
||||
|
||||
val itemStack = boss.spawnEgg!!
|
||||
|
||||
itemStack.amount = amount
|
||||
reciever.inventory.addItem(itemStack)
|
||||
}
|
||||
|
||||
override fun tabComplete(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
): List<String> {
|
||||
val completions = mutableListOf<String>()
|
||||
if (args.isEmpty()) {
|
||||
return BOSS_NAMES
|
||||
}
|
||||
|
||||
if (args.size == 1) {
|
||||
StringUtil.copyPartialMatches(args[0], Bukkit.getOnlinePlayers().stream().map { obj: Player -> obj.name }
|
||||
.collect(Collectors.toList()), completions)
|
||||
return completions
|
||||
}
|
||||
|
||||
if (args.size == 2) {
|
||||
StringUtil.copyPartialMatches(args[1], BOSS_NAMES, completions)
|
||||
completions.sort()
|
||||
return completions
|
||||
}
|
||||
|
||||
if (args.size == 3) {
|
||||
StringUtil.copyPartialMatches(args[2], NUMBERS, completions)
|
||||
completions.sortWith { s1: String, s2: String ->
|
||||
val t1 = s1.toInt()
|
||||
val t2 = s2.toInt()
|
||||
t1 - t2
|
||||
}
|
||||
return completions
|
||||
}
|
||||
return ArrayList(0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* The cached names.
|
||||
*/
|
||||
private val BOSS_NAMES: List<String>
|
||||
get() = Bosses.values().map { it.id }
|
||||
|
||||
|
||||
/**
|
||||
* The cached numbers.
|
||||
*/
|
||||
private val NUMBERS = listOf(
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"10",
|
||||
"32",
|
||||
"64"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.willfp.ecobosses.commands
|
||||
|
||||
import com.willfp.eco.core.command.impl.Subcommand
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CommandKillall(plugin: EcoBossesPlugin) : Subcommand(
|
||||
plugin,
|
||||
"killall",
|
||||
"ecobosses.command.killall",
|
||||
false
|
||||
) {
|
||||
override fun onExecute(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
) {
|
||||
val alive = Bosses.getAllAlive()
|
||||
|
||||
for (boss in alive) {
|
||||
boss.remove()
|
||||
}
|
||||
|
||||
sender.sendMessage(
|
||||
plugin.langYml.getMessage("killall").replace("%amount%", alive.size.toString())
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.willfp.ecobosses.commands
|
||||
|
||||
import com.willfp.eco.core.command.impl.Subcommand
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import org.bukkit.command.CommandSender
|
||||
|
||||
class CommandReload(plugin: EcoBossesPlugin) : Subcommand(
|
||||
plugin,
|
||||
"reload",
|
||||
"ecobosses.command.reload",
|
||||
false
|
||||
) {
|
||||
override fun onExecute(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
) {
|
||||
plugin.reload()
|
||||
sender.sendMessage(plugin.langYml.getMessage("reloaded"))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package com.willfp.ecobosses.commands
|
||||
|
||||
import com.willfp.eco.core.command.impl.Subcommand
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import com.willfp.ecobosses.events.BossSpawnEvent
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.World
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.util.StringUtil
|
||||
|
||||
class CommandSpawn(plugin: EcoBossesPlugin) : Subcommand(
|
||||
plugin,
|
||||
"spawn",
|
||||
"ecobosses.command.spawn",
|
||||
false
|
||||
) {
|
||||
override fun onExecute(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
) {
|
||||
if (args.isEmpty()) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("specify-boss"))
|
||||
return
|
||||
}
|
||||
|
||||
val bossName = args[0]
|
||||
val boss = Bosses.getByID(bossName.lowercase())
|
||||
if (boss == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("specify-boss"))
|
||||
return
|
||||
}
|
||||
|
||||
var location: Location? = null
|
||||
if (sender is Player) {
|
||||
location = sender.location
|
||||
}
|
||||
|
||||
if (args.size >= 4) {
|
||||
val xString = args[1]
|
||||
val yString = args[2]
|
||||
val zString = args[3]
|
||||
val xPos: Double
|
||||
val yPos: Double
|
||||
val zPos: Double
|
||||
if (xString.startsWith("~") && sender is Player) {
|
||||
val xDiff = xString.replace("~", "")
|
||||
val yDiff = yString.replace("~", "")
|
||||
val zDiff = zString.replace("~", "")
|
||||
xPos = if (xDiff.isEmpty()) {
|
||||
sender.location.x
|
||||
} else {
|
||||
try {
|
||||
sender.location.x + xDiff.toDouble()
|
||||
} catch (e: NumberFormatException) {
|
||||
sender.location.x
|
||||
}
|
||||
}
|
||||
yPos = if (yDiff.isEmpty()) {
|
||||
sender.location.y
|
||||
} else {
|
||||
try {
|
||||
sender.location.y + yDiff.toDouble()
|
||||
} catch (e: NumberFormatException) {
|
||||
sender.location.y
|
||||
}
|
||||
}
|
||||
zPos = if (zDiff.isEmpty()) {
|
||||
sender.location.z
|
||||
} else {
|
||||
try {
|
||||
sender.location.z + yDiff.toDouble()
|
||||
} catch (e: NumberFormatException) {
|
||||
sender.location.z
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
xPos = xString.toDouble()
|
||||
yPos = yString.toDouble()
|
||||
zPos = zString.toDouble()
|
||||
} catch (e: NumberFormatException) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-location"))
|
||||
return
|
||||
}
|
||||
}
|
||||
location = Location(null, xPos, yPos, zPos)
|
||||
}
|
||||
var world: World? = null
|
||||
if (sender is Player) {
|
||||
world = sender.world
|
||||
}
|
||||
if (args.size >= 5) {
|
||||
world = Bukkit.getWorld(args[4])
|
||||
}
|
||||
if (location == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-location"))
|
||||
return
|
||||
}
|
||||
|
||||
location.world = world
|
||||
|
||||
if (world == null) {
|
||||
sender.sendMessage(plugin.langYml.getMessage("invalid-world"))
|
||||
return
|
||||
}
|
||||
|
||||
val event = BossSpawnEvent(
|
||||
boss,
|
||||
location,
|
||||
BossSpawnEvent.SpawnReason.COMMAND,
|
||||
null
|
||||
)
|
||||
|
||||
Bukkit.getPluginManager().callEvent(event)
|
||||
|
||||
if (!event.isCancelled) {
|
||||
boss.spawn(location)
|
||||
}
|
||||
|
||||
sender.sendMessage(plugin.langYml.getMessage("spawned"))
|
||||
}
|
||||
|
||||
override fun tabComplete(
|
||||
sender: CommandSender,
|
||||
args: List<String>
|
||||
): List<String> {
|
||||
val completions = mutableListOf<String>()
|
||||
|
||||
if (args.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
if (args.size == 1) {
|
||||
StringUtil.copyPartialMatches(args[0], BOSS_NAMES, completions)
|
||||
completions.sort()
|
||||
return completions
|
||||
}
|
||||
if (args.size == 2) {
|
||||
StringUtil.copyPartialMatches(args[1], TILDE, completions)
|
||||
completions.sort()
|
||||
return completions
|
||||
}
|
||||
if (args.size == 3) {
|
||||
StringUtil.copyPartialMatches(args[2], TILDE, completions)
|
||||
completions.sort()
|
||||
return completions
|
||||
}
|
||||
if (args.size == 4) {
|
||||
StringUtil.copyPartialMatches(args[3], TILDE, completions)
|
||||
completions.sort()
|
||||
return completions
|
||||
}
|
||||
if (args.size == 5) {
|
||||
StringUtil.copyPartialMatches(args[4], Bukkit.getWorlds().map { it.name }, completions)
|
||||
completions.sort()
|
||||
return completions
|
||||
}
|
||||
return ArrayList(0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* The cached names.
|
||||
*/
|
||||
private val BOSS_NAMES: List<String>
|
||||
get() = Bosses.values().map { it.id }
|
||||
|
||||
/**
|
||||
* The cached numbers.
|
||||
*/
|
||||
private val TILDE = listOf(
|
||||
"~"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.willfp.ecobosses.config
|
||||
|
||||
import com.willfp.eco.core.config.BaseConfig
|
||||
import com.willfp.eco.core.config.ConfigType
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
|
||||
class EcoBossesYml(plugin: EcoBossesPlugin) : BaseConfig(
|
||||
"ecobosses",
|
||||
plugin,
|
||||
true,
|
||||
ConfigType.YAML
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.willfp.ecobosses.defence
|
||||
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.entity.Projectile
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
|
||||
class DamageMultiplierHandler : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: EntityDamageByEntityEvent) {
|
||||
val entity = event.entity as? LivingEntity ?: return
|
||||
val boss = Bosses[entity]?.boss ?: return
|
||||
|
||||
if (event.damager is Player) {
|
||||
event.damage *= boss.meleeDamageMultiplier
|
||||
|
||||
if (boss.meleeDamageMultiplier == 0.0) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
if (event.damager is Projectile) {
|
||||
event.damage *= boss.projectileDamageMultiplier
|
||||
|
||||
if (boss.projectileDamageMultiplier == 0.0) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.willfp.ecobosses.defence
|
||||
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageEvent
|
||||
|
||||
class ImmunitiesHandler : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: EntityDamageEvent) {
|
||||
val entity = event.entity as? LivingEntity ?: return
|
||||
val boss = Bosses[entity]?.boss ?: return
|
||||
|
||||
when (event.cause) {
|
||||
EntityDamageEvent.DamageCause.SUFFOCATION -> {
|
||||
if (boss.isImmuneToSuffocation) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
EntityDamageEvent.DamageCause.ENTITY_EXPLOSION, EntityDamageEvent.DamageCause.BLOCK_EXPLOSION -> {
|
||||
if (boss.isImmuneToExplosions) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
EntityDamageEvent.DamageCause.HOT_FLOOR, EntityDamageEvent.DamageCause.FIRE,
|
||||
EntityDamageEvent.DamageCause.FIRE_TICK, EntityDamageEvent.DamageCause.LAVA -> {
|
||||
if (boss.isImmuneToFire) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
EntityDamageEvent.DamageCause.DROWNING -> {
|
||||
if (boss.isImmuneToDrowning) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.willfp.ecobosses.defence
|
||||
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.spigotmc.event.entity.EntityMountEvent
|
||||
|
||||
class MountHandler : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: EntityMountEvent) {
|
||||
val entity = event.entity as? LivingEntity ?: return
|
||||
val boss = Bosses[entity]?.boss ?: return
|
||||
|
||||
if (boss.isPreventingMounts) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.willfp.ecobosses.defence
|
||||
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent
|
||||
|
||||
class PickupHandler : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: EntityPickupItemEvent) {
|
||||
val entity = event.entity as? LivingEntity ?: return
|
||||
Bosses[entity]?.boss ?: return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.willfp.ecobosses.events
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import com.willfp.ecobosses.lifecycle.BossLifecycle
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.entity.EntityDeathEvent
|
||||
|
||||
abstract class BossDeathEvent(
|
||||
val boss: LivingEcoBoss
|
||||
) : Event() {
|
||||
override fun getHandlers(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HANDLERS = HandlerList()
|
||||
|
||||
@JvmStatic
|
||||
fun getHandlerList(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.willfp.ecobosses.events
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import com.willfp.ecobosses.lifecycle.BossLifecycle
|
||||
import org.bukkit.event.HandlerList
|
||||
|
||||
class BossDespawnEvent(
|
||||
boss: LivingEcoBoss,
|
||||
) : BossDeathEvent(boss) {
|
||||
override fun getHandlers(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HANDLERS = HandlerList()
|
||||
|
||||
@JvmStatic
|
||||
fun getHandlerList(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.willfp.ecobosses.events
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import com.willfp.ecobosses.lifecycle.BossLifecycle
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.entity.EntityDeathEvent
|
||||
|
||||
class BossKillEvent(
|
||||
boss: LivingEcoBoss,
|
||||
val killer: Player?,
|
||||
val event: EntityDeathEvent
|
||||
) : BossDeathEvent(boss) {
|
||||
override fun getHandlers(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HANDLERS = HandlerList()
|
||||
|
||||
@JvmStatic
|
||||
fun getHandlerList(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.willfp.ecobosses.events
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.Cancellable
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.HandlerList
|
||||
|
||||
class BossSpawnEvent(
|
||||
val boss: EcoBoss,
|
||||
val location: Location,
|
||||
val reason: SpawnReason,
|
||||
val spawner: Player?
|
||||
) : Event(), Cancellable {
|
||||
private var isCancelled: Boolean = false
|
||||
|
||||
override fun isCancelled(): Boolean {
|
||||
return isCancelled
|
||||
}
|
||||
|
||||
override fun setCancelled(cancelled: Boolean) {
|
||||
isCancelled = cancelled
|
||||
}
|
||||
|
||||
override fun getHandlers(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
|
||||
enum class SpawnReason {
|
||||
TOTEM,
|
||||
EGG,
|
||||
COMMAND,
|
||||
AUTOSPAWN,
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HANDLERS = HandlerList()
|
||||
|
||||
@JvmStatic
|
||||
fun getHandlerList(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.willfp.ecobosses.events
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
class BossTryDropItemEvent(
|
||||
val boss: EcoBoss,
|
||||
val location: Location,
|
||||
var items: MutableCollection<ItemStack>,
|
||||
var chance: Double,
|
||||
val player: Player?
|
||||
): Event() {
|
||||
override fun getHandlers(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val HANDLERS = HandlerList()
|
||||
|
||||
@JvmStatic
|
||||
fun getHandlerList(): HandlerList {
|
||||
return HANDLERS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.willfp.ecobosses.integrations.levelledmobs
|
||||
|
||||
import com.willfp.eco.core.integrations.Integration
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import me.lokka30.levelledmobs.events.MobPreLevelEvent
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
|
||||
class IntegrationLevelledMobs : Listener, Integration {
|
||||
@EventHandler
|
||||
fun handle(event: MobPreLevelEvent) {
|
||||
if (Bosses[event.entity] != null) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPluginName(): String {
|
||||
return "LevelledMobs"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.willfp.ecobosses.lifecycle
|
||||
|
||||
enum class BossLifecycle(
|
||||
val isDeath: Boolean
|
||||
) {
|
||||
SPAWN(false),
|
||||
KILL(true),
|
||||
DESPAWN(true),
|
||||
INJURE(false)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.willfp.ecobosses.lifecycle
|
||||
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.SlimeSplitEvent
|
||||
|
||||
class CompatibilityListeners : Listener {
|
||||
@EventHandler
|
||||
fun handle(event: SlimeSplitEvent) {
|
||||
if (Bosses[event.entity as? LivingEntity ?: return] != null) {
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.willfp.ecobosses.lifecycle
|
||||
|
||||
import com.willfp.ecobosses.events.BossDespawnEvent
|
||||
import com.willfp.ecobosses.events.BossKillEvent
|
||||
import com.willfp.ecobosses.events.BossSpawnEvent
|
||||
import com.willfp.libreforge.LibReforgePlugin
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
|
||||
class ConsoleLoggers(
|
||||
private val plugin: LibReforgePlugin
|
||||
) : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: BossSpawnEvent) {
|
||||
if (!plugin.configYml.getBool("log-spawn-kill")) {
|
||||
return
|
||||
}
|
||||
|
||||
val location = "${event.location.world?.name}: ${event.location.x}, ${event.location.y}, ${event.location.z}"
|
||||
|
||||
plugin.logger.info("&a${event.boss.id}&r was spawned by &a${event.spawner?.name}&r at &a$location")
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: BossKillEvent) {
|
||||
if (!plugin.configYml.getBool("log-spawn-kill")) {
|
||||
return
|
||||
}
|
||||
|
||||
val loc = event.boss.entity?.location
|
||||
val location = "${loc?.world?.name}: ${loc?.x}, ${loc?.y}, ${loc?.z}"
|
||||
|
||||
plugin.logger.info("&a${event.boss.boss.id}&r was killed by &a${event.killer?.name}&r at &a$location")
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: BossDespawnEvent) {
|
||||
if (!plugin.configYml.getBool("log-spawn-kill")) {
|
||||
return
|
||||
}
|
||||
val loc = event.boss.entity?.location
|
||||
val location = "${loc?.world?.name}: ${loc?.x}, ${loc?.y}, ${loc?.z}"
|
||||
|
||||
plugin.logger.info("&a${event.boss.boss.id}&r despawned at &a$location")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.willfp.ecobosses.lifecycle
|
||||
|
||||
import com.willfp.eco.core.events.EntityDeathByEntityEvent
|
||||
import com.willfp.eco.util.tryAsPlayer
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import com.willfp.ecobosses.events.BossKillEvent
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDeathEvent
|
||||
|
||||
class DeathListeners : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: EntityDeathByEntityEvent) {
|
||||
val boss = Bosses[event.victim] ?: return
|
||||
|
||||
val deathEvent = BossKillEvent(boss, event.killer.tryAsPlayer(), event.deathEvent)
|
||||
Bukkit.getPluginManager().callEvent(deathEvent)
|
||||
|
||||
boss.remove()
|
||||
|
||||
event.drops.clear()
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: EntityDeathEvent) {
|
||||
val boss = Bosses[event.entity] ?: return
|
||||
|
||||
val deathEvent = BossKillEvent(boss, null, event)
|
||||
Bukkit.getPluginManager().callEvent(deathEvent)
|
||||
|
||||
boss.remove()
|
||||
|
||||
event.drops.clear()
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: BossKillEvent) {
|
||||
event.boss.boss.processRewards(event)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.willfp.ecobosses.lifecycle
|
||||
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import com.willfp.ecobosses.events.BossDeathEvent
|
||||
import com.willfp.ecobosses.events.BossDespawnEvent
|
||||
import com.willfp.ecobosses.events.BossKillEvent
|
||||
import com.willfp.ecobosses.events.BossSpawnEvent
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageEvent
|
||||
|
||||
class LifecycleHandlers : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: EntityDamageEvent) {
|
||||
val entity = event.entity as? LivingEntity ?: return
|
||||
val boss = Bosses[entity] ?: return
|
||||
|
||||
boss.boss.handleLifecycle(BossLifecycle.INJURE, entity.location, entity)
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: BossKillEvent) {
|
||||
val entity = event.boss.entity ?: return
|
||||
|
||||
event.boss.boss.handleLifecycle(BossLifecycle.KILL, entity.location, entity)
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: BossDespawnEvent) {
|
||||
val entity = event.boss.entity ?: return
|
||||
|
||||
event.boss.boss.handleLifecycle(BossLifecycle.DESPAWN, entity.location, entity)
|
||||
}
|
||||
|
||||
@EventHandler(
|
||||
ignoreCancelled = true,
|
||||
priority = EventPriority.MONITOR
|
||||
)
|
||||
fun handle(event: BossSpawnEvent) {
|
||||
event.boss.handleLifecycle(BossLifecycle.SPAWN, event.location, null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.willfp.ecobosses.spawn
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import com.willfp.ecobosses.events.BossSpawnEvent
|
||||
import org.bukkit.Bukkit
|
||||
|
||||
object AutospawnHandler {
|
||||
private var tick = 1
|
||||
|
||||
fun startSpawning(plugin: EcoPlugin) {
|
||||
plugin.scheduler.runTimer(1, 1) {
|
||||
for (boss in Bosses.values()) {
|
||||
if (boss.autoSpawnInterval < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (tick % boss.autoSpawnInterval != 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
val location = boss.autoSpawnLocations.randomOrNull() ?: continue
|
||||
val world = location.world ?: continue
|
||||
|
||||
if (plugin.configYml.getBool("autospawn.one-boss-per-world")) {
|
||||
if (Bosses.getAllAlive().mapNotNull { it.entity }.any { it.world == world }) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.AUTOSPAWN, null)
|
||||
|
||||
Bukkit.getPluginManager().callEvent(spawnEvent)
|
||||
|
||||
if (!spawnEvent.isCancelled) {
|
||||
boss.spawn(location)
|
||||
}
|
||||
}
|
||||
|
||||
tick++
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.willfp.ecobosses.spawn
|
||||
|
||||
import com.willfp.ecobosses.bosses.bossEgg
|
||||
import com.willfp.ecobosses.events.BossSpawnEvent
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.event.Event
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.Action
|
||||
import org.bukkit.event.player.PlayerInteractEvent
|
||||
import org.bukkit.inventory.EquipmentSlot
|
||||
|
||||
class SpawnEggHandler : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: PlayerInteractEvent) {
|
||||
if (event.action != Action.RIGHT_CLICK_BLOCK) {
|
||||
return
|
||||
}
|
||||
|
||||
val item = event.item ?: return
|
||||
val boss = item.bossEgg ?: return
|
||||
|
||||
event.isCancelled = true
|
||||
event.setUseItemInHand(Event.Result.DENY)
|
||||
|
||||
val location = event.clickedBlock?.location?.add(0.0, 1.5, 0.0) ?: return
|
||||
|
||||
val player = event.player
|
||||
|
||||
if (!boss.spawnConditions.all { it.condition.isConditionMet(player, it.config) }) {
|
||||
return
|
||||
}
|
||||
|
||||
val spawnEvent = BossSpawnEvent(boss, location, BossSpawnEvent.SpawnReason.EGG, player)
|
||||
|
||||
Bukkit.getPluginManager().callEvent(spawnEvent)
|
||||
|
||||
if (spawnEvent.isCancelled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.hand == EquipmentSlot.HAND) {
|
||||
val hand = event.player.inventory.itemInMainHand
|
||||
hand.amount = hand.amount - 1
|
||||
} else {
|
||||
val hand = event.player.inventory.itemInOffHand
|
||||
hand.amount = hand.amount - 1
|
||||
}
|
||||
|
||||
boss.spawn(location)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.willfp.ecobosses.spawn
|
||||
|
||||
import com.willfp.eco.util.containsIgnoreCase
|
||||
import com.willfp.ecobosses.bosses.Bosses
|
||||
import com.willfp.ecobosses.events.BossSpawnEvent
|
||||
import com.willfp.ecobosses.util.SpawnTotem
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.BlockPlaceEvent
|
||||
|
||||
class SpawnTotemHandler : Listener {
|
||||
@EventHandler(
|
||||
ignoreCancelled = true
|
||||
)
|
||||
fun handle(event: BlockPlaceEvent) {
|
||||
for (i in 0..2) {
|
||||
lateinit var top: Block
|
||||
lateinit var middle: Block
|
||||
lateinit var bottom: Block
|
||||
|
||||
// I know this code sucks ass, but I can't be arsed to write it nicely
|
||||
when (i) {
|
||||
0 -> {
|
||||
top = event.block
|
||||
middle = event.block.getRelative(0, -1, 0)
|
||||
bottom = event.block.getRelative(0, -2, 0)
|
||||
}
|
||||
1 -> {
|
||||
top = event.block.getRelative(0, 2, 0)
|
||||
middle = event.block.getRelative(0, 1, 0)
|
||||
bottom = event.block
|
||||
}
|
||||
2 -> {
|
||||
top = event.block.getRelative(0, 1, 0)
|
||||
middle = event.block
|
||||
bottom = event.block.getRelative(0, -1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
val placedTotem = SpawnTotem(top.type, middle.type, bottom.type)
|
||||
for (boss in Bosses.values()) {
|
||||
if (boss.totem == null || boss.disabledTotemWorlds.containsIgnoreCase(event.block.world.name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!boss.totem.matches(placedTotem)) {
|
||||
continue
|
||||
}
|
||||
|
||||
val player = event.player
|
||||
|
||||
if (!boss.spawnConditions.all { it.condition.isConditionMet(player, it.config) }) {
|
||||
return
|
||||
}
|
||||
|
||||
val spawnEvent = BossSpawnEvent(boss, event.block.location, BossSpawnEvent.SpawnReason.TOTEM, player)
|
||||
|
||||
Bukkit.getPluginManager().callEvent(spawnEvent)
|
||||
|
||||
if (!spawnEvent.isCancelled) {
|
||||
top.type = Material.AIR
|
||||
middle.type = Material.AIR
|
||||
bottom.type = Material.AIR
|
||||
|
||||
boss.spawn(event.block.location.add(0.0, 1.5, 0.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.willfp.ecobosses.tick
|
||||
|
||||
import com.willfp.eco.util.asAudience
|
||||
import com.willfp.eco.util.toComponent
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.attribute.Attribute
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class BossBarTicker(
|
||||
private val bar: BossBar
|
||||
) : BossTicker {
|
||||
override fun tick(boss: LivingEcoBoss, tick: Int) {
|
||||
val entity = boss.entity ?: return
|
||||
|
||||
bar.name(entity.customName!!.toComponent())
|
||||
bar.progress((entity.health / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH)!!.value).toFloat())
|
||||
|
||||
if (tick % 40 == 0) {
|
||||
for (player in Bukkit.getOnlinePlayers()) {
|
||||
player.asAudience().hideBossBar(bar)
|
||||
}
|
||||
entity.getNearbyEntities(
|
||||
boss.boss.bossBarRadius,
|
||||
boss.boss.bossBarRadius,
|
||||
boss.boss.bossBarRadius
|
||||
).filterIsInstance<Player>()
|
||||
.map { it.asAudience() }
|
||||
.forEach { it.showBossBar(bar) }
|
||||
}
|
||||
|
||||
if (tick % 10 != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
entity.target = boss.boss.targetMode.getTarget(boss) ?: return
|
||||
}
|
||||
|
||||
override fun onDeath(boss: LivingEcoBoss, tick: Int) {
|
||||
for (player in Bukkit.getOnlinePlayers()) {
|
||||
player.asAudience().hideBossBar(bar)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.willfp.ecobosses.tick
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
|
||||
interface BossTicker {
|
||||
fun tick(
|
||||
boss: LivingEcoBoss,
|
||||
tick: Int
|
||||
) {
|
||||
// Can be overridden when needed.
|
||||
}
|
||||
|
||||
fun onDeath(
|
||||
boss: LivingEcoBoss,
|
||||
tick: Int
|
||||
) {
|
||||
// Can be overridden when needed.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.willfp.ecobosses.tick
|
||||
|
||||
import com.willfp.eco.util.NumberUtils
|
||||
import com.willfp.eco.util.formatEco
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import kotlin.math.ceil
|
||||
|
||||
class DisplayNameTicker : BossTicker {
|
||||
override fun tick(boss: LivingEcoBoss, tick: Int) {
|
||||
val entity = boss.entity ?: return
|
||||
|
||||
val timeLeft = ceil(
|
||||
(boss.deathTime - System.currentTimeMillis()) / 1000.0
|
||||
).toInt()
|
||||
|
||||
val formattedTime = String.format("%d:%02d", timeLeft / 60, timeLeft % 60)
|
||||
|
||||
entity.customName = boss.boss.displayName
|
||||
.replace("%health%", NumberUtils.format(entity.health))
|
||||
.replace("%time%", formattedTime)
|
||||
.formatEco()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.willfp.ecobosses.tick
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import com.willfp.ecobosses.events.BossDespawnEvent
|
||||
import com.willfp.ecobosses.lifecycle.BossLifecycle
|
||||
import org.bukkit.Bukkit
|
||||
|
||||
class LifespanTicker : BossTicker {
|
||||
override fun tick(boss: LivingEcoBoss, tick: Int) {
|
||||
val timeLeft = (boss.deathTime - System.currentTimeMillis()) / 1000.0
|
||||
|
||||
if (timeLeft <= 0) {
|
||||
val event = BossDespawnEvent(boss)
|
||||
Bukkit.getPluginManager().callEvent(event)
|
||||
|
||||
boss.remove()
|
||||
boss.boss.handleLifecycle(
|
||||
BossLifecycle.DESPAWN,
|
||||
boss.entity?.location ?: return,
|
||||
boss.entity
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.willfp.ecobosses.tick
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
|
||||
class TargetTicker : BossTicker {
|
||||
override fun tick(boss: LivingEcoBoss, tick: Int) {
|
||||
val entity = boss.entity ?: return
|
||||
|
||||
if (tick % 10 != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
entity.target = boss.boss.targetMode.getTarget(boss) ?: return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.willfp.ecobosses.tick
|
||||
|
||||
import com.willfp.ecobosses.bosses.LivingEcoBoss
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.block.BlockFace
|
||||
|
||||
class TeleportHandler : BossTicker {
|
||||
override fun tick(boss: LivingEcoBoss, tick: Int) {
|
||||
val entity = boss.entity ?: return
|
||||
if (!boss.boss.canTeleport) {
|
||||
return
|
||||
}
|
||||
|
||||
if (tick % boss.boss.teleportInterval != 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val range = boss.boss.teleportRange
|
||||
|
||||
val validLocations = mutableListOf<Location>()
|
||||
|
||||
for (x in -range..range) {
|
||||
for (y in -range..range) {
|
||||
for (z in -range..range) {
|
||||
val location = entity.location.clone().apply {
|
||||
this.x += x
|
||||
this.y += y
|
||||
this.z += z
|
||||
}
|
||||
val block = location.block
|
||||
|
||||
if (block.type == Material.AIR && block.getRelative(BlockFace.UP).type == Material.AIR && !(block.getRelative(
|
||||
BlockFace.DOWN
|
||||
).isLiquid || block.getRelative(BlockFace.DOWN).type == Material.AIR)
|
||||
) {
|
||||
validLocations.add(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validLocations.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
entity.teleport(validLocations.random())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.willfp.ecobosses.util
|
||||
|
||||
import com.willfp.eco.core.EcoPlugin
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Keyed
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.inventory.Recipe
|
||||
|
||||
class DiscoverRecipeListener(private val plugin: EcoPlugin) : Listener {
|
||||
@EventHandler
|
||||
fun onJoin(event: PlayerJoinEvent) {
|
||||
if (!plugin.configYml.getBool("discover-recipes")) {
|
||||
return
|
||||
}
|
||||
mutableListOf<Recipe>()
|
||||
.apply { Bukkit.getServer().recipeIterator().forEachRemaining(this::add) }
|
||||
.filterIsInstance<Keyed>().map { it.key }
|
||||
.filter { it.namespace == plugin.name.lowercase() }
|
||||
.filter { !it.key.contains("displayed") }
|
||||
.forEach { event.player.discoverRecipe(it) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.willfp.ecobosses.util
|
||||
|
||||
import com.willfp.eco.util.tryAsPlayer
|
||||
import com.willfp.ecobosses.EcoBossesPlugin
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.EventPriority
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent
|
||||
import java.util.*
|
||||
|
||||
data class Damager(
|
||||
val uuid: UUID,
|
||||
var damage: Double
|
||||
)
|
||||
|
||||
private const val metaKey = "TOP_DAMAGERS"
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
var LivingEntity.topDamagers: List<Damager>
|
||||
get() = (this.getMetadata(metaKey).getOrNull(0)?.value() as? List<Damager>) ?: emptyList()
|
||||
private set(value) {
|
||||
this.removeMetadata(metaKey, EcoBossesPlugin.instance)
|
||||
this.setMetadata(metaKey, EcoBossesPlugin.instance.metadataValueFactory.create(value))
|
||||
}
|
||||
|
||||
class TopDamagerListener : Listener {
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
fun handle(event: EntityDamageByEntityEvent) {
|
||||
val uuid = event.damager.tryAsPlayer()?.uniqueId ?: return
|
||||
|
||||
val victim = event.entity as? LivingEntity ?: return
|
||||
|
||||
val topDamagers = victim.topDamagers.toMutableList()
|
||||
|
||||
val damager = topDamagers.firstOrNull { it.uuid == uuid } ?: Damager(uuid, 0.0)
|
||||
damager.damage += event.damage
|
||||
topDamagers.removeIf { it.uuid == uuid }
|
||||
topDamagers.add(damager)
|
||||
victim.topDamagers = topDamagers.sortedByDescending { it.damage }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user