blob: f7a3caef2aa4fa594a0273913e611f4ab1c8b65b [file] [log] [blame] [raw]
package net.glowstone.entity;
import com.flowpowered.network.Message;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import lombok.Getter;
import net.glowstone.EventFactory;
import net.glowstone.GlowWorld;
import net.glowstone.block.GlowBlock;
import net.glowstone.entity.physics.BoundingBox;
import net.glowstone.net.GlowSession;
import net.glowstone.net.message.play.entity.SpawnLightningStrikeMessage;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Damageable;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LightningStrike;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.util.Vector;
/**
* A GlowLightning strike is an entity produced during thunderstorms.
*/
public class GlowLightningStrike extends GlowWeather implements LightningStrike {
/**
* How long this lightning strike has to remain in the world.
*/
private final int ticksToLive;
/**
* Whether the lightning strike is just for effect.
*/
@Getter
private boolean effect;
/**
* Whether the lightning strike is silent.
*/
private boolean isSilent;
private final LightningStrike.Spigot spigot = new LightningStrike.Spigot() {
@Override
public boolean isSilent() {
return isSilent;
}
};
public GlowLightningStrike(Location location) {
this(location, false, false);
}
/**
* Creates a lightning strike.
*
* @param location the location to strike
* @param effect true if this lightning strike doesn't damage entities or start fires
* @param isSilent true to suppress the sound effect
*/
public GlowLightningStrike(Location location, boolean effect, boolean isSilent) {
super(location);
this.effect = effect;
this.isSilent = isSilent;
ticksToLive = 30;
}
@Override
public EntityType getType() {
return EntityType.LIGHTNING;
}
@Override
public void pulse() {
super.pulse();
if (getTicksLived() >= ticksToLive) {
remove();
}
if (getTicksLived() == 1) {
GlowWorld world = (GlowWorld) location.getWorld();
// Play Sound
if (!isSilent) {
world.playSound(location, Sound.ENTITY_LIGHTNING_THUNDER, 10000,
0.8F + ThreadLocalRandom.current().nextFloat() * 0.2F);
world.playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 2,
0.5F + ThreadLocalRandom.current().nextFloat() * 0.2F);
}
if (!effect) { // if it's not just a visual effect
// set target block on fire if required
if (world.getGameRuleMap().getBoolean("doFireTick")) {
GlowBlock block = world.getBlockAt(location);
setBlockOnFire(block);
for (int i = 0; i < 4; i++) {
int x = location.getBlockX() - 1 + ThreadLocalRandom.current().nextInt(3);
int z = location.getBlockZ() - 1 + ThreadLocalRandom.current().nextInt(3);
int y = location.getBlockY() - 1 + ThreadLocalRandom.current().nextInt(3);
block = world.getBlockAt(x, y, z);
setBlockOnFire(block);
}
}
// deal damage to nearby entities
for (Entity entity : getNearbyEntities(3, 6, 3)) {
if (entity.isDead()) {
continue;
}
if (entity instanceof Damageable) {
((Damageable) entity)
.damage(5, this, EntityDamageEvent.DamageCause.LIGHTNING);
}
entity.setFireTicks(entity.getMaxFireTicks());
}
// TODO: Spawn Skeletontrap
}
}
}
@Override
public List<Message> createSpawnMessage() {
double x = location.getX();
double y = location.getY();
double z = location.getZ();
return Collections.singletonList(new SpawnLightningStrikeMessage(entityId, x, y, z));
}
@Override
public List<Message> createUpdateMessage(GlowSession session) {
return Collections.emptyList();
}
@Override
public List<Entity> getNearbyEntities(double x, double y, double z) {
// This behavior is similar to CraftBukkit, where a call with args
// (0, 0, 0) finds any entities whose bounding boxes intersect that of
// this entity.
BoundingBox searchBox = BoundingBox
.fromPositionAndSize(location.toVector(), new Vector(0, 0, 0));
Vector vec = new Vector(x, y, z);
Vector vec2 = new Vector(0, 0.5 * y, 0);
searchBox.minCorner.subtract(vec).add(vec2);
searchBox.maxCorner.add(vec).add(vec2);
return world.getEntityManager().getEntitiesInside(searchBox, this);
}
private void setBlockOnFire(GlowBlock block) {
if (block.isEmpty() && block.getRelative(BlockFace.DOWN).isFlammable()) {
BlockIgniteEvent igniteEvent = new BlockIgniteEvent(block, IgniteCause.LIGHTNING, this);
EventFactory.getInstance().callEvent(igniteEvent);
if (!igniteEvent.isCancelled()) {
BlockState state = block.getState();
state.setType(Material.FIRE);
state.update(true);
}
}
}
@Override
public LightningStrike.Spigot spigot() {
return spigot;
}
}