mirror of
https://github.com/Auxilor/EcoMobs.git
synced 2025-12-22 16:39:25 +00:00
Continued rewrite
This commit is contained in:
@@ -1,64 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick.tickers;
|
||||
|
||||
import com.willfp.eco.util.PlayerUtils;
|
||||
import com.willfp.eco.util.StringUtils;
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.tick.BossTicker;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
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.name(StringUtils.toComponent(entity.getCustomName()));
|
||||
bossBar.progress((float) (entity.getHealth() / entity.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()));
|
||||
|
||||
if (tick % 40 == 0) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
PlayerUtils.getAudience(player).hideBossBar(bossBar);
|
||||
}
|
||||
entity.getNearbyEntities(radius, radius, radius).forEach(entity1 -> {
|
||||
if (entity1 instanceof Player) {
|
||||
PlayerUtils.getAudience((Player) entity1).showBossBar(bossBar);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(@NotNull final EcoBoss boss,
|
||||
@Nullable final LivingEntity entity,
|
||||
final long tick) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
PlayerUtils.getAudience(player).hideBossBar(bossBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick.tickers;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.bosses.util.obj.OptionedSound;
|
||||
import com.willfp.ecobosses.tick.BossTicker;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DeathTimeTicker implements BossTicker {
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
if (boss.getTimeToLive() < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int timeLeft;
|
||||
timeLeft = (int) (entity.getMetadata("death-time").get(0).asLong() - System.currentTimeMillis());
|
||||
timeLeft = (int) Math.ceil(timeLeft / 1000D);
|
||||
if (timeLeft <= 0) {
|
||||
entity.remove();
|
||||
boss.removeLivingBoss(entity);
|
||||
|
||||
for (String despawnMessage : boss.getDespawnMessages()) {
|
||||
Bukkit.broadcastMessage(despawnMessage);
|
||||
}
|
||||
|
||||
for (OptionedSound sound : boss.getDespawnSounds()) {
|
||||
entity.getWorld().playSound(entity.getLocation(), sound.sound(), sound.volume(), sound.pitch());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +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.tick.BossTicker;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NamePlaceholderTicker implements BossTicker {
|
||||
@Override
|
||||
public void tick(@NotNull final EcoBoss boss,
|
||||
@NotNull final LivingEntity entity,
|
||||
final long tick) {
|
||||
int timeLeft = -1;
|
||||
if (boss.getTimeToLive() > 0) {
|
||||
timeLeft = (int) (entity.getMetadata("death-time").get(0).asLong() - System.currentTimeMillis());
|
||||
timeLeft = (int) Math.ceil(timeLeft / 1000D);
|
||||
}
|
||||
|
||||
String time = "";
|
||||
if (timeLeft > 0) {
|
||||
time = String.format("%d:%02d", timeLeft/60, timeLeft%60);
|
||||
}
|
||||
entity.setCustomName(
|
||||
boss.getDisplayName()
|
||||
.replace("%health%", StringUtils.internalToString(entity.getHealth()))
|
||||
.replace("%time%", time)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.tick.tickers;
|
||||
|
||||
import com.willfp.ecobosses.bosses.EcoBoss;
|
||||
import com.willfp.ecobosses.tick.BossTicker;
|
||||
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,8 +0,0 @@
|
||||
package com.willfp.ecobosses.bosses.util.obj;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record ArgumentedEffectName(@NotNull String name, @NotNull List<String> args) {
|
||||
}
|
||||
@@ -3,6 +3,6 @@ package com.willfp.ecobosses.bosses
|
||||
enum class BossLifecycle {
|
||||
SPAWN,
|
||||
KILL,
|
||||
DESPAWN
|
||||
DESPAWN,
|
||||
INJURE
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,23 @@ import com.willfp.eco.core.EcoPlugin
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
import com.willfp.eco.core.entities.Entities
|
||||
import com.willfp.eco.core.entities.TestableEntity
|
||||
import com.willfp.eco.core.items.Items
|
||||
import com.willfp.eco.util.toComponent
|
||||
import com.willfp.ecobosses.tick.BossBarTicker
|
||||
import com.willfp.ecobosses.tick.BossTicker
|
||||
import com.willfp.ecobosses.tick.DisplayNameTicker
|
||||
import com.willfp.ecobosses.tick.LifespanTicker
|
||||
import com.willfp.ecobosses.tick.TargetTicker
|
||||
import com.willfp.ecobosses.util.BossDrop
|
||||
import com.willfp.ecobosses.util.CommandReward
|
||||
import com.willfp.ecobosses.util.ConfiguredSound
|
||||
import com.willfp.ecobosses.util.LocalBroadcast
|
||||
import com.willfp.ecobosses.util.PlayableSound
|
||||
import com.willfp.ecobosses.util.XpReward
|
||||
import com.willfp.libreforge.Holder
|
||||
import com.willfp.libreforge.conditions.ConfiguredCondition
|
||||
import com.willfp.libreforge.effects.ConfiguredEffect
|
||||
import com.willfp.libreforge.effects.Effects
|
||||
import net.kyori.adventure.bossbar.BossBar
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.LivingEntity
|
||||
import org.bukkit.entity.Player
|
||||
@@ -36,6 +43,14 @@ class EcoBoss(
|
||||
|
||||
val targetMode = TargetMode.getByID(config.getString("target.mode"))!!
|
||||
|
||||
val isBossBarEnabled = config.getBool("bossBar.enabled")
|
||||
|
||||
val bossBarRadius = config.getDouble("bossBar.radius")
|
||||
|
||||
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>()
|
||||
|
||||
@@ -48,6 +63,79 @@ class EcoBoss(
|
||||
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 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) }
|
||||
.map { it.item }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
|
||||
private val mob: TestableEntity = Entities.lookup(config.getString("mob"))
|
||||
|
||||
private val currentlyAlive = mutableMapOf<UUID, LivingEcoBoss>()
|
||||
@@ -85,15 +173,39 @@ class EcoBoss(
|
||||
}
|
||||
|
||||
private fun createTickersFor(entity: LivingEntity): Set<BossTicker> {
|
||||
return setOf(
|
||||
val tickers = mutableSetOf(
|
||||
LifespanTicker(),
|
||||
DisplayNameTicker(),
|
||||
TargetTicker()
|
||||
)
|
||||
|
||||
if (isBossBarEnabled) {
|
||||
tickers.add(
|
||||
BossBarTicker(
|
||||
BossBar.bossBar(
|
||||
this.displayName.toComponent(),
|
||||
1.0f,
|
||||
bossBarColor,
|
||||
bossBarStyle
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return tickers
|
||||
}
|
||||
|
||||
fun handleLifecycle(player: Player, lifecycle: BossLifecycle) {
|
||||
sounds[lifecycle]?.play(player)
|
||||
fun handleLifecycle(lifecycle: BossLifecycle, location: Location) {
|
||||
sounds[lifecycle]?.play(location)
|
||||
messages[lifecycle]?.forEach { it.broadcast(location) }
|
||||
}
|
||||
|
||||
fun processRewards(player: Player, location: Location) {
|
||||
for (drop in drops) {
|
||||
drop.drop(location, player)
|
||||
}
|
||||
|
||||
xp.drop(location, player)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@@ -114,8 +226,3 @@ class EcoBoss(
|
||||
+ "}")
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleHolder(
|
||||
override val conditions: Set<ConfiguredCondition>,
|
||||
override val effects: Set<ConfiguredEffect>
|
||||
) : Holder
|
||||
@@ -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,33 @@
|
||||
package com.willfp.ecobosses.util
|
||||
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
data class LocalBroadcast(
|
||||
val messages: Iterable<String>,
|
||||
val radius: Double
|
||||
) {
|
||||
fun broadcast(location: Location) {
|
||||
if (radius < 0) {
|
||||
for (message in messages) {
|
||||
Bukkit.broadcastMessage(message)
|
||||
}
|
||||
} else {
|
||||
val world = location.world ?: return
|
||||
world.getNearbyEntities(location, radius, radius, radius)
|
||||
.filterIsInstance<Player>()
|
||||
.forEach { player -> messages.forEach { player.sendMessage(it) } }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromConfig(config: Config): LocalBroadcast {
|
||||
return LocalBroadcast(
|
||||
config.getFormattedStrings("message"),
|
||||
config.getDouble("radius")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
package com.willfp.ecobosses.util
|
||||
|
||||
import com.willfp.eco.core.config.interfaces.Config
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Sound
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
data class ConfiguredSound(
|
||||
private val sound: Sound,
|
||||
private val pitch: Double,
|
||||
private val volume: Double
|
||||
) {
|
||||
fun play(player: Player) {
|
||||
player.playSound(player.location, sound, volume.toFloat(), pitch.toFloat())
|
||||
fun play(location: Location) {
|
||||
location.world?.playSound(location, sound, volume.toFloat(), pitch.toFloat())
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -27,9 +27,9 @@ data class ConfiguredSound(
|
||||
data class PlayableSound(
|
||||
val sounds: Iterable<ConfiguredSound>
|
||||
) {
|
||||
fun play(player: Player) {
|
||||
fun play(location: Location) {
|
||||
for (sound in sounds) {
|
||||
sound.play(player)
|
||||
sound.play(location)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.willfp.ecobosses.util
|
||||
|
||||
import com.willfp.eco.core.drops.DropQueue
|
||||
import com.willfp.eco.util.NumberUtils
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
|
||||
data class BossDrop(
|
||||
val chance: Double,
|
||||
val drops: Collection<ItemStack>
|
||||
) {
|
||||
fun drop(location: Location, player: Player) {
|
||||
if (NumberUtils.randFloat(0.0, 100.0) < chance) {
|
||||
DropQueue(player)
|
||||
.setLocation(location)
|
||||
.addItems(drops)
|
||||
.push()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class CommandReward(
|
||||
val chance: Double,
|
||||
val commands: Collection<String>
|
||||
) {
|
||||
fun reward(player: Player) {
|
||||
if (NumberUtils.randFloat(0.0, 100.0) < chance) {
|
||||
for (command in commands) {
|
||||
Bukkit.getServer().dispatchCommand(
|
||||
Bukkit.getConsoleSender(),
|
||||
command.replace("%player%", player.name)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class XpReward(
|
||||
val minimum: Int,
|
||||
val maximum: Int
|
||||
) {
|
||||
fun drop(location: Location, player: Player) {
|
||||
DropQueue(player)
|
||||
.setLocation(location)
|
||||
.addXP(NumberUtils.randInt(minimum, maximum))
|
||||
.push()
|
||||
}
|
||||
}
|
||||
@@ -22,4 +22,78 @@ bosses:
|
||||
- id: steel_golem
|
||||
mob: iron_golem
|
||||
displayName: "&8Steel Golem &7| &c%health%♥ &7| &e%time%"
|
||||
effects: [ ]
|
||||
effects: [ ]
|
||||
rewards:
|
||||
xp:
|
||||
minimum: 30000
|
||||
maximum: 60000
|
||||
topDamagerCommands:
|
||||
1: []
|
||||
2: []
|
||||
3: []
|
||||
nearbyPlayerCommands:
|
||||
radius: 10
|
||||
commands: []
|
||||
drops: []
|
||||
target:
|
||||
mode: highest_health
|
||||
range: 40
|
||||
bossBar:
|
||||
enabled: true
|
||||
color: white
|
||||
style: solid
|
||||
radius: 120
|
||||
messages:
|
||||
spawn:
|
||||
- message:
|
||||
- ""
|
||||
- "&fA &8&lSteel Golem&r&f has been spawned!"
|
||||
- "&fCome fight it at &8%x%&f, &8%y%&f, &8%z%&f!"
|
||||
- ""
|
||||
radius: -1
|
||||
kill:
|
||||
- message:
|
||||
- ""
|
||||
- "&fThe &8&lSteel Golem&r&f has been killed!"
|
||||
- "&fMost Damage:"
|
||||
- "&f - &8%damage_1_player%&f (%damage_1% Damage)"
|
||||
- "&f - &8%damage_2_player%&f (%damage_2% Damage)"
|
||||
- "&f - &8%damage_3_player%&f (%damage_3% Damage)"
|
||||
- ""
|
||||
radius: -1
|
||||
despawn:
|
||||
- message:
|
||||
- ""
|
||||
- "&fYou ran out of time to kill the &8&lSteel Golem&r&f!"
|
||||
- ""
|
||||
radius: -1
|
||||
injure: [ ]
|
||||
sounds:
|
||||
spawn:
|
||||
- sound: entity_iron_golem_death
|
||||
pitch: 0.8
|
||||
volume: 100
|
||||
- sound: entity_iron_golem_hurt
|
||||
pitch: 0.5
|
||||
volume: 100
|
||||
- sound: entity_ender_dragon_growl
|
||||
pitch: 0.5
|
||||
volume: 100
|
||||
kill:
|
||||
- sound: entity_ender_dragon_death
|
||||
pitch: 1.8
|
||||
volume: 100
|
||||
- sound: entity_wither_death
|
||||
pitch: 1.2
|
||||
volume: 100
|
||||
despawn:
|
||||
- sound: entity_ender_dragon_ambient
|
||||
pitch: 0.5
|
||||
volume: 50
|
||||
- sound: entity_enderman_death
|
||||
pitch: 0.5
|
||||
volume: 50
|
||||
injure:
|
||||
- sound: entity_iron_golem_damage
|
||||
pitch: 0.7
|
||||
volume: 10
|
||||
Reference in New Issue
Block a user