package tc.oc.pgm.pickup; import com.sk89q.minecraft.util.commands.ChatColor; import org.bukkit.*; import org.bukkit.entity.EnderCrystal; import org.bukkit.entity.Entity; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.geometry.Cuboid; import java.time.Duration; import java.time.Instant; import tc.oc.commons.bukkit.geometry.Capsule; import tc.oc.commons.bukkit.geometry.Sphere; import tc.oc.pgm.cooldown.CooldownPlayerFacet; import tc.oc.pgm.events.ListenerScope; import tc.oc.pgm.features.Feature; import tc.oc.pgm.kits.KitPlayerFacet; import tc.oc.pgm.match.Match; import tc.oc.pgm.match.MatchPlayer; import tc.oc.pgm.match.MatchScope; import tc.oc.pgm.match.Repeatable; import java.util.Optional; import static tc.oc.commons.core.util.TimeUtils.isEqualOrBeforeNow; import static tc.oc.commons.core.util.TimeUtils.isInfPositive; import static tc.oc.commons.core.util.Utils.ifInstance; @ListenerScope(MatchScope.RUNNING) public class Pickup implements Feature<PickupDefinition>, Listener { private final Match match; private final World world; private final PickupDefinition data; private Optional<Entity> entity; private Optional<Instant> spawnAt; public Pickup(Match match, PickupDefinition data) { this.match = match; this.world = match.getWorld(); this.data = data; this.entity = Optional.empty(); this.spawnAt = Optional.of(match.getInstantNow()); } public boolean isSpawned() { return entity.isPresent(); } public void spawn() { Location location = data.region().getRandom(match.getRandom()).toLocation(world); effects(Sound.BLOCK_NOTE_BASEDRUM, Particle.CLOUD); Entity entity = world.spawn(location, (Class) data.appearance().getEntityClass()); entity.setKnockbackReduction(1); data.name().ifPresent(name -> { entity.setCustomName(ChatColor.translateAlternateColorCodes('`', name)); entity.setCustomNameVisible(true); }); switch(data.appearance()) { // TODO: Support more appearances later case ENDER_CRYSTAL: ifInstance(entity, EnderCrystal.class, crystal -> crystal.setShowingBottom(false)); break; case PRIMED_TNT: ifInstance(entity, TNTPrimed.class, tnt -> tnt.setFuseTicks(Integer.MAX_VALUE)); break; } this.entity = Optional.of(entity); spawnAt = Optional.empty(); } public void despawn(boolean delay) { if(!data.respawn().equals(Duration.ZERO)) { entity.ifPresent(entity -> { entity.remove(); effects(Sound.BLOCK_LAVA_POP, Particle.SMOKE_LARGE); this.entity = Optional.empty(); }); spawnAt = Optional.ofNullable(delay ? isInfPositive(data.respawn()) ? null : match.getInstantNow().plus(data.respawn()) : match.getInstantNow()); } else { entity.ifPresent(entity -> effects(Sound.BLOCK_LAVA_POP, Particle.SLIME)); } } private void effects(Sound sound, Particle particle) { entity.ifPresent(entity -> { if(data.effects()) { Cuboid box = entity.getBoundingBox(); for(int i = 0; i < box.volume(); i++) { world.spawnParticle(particle, box.randomPointInside(match.getRandom()).toLocation(world), 3, 1, 1, 1, 0); } } if(data.sounds()) { world.playSound(entity.getLocation(), sound, 1, 1); } }); } @Repeatable(scope = MatchScope.LOADED) public void tick() { if(isSpawned()) { if(data.visible().query(match).isDenied()) { despawn(false); } } else { if(spawnAt.isPresent() && isEqualOrBeforeNow(match.getInstantNow(), spawnAt.get()) && data.visible().query(match).isAllowed()) { spawn(); } } } @EventHandler(ignoreCancelled = true) public void onMove(PlayerMoveEvent event) { if(!isSpawned()) return; MatchPlayer player = match.getPlayer(event.getPlayer()); if(player != null) { CooldownPlayerFacet cooler = player.facet(CooldownPlayerFacet.class); if(player.canInteract() && cooler.isNotCooling(this) && Capsule.fromEndpointsAndRadius(event.getFrom().position(), event.getTo().position(), 0.5) .intersects(Sphere.fromCircumscribedCuboid(entity.get().getBoundingBox())) && data.pickup().query(player).isAllowed()) { cooler.coolFor(this, data.cooldown()); despawn(true); player.facet(KitPlayerFacet.class).applyKit(data.kit(), false); } } } @EventHandler(ignoreCancelled = true) public void onDamage(EntityDamageEvent event) { if(isSpawned() && event.getEntity().equals(entity.get())) { event.setCancelled(true); } } @EventHandler(ignoreCancelled = true) public void onDeath(EntityDeathEvent event) { if(isSpawned() && event.getEntity().equals(entity.get())) { event.setDroppedExp(0); event.getDrops().clear(); despawn(false); } } @Override public PickupDefinition getDefinition() { return data; } }