diff --git a/src/main/java/world/bentobox/acidisland/AISettings.java b/src/main/java/world/bentobox/acidisland/AISettings.java index 47bef56..2236dac 100644 --- a/src/main/java/world/bentobox/acidisland/AISettings.java +++ b/src/main/java/world/bentobox/acidisland/AISettings.java @@ -69,7 +69,7 @@ public class AISettings implements WorldSettings { @ConfigEntry(path = "acid.damage.acid.item") private long acidDestroyItemTime = 0; - @ConfigComment("Damage from acid rain") + @ConfigComment("Damage from acid rain (and snow, if toggled on).") @ConfigEntry(path = "acid.damage.rain") private int acidRainDamage = 1; @@ -82,12 +82,34 @@ public class AISettings implements WorldSettings { @ConfigEntry(path = "acid.damage.delay") private long acidDamageDelay = 2; - @ConfigComment("Portion effects from going into acid water") - @ConfigComment("You can list multiple effects") + @ConfigComment("Potion effects from going into acid water.") + @ConfigComment("You can list multiple effects.") + @ConfigComment("Available effects are:") + @ConfigComment(" BLINDNESS") + @ConfigComment(" CONFUSION") + @ConfigComment(" HUNGER") + @ConfigComment(" POISON") + @ConfigComment(" SLOW") + @ConfigComment(" SLOW_DIGGING") + @ConfigComment(" WEAKNESS") @ConfigEntry(path = "acid.damage.effects") @Adapter(PotionEffectListAdapter.class) private List acidEffects = new ArrayList<>(); + @ConfigComment("Potion effects from going into acid rain and snow.") + @ConfigComment("You can list multiple effects.") + @ConfigComment("Available effects are:") + @ConfigComment(" BLINDNESS") + @ConfigComment(" CONFUSION") + @ConfigComment(" HUNGER") + @ConfigComment(" POISON") + @ConfigComment(" SLOW") + @ConfigComment(" SLOW_DIGGING") + @ConfigComment(" WEAKNESS") + @ConfigEntry(path = "acid.damage.rain-effects", since = "1.9.1") + @Adapter(PotionEffectListAdapter.class) + private List acidRainEffects = new ArrayList<>(); + @ConfigComment("If player wears a helmet then they will not suffer from acid rain") @ConfigEntry(path = "acid.damage.protection.helmet") private boolean helmetProtection; @@ -1517,6 +1539,7 @@ public class AISettings implements WorldSettings { /** * @return the pasteMissingIslands + * @since 1.10.0 */ @Override public boolean isPasteMissingIslands() { @@ -1525,8 +1548,27 @@ public class AISettings implements WorldSettings { /** * @param pasteMissingIslands the pasteMissingIslands to set + * @since 1.10.0 */ public void setPasteMissingIslands(boolean pasteMissingIslands) { this.pasteMissingIslands = pasteMissingIslands; } + + /** + * Get acid rain potion effects + * @return liust of potion effects + * @since 1.9.1 + */ + public List getAcidRainEffects() { + return acidRainEffects; + } + + /** + * + * @param acidRainEffects + * @since 1.9.1 + */ + public void setAcidRainEffects(List acidRainEffects) { + this.acidRainEffects = acidRainEffects; + } } diff --git a/src/main/java/world/bentobox/acidisland/events/AcidEvent.java b/src/main/java/world/bentobox/acidisland/events/AcidEvent.java index 80d9ff0..48cf8f0 100644 --- a/src/main/java/world/bentobox/acidisland/events/AcidEvent.java +++ b/src/main/java/world/bentobox/acidisland/events/AcidEvent.java @@ -1,6 +1,5 @@ package world.bentobox.acidisland.events; -import java.util.ArrayList; import java.util.List; import org.bukkit.entity.Player; @@ -21,7 +20,7 @@ public class AcidEvent extends Event implements Cancellable { private Player player; private double totalDamage; private final double protection; - private List potionEffects = new ArrayList<>(); + private List potionEffects; /** * @param player - player diff --git a/src/main/java/world/bentobox/acidisland/events/AcidRainEvent.java b/src/main/java/world/bentobox/acidisland/events/AcidRainEvent.java index c6f6962..f1ab40e 100644 --- a/src/main/java/world/bentobox/acidisland/events/AcidRainEvent.java +++ b/src/main/java/world/bentobox/acidisland/events/AcidRainEvent.java @@ -1,9 +1,12 @@ package world.bentobox.acidisland.events; +import java.util.List; + import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +import org.bukkit.potion.PotionEffectType; /** * This event is fired when a player is going to be burned by acid rain @@ -17,6 +20,10 @@ public class AcidRainEvent extends Event implements Cancellable { private Player player; private double rainDamage; private final double protection; + /** + * @since 1.9.1 + */ + private List potionEffects; private boolean cancelled; @@ -26,10 +33,11 @@ public class AcidRainEvent extends Event implements Cancellable { * @param rainDamage * @param protection */ - public AcidRainEvent(Player player, double rainDamage, double protection) { + public AcidRainEvent(Player player, double rainDamage, double protection, List potionEffects) { this.player = player; this.rainDamage = rainDamage; this.protection = protection; + this.potionEffects = potionEffects; } /** @@ -69,6 +77,24 @@ public class AcidRainEvent extends Event implements Cancellable { this.rainDamage = rainDamage; } + /** + * Returns the potion effects that will be applied to the player. + * @return list of potion effect types + * @since 1.9.1 + */ + public List getPotionEffects() { + return potionEffects; + } + + /** + * + * @param potionEffects the potionEffects to set + * @since 1.9.1 + */ + public void setPotionEffects(List potionEffects) { + this.potionEffects = potionEffects; + } + @Override public HandlerList getHandlers() { return handlers; diff --git a/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java b/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java index 0f30431..21228ba 100644 --- a/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java +++ b/src/main/java/world/bentobox/acidisland/listeners/AcidEffect.java @@ -9,6 +9,7 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; +import org.bukkit.World.Environment; import org.bukkit.attribute.Attribute; import org.bukkit.block.BlockFace; import org.bukkit.entity.EntityType; @@ -116,11 +117,16 @@ public class AcidEffect implements Listener { } else if (wetPlayers.containsKey(player) && wetPlayers.get(player) < System.currentTimeMillis()) { double protection = addon.getSettings().getAcidRainDamage() * getDamageReduced(player); double totalDamage = Math.max(0, addon.getSettings().getAcidRainDamage() - protection); - AcidRainEvent e = new AcidRainEvent(player, totalDamage, protection); - addon.getServer().getPluginManager().callEvent(e); - if (!e.isCancelled()) { - player.damage(e.getRainDamage()); - player.getWorld().playSound(playerLoc, Sound.ENTITY_CREEPER_PRIMED, 3F, 3F); + AcidRainEvent event = new AcidRainEvent(player, totalDamage, protection, addon.getSettings().getAcidRainEffects()); + addon.getServer().getPluginManager().callEvent(event); + if (!event.isCancelled()) { + event.getPotionEffects().stream().filter(EFFECTS::contains).forEach(t -> player.addPotionEffect(new PotionEffect(t, 600, 1))); + event.getPotionEffects().stream().filter(e -> e.equals(PotionEffectType.POISON)).forEach(t -> player.addPotionEffect(new PotionEffect(t, 200, 1))); + // Apply damage if there is any + if (event.getRainDamage() > 0D) { + player.damage(event.getRainDamage()); + player.getWorld().playSound(playerLoc, Sound.ENTITY_CREEPER_PRIMED, 3F, 3F); + } } } } @@ -172,11 +178,13 @@ public class AcidEffect implements Listener { * @return true if they are safe */ private boolean isSafeFromRain(Player player) { - if (addon.getSettings().isHelmetProtection() && (player.getInventory().getHelmet() != null - && player.getInventory().getHelmet().getType().name().contains("HELMET")) + if (player.getWorld().getEnvironment().equals(Environment.NETHER) + || player.getWorld().getEnvironment().equals(Environment.THE_END) + || (addon.getSettings().isHelmetProtection() && (player.getInventory().getHelmet() != null && player.getInventory().getHelmet().getType().name().contains("HELMET"))) || (!addon.getSettings().isAcidDamageSnow() && player.getLocation().getBlock().getTemperature() < 0.1) // snow falls || player.getLocation().getBlock().getHumidity() == 0 // dry - || (player.getActivePotionEffects().stream().map(PotionEffect::getType).anyMatch(IMMUNE_EFFECTS::contains))) { + || (player.getActivePotionEffects().stream().map(PotionEffect::getType).anyMatch(IMMUNE_EFFECTS::contains)) + ) { return true; } // Check if all air above player diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b549d68..ff9cf99 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -19,18 +19,38 @@ acid: animal: 5 # Destroy items after this many seconds in acid. 0 = do not destroy items item: 0 - # Damage from acid rain + # Damage from acid rain (and snow, if toggled on). rain: 1 # Damage from acid snow snow: false # Delay before acid or acid rain starts burning # This can give time for conduit power to kick in delay: 2 - # Portion effects from going into acid water - # You can list multiple effects + # Potion effects from going into acid water. + # You can list multiple effects. + # Available effects are: + # BLINDNESS + # CONFUSION + # HUNGER + # POISON + # SLOW + # SLOW_DIGGING + # WEAKNESS effects: - CONFUSION - BLINDNESS + # Potion effects from going into acid rain and snow. + # You can list multiple effects. + # Available effects are: + # BLINDNESS + # CONFUSION + # HUNGER + # POISON + # SLOW + # SLOW_DIGGING + # WEAKNESS + # Added since 1.9.1. + rain-effects: [] protection: # If player wears a helmet then they will not suffer from acid rain helmet: false @@ -131,10 +151,10 @@ world: # This setting is toggled in world flags and set by the settings GUI. # Mob white list - these mobs will NOT be removed when logging in or doing /island remove-mobs-whitelist: - - ZOMBIE_VILLAGER - - WITHER - PIG_ZOMBIE + - WITHER - ENDERMAN + - ZOMBIE_VILLAGER # World flags. These are boolean settings for various flags for this world flags: CREEPER_DAMAGE: true @@ -173,14 +193,14 @@ world: END_PORTAL: 500 BREEDING: 500 HURT_VILLAGERS: 500 - TURTLE_EGGS: 500 FROST_WALKER: 500 + TURTLE_EGGS: 500 COLLECT_LAVA: 500 LEVER: 500 ELYTRA: 0 - RIDING: 500 HURT_MONSTERS: 0 CAKE: 500 + RIDING: 500 ARMOR_STAND: 500 NAME_TAG: 500 TRADING: 0 @@ -189,10 +209,10 @@ world: NOTE_BLOCK: 0 FLINT_AND_STEEL: 500 NETHER_PORTAL: 500 - CROP_TRAMPLE: 500 ITEM_PICKUP: 0 - BREWING: 500 + CROP_TRAMPLE: 500 DROPPER: 500 + BREWING: 500 TNT_PRIMING: 500 COLLECT_WATER: 500 BUTTON: 500 @@ -203,8 +223,8 @@ world: EXPERIENCE_BOTTLE_THROWING: 500 PRESSURE_PLATE: 0 DYE: 500 - ITEM_FRAME: 500 PLACE_BLOCKS: 500 + ITEM_FRAME: 500 CRAFTING: 0 ENCHANTING: 0 SHEARING: 500 @@ -217,12 +237,12 @@ world: EXPERIENCE_PICKUP: 500 HOPPER: 500 LEASH: 500 - BREAK_BLOCKS: 500 MOUNT_INVENTORY: 500 + BREAK_BLOCKS: 500 CHORUS_FRUIT: 500 CONTAINER: 500 - JUKEBOX: 500 POTION_THROWING: 500 + JUKEBOX: 500 # These are the default settings for new islands default-island-settings: PVP_END: false @@ -230,8 +250,8 @@ world: PVP_NETHER: false LEAF_DECAY: true TNT_DAMAGE: true - FIRE_IGNITE: true MONSTER_SPAWN: true + FIRE_IGNITE: true FIRE_SPREAD: true FIRE_BURNING: true PVP_OVERWORLD: false @@ -257,7 +277,7 @@ island: # Use this permission to set for specific user groups: acidisland.island.maxhomes. max-homes: 1 reset: - # How many resets a player is allowed (override with /acid clearresets ) + # How many resets a player is allowed (manage with /acid reset add/remove/reset/set command) # Value of -1 means unlimited, 0 means hardcore - no resets. # Example, 2 resets means they get 2 resets or 3 islands lifetime reset-limit: -1 diff --git a/src/test/java/world/bentobox/acidisland/events/AcidRainEventTest.java b/src/test/java/world/bentobox/acidisland/events/AcidRainEventTest.java index 7aac502..c8899a6 100644 --- a/src/test/java/world/bentobox/acidisland/events/AcidRainEventTest.java +++ b/src/test/java/world/bentobox/acidisland/events/AcidRainEventTest.java @@ -7,19 +7,27 @@ import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffectType; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class AcidRainEventTest { @Mock private Player player; + private List effects; private AcidRainEvent e; @Before public void setUp() throws Exception { - e = new AcidRainEvent(player, 10, 5); + effects = Arrays.asList(PotionEffectType.values()); + e = new AcidRainEvent(player, 10, 5, effects); } @Test @@ -55,6 +63,17 @@ public class AcidRainEventTest { assertTrue(e.getRainDamage() == 50D); } + @Test + public void testGetPotionEffects() { + Assert.assertArrayEquals(PotionEffectType.values(), e.getPotionEffects().toArray()); + } + + @Test + public void testSetPotionEffects() { + e.setPotionEffects(new ArrayList<>()); + assertTrue(e.getPotionEffects().isEmpty()); + } + @Test public void testIsCancelled() { assertFalse(e.isCancelled()); diff --git a/src/test/java/world/bentobox/acidisland/listeners/AcidEffectTest.java b/src/test/java/world/bentobox/acidisland/listeners/AcidEffectTest.java index 43bc5a3..ab7e93c 100644 --- a/src/test/java/world/bentobox/acidisland/listeners/AcidEffectTest.java +++ b/src/test/java/world/bentobox/acidisland/listeners/AcidEffectTest.java @@ -18,6 +18,7 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.World.Environment; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; @@ -146,6 +147,7 @@ public class AcidEffectTest { when(world.hasStorm()).thenReturn(true); when(world.getBlockAt(anyInt(), anyInt(), anyInt())).thenReturn(airBlock); when(world.getMaxHeight()).thenReturn(5); + when(world.getEnvironment()).thenReturn(Environment.NORMAL); ae = new AcidEffect(addon); } @@ -305,6 +307,38 @@ public class AcidEffectTest { verify(settings).getAcidDamageDelay(); } + /** + * Test method for {@link world.bentobox.acidisland.listeners.AcidEffect#onPlayerMove(org.bukkit.event.player.PlayerMoveEvent)}. + */ + @Test + public void testOnPlayerMoveAcidRainWrongWorld() { + World nether = mock(World.class); + when(nether.getName()).thenReturn("world_nether"); + when(nether.getEnvironment()).thenReturn(Environment.NETHER); + when(player.getWorld()).thenReturn(nether); + + PlayerMoveEvent e = new PlayerMoveEvent(player, from, to); + ae.onPlayerMove(e); + // 2 times only + verify(addon, times(2)).getPlugin(); + } + + /** + * Test method for {@link world.bentobox.acidisland.listeners.AcidEffect#onPlayerMove(org.bukkit.event.player.PlayerMoveEvent)}. + */ + @Test + public void testOnPlayerMoveAcidRainWrongWorldEnd() { + World end = mock(World.class); + when(end.getName()).thenReturn("world_end"); + when(end.getEnvironment()).thenReturn(Environment.THE_END); + when(player.getWorld()).thenReturn(end); + + PlayerMoveEvent e = new PlayerMoveEvent(player, from, to); + ae.onPlayerMove(e); + // 2 times only + verify(addon, times(2)).getPlugin(); + } + /** * Test method for {@link world.bentobox.acidisland.listeners.AcidEffect#onPlayerMove(org.bukkit.event.player.PlayerMoveEvent)}. */ diff --git a/src/test/java/world/bentobox/acidisland/world/ChunkGeneratorWorldTest.java b/src/test/java/world/bentobox/acidisland/world/ChunkGeneratorWorldTest.java index 79e2846..898e5ef 100644 --- a/src/test/java/world/bentobox/acidisland/world/ChunkGeneratorWorldTest.java +++ b/src/test/java/world/bentobox/acidisland/world/ChunkGeneratorWorldTest.java @@ -84,6 +84,7 @@ public class ChunkGeneratorWorldTest { /** * Test method for {@link world.bentobox.bskyblock.generators.ChunkGeneratorWorld#generateChunkData(org.bukkit.World, java.util.Random, int, int, org.bukkit.generator.ChunkGenerator.BiomeGrid)}. */ + @SuppressWarnings("deprecation") @Test public void testGenerateChunkDataWorldRandomIntIntBiomeGridOverworldVoid() { ChunkData cd = cg.generateChunkData(world, random, 0 , 0 , biomeGrid); @@ -101,6 +102,7 @@ public class ChunkGeneratorWorldTest { /** * Test method for {@link world.bentobox.bskyblock.generators.ChunkGeneratorWorld#generateChunkData(org.bukkit.World, java.util.Random, int, int, org.bukkit.generator.ChunkGenerator.BiomeGrid)}. */ + @SuppressWarnings("deprecation") @Test public void testGenerateChunkDataWorldRandomIntIntBiomeGridOverworldSea() { // Set sea height @@ -122,6 +124,7 @@ public class ChunkGeneratorWorldTest { /** * Test method for {@link world.bentobox.bskyblock.generators.ChunkGeneratorWorld#generateChunkData(org.bukkit.World, java.util.Random, int, int, org.bukkit.generator.ChunkGenerator.BiomeGrid)}. */ + @SuppressWarnings("deprecation") @Test public void testGenerateChunkDataWorldRandomIntIntBiomeGridEnd() { when(world.getEnvironment()).thenReturn(World.Environment.THE_END); @@ -141,6 +144,7 @@ public class ChunkGeneratorWorldTest { /** * Test method for {@link world.bentobox.bskyblock.generators.ChunkGeneratorWorld#generateChunkData(org.bukkit.World, java.util.Random, int, int, org.bukkit.generator.ChunkGenerator.BiomeGrid)}. */ + @SuppressWarnings("deprecation") @Test public void testGenerateChunkDataWorldRandomIntIntBiomeGridNetherWithRoof() { when(world.getEnvironment()).thenReturn(World.Environment.NETHER); @@ -158,6 +162,7 @@ public class ChunkGeneratorWorldTest { /** * Test method for {@link world.bentobox.bskyblock.generators.ChunkGeneratorWorld#generateChunkData(org.bukkit.World, java.util.Random, int, int, org.bukkit.generator.ChunkGenerator.BiomeGrid)}. */ + @SuppressWarnings("deprecation") @Test public void testGenerateChunkDataWorldRandomIntIntBiomeGridNetherNoRoof() { when(settings.isNetherRoof()).thenReturn(false);