siege weapon modular system beginnings
This commit is contained in:
parent
45aacd626e
commit
b4ed912f7d
@ -180,4 +180,14 @@ public class UtilMath
|
|||||||
|
|
||||||
return values.get(closestIndex);
|
return values.get(closestIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isOdd(int size)
|
||||||
|
{
|
||||||
|
return !isEven(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEven(int size)
|
||||||
|
{
|
||||||
|
return size % 2 == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package mineplex.game.clans.clans.siege.cannon;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import mineplex.game.clans.clans.siege.weapon.AccessType;
|
||||||
|
|
||||||
|
public class AccessRule
|
||||||
|
{
|
||||||
|
private Predicate<Player> _access;
|
||||||
|
private AccessType _type;
|
||||||
|
|
||||||
|
public AccessRule(AccessType type, Predicate<Player> access)
|
||||||
|
{
|
||||||
|
_type = type;
|
||||||
|
_access = access;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allow(AccessType type, Player player)
|
||||||
|
{
|
||||||
|
return type.equals(_type) && _access.test(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,610 +1,125 @@
|
|||||||
package mineplex.game.clans.clans.siege.cannon;
|
package mineplex.game.clans.clans.siege.cannon;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Vector;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
|
||||||
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftArmorStand;
|
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.Slime;
|
import org.bukkit.entity.Slime;
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.HandlerList;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
|
||||||
import org.bukkit.event.entity.EntityDamageEvent;
|
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
|
||||||
import org.bukkit.event.inventory.InventoryCloseEvent;
|
|
||||||
import org.bukkit.event.inventory.InventoryType;
|
import org.bukkit.event.inventory.InventoryType;
|
||||||
import org.bukkit.event.player.PlayerArmorStandManipulateEvent;
|
|
||||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
|
|
||||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
|
||||||
import org.bukkit.inventory.Inventory;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.potion.PotionEffect;
|
import org.bukkit.potion.PotionEffect;
|
||||||
import org.bukkit.potion.PotionEffectType;
|
import org.bukkit.potion.PotionEffectType;
|
||||||
import org.bukkit.util.EulerAngle;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import mineplex.core.common.util.C;
|
import mineplex.core.common.util.C;
|
||||||
import mineplex.core.common.util.F;
|
import mineplex.core.common.util.F;
|
||||||
import mineplex.core.common.util.UtilAlg;
|
|
||||||
import mineplex.core.common.util.UtilBlock;
|
|
||||||
import mineplex.core.common.util.UtilEnt;
|
import mineplex.core.common.util.UtilEnt;
|
||||||
import mineplex.core.common.util.UtilInv;
|
|
||||||
import mineplex.core.common.util.UtilItem;
|
|
||||||
import mineplex.core.common.util.UtilMath;
|
|
||||||
import mineplex.core.common.util.UtilParticle;
|
import mineplex.core.common.util.UtilParticle;
|
||||||
import mineplex.core.common.util.UtilParticle.ParticleType;
|
import mineplex.core.common.util.UtilParticle.ParticleType;
|
||||||
import mineplex.core.common.util.UtilParticle.ViewDist;
|
import mineplex.core.common.util.UtilParticle.ViewDist;
|
||||||
import mineplex.core.common.util.UtilPlayer;
|
import mineplex.core.common.util.UtilPlayer;
|
||||||
import mineplex.core.common.util.UtilServer;
|
import mineplex.core.common.util.UtilServer;
|
||||||
import mineplex.core.common.util.UtilText;
|
|
||||||
import mineplex.core.common.util.UtilTextMiddle;
|
|
||||||
import mineplex.core.common.util.UtilTime;
|
|
||||||
import mineplex.core.hologram.Hologram;
|
|
||||||
import mineplex.core.itemstack.ItemBuilder;
|
|
||||||
import mineplex.core.updater.UpdateType;
|
|
||||||
import mineplex.core.updater.event.UpdateEvent;
|
|
||||||
import mineplex.game.clans.clans.ClanInfo;
|
import mineplex.game.clans.clans.ClanInfo;
|
||||||
import mineplex.game.clans.clans.ClanTips.TipType;
|
import mineplex.game.clans.clans.siege.weapon.AccessType;
|
||||||
import mineplex.game.clans.clans.ClansManager;
|
import mineplex.game.clans.clans.siege.weapon.ProjectileType;
|
||||||
import mineplex.game.clans.clans.siege.BarrierCollisionBox;
|
import mineplex.game.clans.clans.siege.weapon.SiegeWeapon;
|
||||||
|
import mineplex.game.clans.clans.siege.weapon.WeaponStateInfo;
|
||||||
|
|
||||||
public class Cannon implements Listener
|
public class Cannon extends SiegeWeapon
|
||||||
{
|
{
|
||||||
public static final ItemStack CANNON_ITEM = new ItemBuilder(Material.IRON_BLOCK, 1).setRawTitle(C.cBlue + "Cannon").setLore(C.cWhite + "BOOM BABY!").build();
|
|
||||||
|
|
||||||
public static final int COOLDOWN = 20 * 1000 /* 20 seconds*/;
|
|
||||||
|
|
||||||
public static final int MAX_SULPHUR = 3;
|
|
||||||
public static final int MAX_TNT = 1;
|
|
||||||
|
|
||||||
public static final double MAX_HEALTH = 600;
|
|
||||||
|
|
||||||
public static final int TNT_SLOT = 4;
|
|
||||||
public static final List<Integer> SULPHUR_SLOTS = Arrays.asList(1, 3, 5, 7);
|
|
||||||
public static final List<Integer> EMPTY_SLOTS = Arrays.asList(0, 2, 6, 8);
|
|
||||||
|
|
||||||
private static final double[] VERT_POWER = { 0.5, 0.75631, 0.9382 };
|
|
||||||
private static final double[] HORIZ_POWER = { 0.8, 1.1241, 1.34231 };
|
|
||||||
|
|
||||||
private Location _location;
|
|
||||||
private CannonState _state;
|
|
||||||
|
|
||||||
private Player _rider;
|
|
||||||
|
|
||||||
// Entity Information
|
|
||||||
private List<Entity> _entities;
|
|
||||||
|
|
||||||
private TNTPrimed _projectile;
|
|
||||||
|
|
||||||
private Inventory _inventory;
|
|
||||||
|
|
||||||
private long _lastFired = -1;
|
|
||||||
|
|
||||||
private double _health = MAX_HEALTH;
|
|
||||||
|
|
||||||
private Hologram _healthHologram;
|
|
||||||
|
|
||||||
private ClanInfo _clan;
|
|
||||||
|
|
||||||
private BarrierCollisionBox _collisionBox;
|
|
||||||
|
|
||||||
public Cannon(Location location, ClanInfo clan)
|
public Cannon(Location location, ClanInfo clan)
|
||||||
{
|
{
|
||||||
_location = location;
|
super(location, 600.d, "Cannon", clan, clan.Clans);
|
||||||
_state = CannonState.UNLOADED;
|
|
||||||
|
|
||||||
_clan = clan;
|
setBoundingBox(1);
|
||||||
|
|
||||||
_entities = new ArrayList<>();
|
setStateInfo("Unloaded", new WeaponStateInfo(Material.SPONGE, (byte) 1));
|
||||||
|
setStateInfo("Loaded", new WeaponStateInfo(Material.SPONGE, (byte) 0));
|
||||||
|
|
||||||
_collisionBox = BarrierCollisionBox.single(_location.clone());
|
Slime slime = location.getWorld().spawn(location, Slime.class);
|
||||||
_collisionBox.Construct();
|
Slime slime2 = location.getWorld().spawn(location, Slime.class);
|
||||||
_collisionBox.registerRight((block, player) -> handleRightClick(player));
|
|
||||||
_collisionBox.registerLeft((block, player) -> handleLeftClick(player, -1));
|
|
||||||
|
|
||||||
_inventory = UtilServer.getServer().createInventory(null, InventoryType.DISPENSER, C.cRedB + "Cannon");
|
slime.setPassenger(slime2);
|
||||||
|
|
||||||
_healthHologram = new Hologram(ClansManager.getInstance().getHologramManager(), location.clone().add(.5, 3, .5), "Cannon Health", getDisplayHealth());
|
|
||||||
_healthHologram.start();
|
|
||||||
|
|
||||||
updateEntities();
|
UtilEnt.silence(slime, true);
|
||||||
}
|
UtilEnt.silence(slime2, true);
|
||||||
|
UtilEnt.Vegetate(slime);
|
||||||
public void cleanup()
|
UtilEnt.Vegetate(slime2);
|
||||||
{
|
|
||||||
_entities.forEach(Entity::remove);
|
|
||||||
|
|
||||||
_entities.clear();
|
slime.setSize(-1);
|
||||||
|
slime2.setSize(-1);
|
||||||
|
slime.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 99999999, 1, true, false));
|
||||||
|
slime2.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 99999999, 1, true, false));
|
||||||
|
|
||||||
_collisionBox.Destruct();
|
ArmorStand armorStand = location.getWorld().spawn(location, ArmorStand.class);
|
||||||
_healthHologram.stop();
|
|
||||||
_healthHologram = null;
|
|
||||||
|
|
||||||
HandlerList.unregisterAll(this);
|
UtilEnt.setFakeHead(armorStand, true);
|
||||||
}
|
armorStand.teleport(location);
|
||||||
|
armorStand.setVisible(false);
|
||||||
private void updateEntities()
|
armorStand.setGravity(false);
|
||||||
{
|
|
||||||
if (_entities.isEmpty())
|
|
||||||
{
|
|
||||||
Slime slime = getArmorStandLocation().getWorld().spawn(getArmorStandLocation(), Slime.class);
|
|
||||||
|
|
||||||
UtilEnt.silence(slime, true);
|
|
||||||
UtilEnt.Vegetate(slime);
|
|
||||||
|
|
||||||
slime.setSize(-1);
|
|
||||||
slime.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 99999999, 1, true, false));
|
|
||||||
|
|
||||||
_entities.add(slime);
|
|
||||||
|
|
||||||
slime = getArmorStandLocation().getWorld().spawn(getArmorStandLocation(), Slime.class);
|
|
||||||
|
|
||||||
UtilEnt.silence(slime, true);
|
|
||||||
UtilEnt.Vegetate(slime);
|
|
||||||
|
|
||||||
slime.setSize(-1);
|
|
||||||
slime.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 99999999, 1, true, false));
|
|
||||||
|
|
||||||
UtilMath.getLast(_entities).setPassenger(slime);
|
|
||||||
|
|
||||||
_entities.add(slime);
|
|
||||||
|
|
||||||
ArmorStand armorStand = _location.getWorld().spawn(getArmorStandLocation(), ArmorStand.class);
|
|
||||||
|
|
||||||
UtilEnt.setFakeHead(armorStand, true);
|
|
||||||
armorStand.teleport(getArmorStandLocation());
|
|
||||||
armorStand.setVisible(false);
|
|
||||||
armorStand.setHelmet(_state.toItemStack());
|
|
||||||
armorStand.setGravity(false);
|
|
||||||
|
|
||||||
armorStand.setPassenger(UtilMath.getFirst(_entities));
|
|
||||||
|
|
||||||
_entities.add(0, armorStand);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
getArmorStand().setHelmet(_state.toItemStack());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CraftArmorStand getArmorStand()
|
|
||||||
{
|
|
||||||
return (CraftArmorStand) UtilMath.getFirst(_entities);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Location getArmorStandLocation()
|
|
||||||
{
|
|
||||||
return _location.clone().add(.5, .15, .5);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setState(CannonState state)
|
|
||||||
{
|
|
||||||
_state = state;
|
|
||||||
updateEntities();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fire()
|
|
||||||
{
|
|
||||||
TNTPrimed tnt = _location.getWorld().spawn(_location.clone().add(.5, .3, .5), TNTPrimed.class);
|
|
||||||
|
|
||||||
_projectile = tnt;
|
armorStand.setPassenger(slime);
|
||||||
|
|
||||||
double vVel = VERT_POWER[getPower() - 1];
|
addEntity(slime, "Slime1");
|
||||||
double hMulti = HORIZ_POWER[getPower() - 1];
|
addEntity(slime2, "PLAYERMOUNT");
|
||||||
|
addEntity(armorStand, "WEAPON");
|
||||||
|
|
||||||
Vector velocity = UtilAlg.getTrajectory(
|
setState("Unloaded");
|
||||||
getArmorStand().getLocation(),
|
|
||||||
UtilAlg.moveForward(
|
|
||||||
getArmorStand().getLocation(),
|
|
||||||
2.,
|
|
||||||
(float) Math.toDegrees(getArmorStand().getHeadPose().getY()), false))
|
|
||||||
.multiply(hMulti)
|
|
||||||
.setY(vVel);
|
|
||||||
|
|
||||||
tnt.setVelocity(velocity);
|
setFirepowerType(Material.SULPHUR);
|
||||||
|
setAmmunitionType(Material.TNT);
|
||||||
|
|
||||||
_inventory.setItem(TNT_SLOT, UtilInv.decrement(_inventory.getItem(TNT_SLOT)));
|
setFirepowerSlots(1, 3, 5, 7);
|
||||||
SULPHUR_SLOTS.forEach(_inventory::clear);
|
setMaximumFirepowerPerSlot(3);
|
||||||
|
|
||||||
UtilParticle.PlayParticleToAll(ParticleType.LARGE_EXPLODE, getArmorStandLocation(), new Vector(0, 0, 0), .1f, 2, ViewDist.MAX);
|
setAmmunitionSlot(4);
|
||||||
UtilServer.getServer().getOnlinePlayers().forEach(player -> player.playSound(getArmorStandLocation(), Sound.EXPLODE, 1.f, 1.f));
|
setMaximumAmmunitionPerSlot(1);
|
||||||
|
|
||||||
_lastFired = System.currentTimeMillis();
|
setFireCooldown(20000);
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onCloseInv(InventoryCloseEvent event)
|
|
||||||
{
|
|
||||||
if (!event.getInventory().equals(_inventory))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClansManager.getInstance().runSyncLater(() -> {
|
setProjectileType(ProjectileType.PRIMED_TNT);
|
||||||
if (event.getPlayer().getInventory().equals(_inventory))
|
setProjectileDoCrater(3, 2.d);
|
||||||
|
|
||||||
|
enableInventory(UtilServer.getServer().createInventory(null, InventoryType.DISPENSER, C.cDAquaB + _name), new AccessRule(AccessType.RCLICK_BB, super::isRiding));
|
||||||
|
|
||||||
|
setRideable(new AccessRule(AccessType.RCLICK_BB, player -> {
|
||||||
|
if (!_owner.isMember(player))
|
||||||
{
|
{
|
||||||
return;
|
UtilPlayer.message(player, F.main("Clans", "This cannon is not owned by your Clan."));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canBeFired())
|
if (getRider() != null && !getRider().equals(player))
|
||||||
{
|
{
|
||||||
UtilTextMiddle.display("Cannon Ready", "Power Level: " + C.cGreen + UtilText.repeat("▌", getPower()) + C.cRed + UtilText.repeat("▌", 3 - getPower()), 20, 100, 20, _rider);
|
UtilPlayer.message(player, F.main("Clans", "Someone is already riding this cannon."));
|
||||||
}
|
return false;
|
||||||
}, 3L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
|
||||||
public void onTntExplode(EntityExplodeEvent event)
|
|
||||||
{
|
|
||||||
// stop the tnt from exploding naturally
|
|
||||||
if (event.getEntity().equals(_projectile))
|
|
||||||
{
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateProjectile()
|
|
||||||
{
|
|
||||||
if (_projectile != null)
|
|
||||||
{
|
|
||||||
UtilParticle.PlayParticleToAll(ParticleType.LARGE_SMOKE, _projectile.getLocation().add(0, .5, 0), new Vector(0, 0, 0), .1f, 3, ViewDist.MAX);
|
|
||||||
|
|
||||||
_projectile.setFuseTicks(40);
|
|
||||||
|
|
||||||
if ((Math.abs(_projectile.getVelocity().getX()) < 0.01 || Math.abs(_projectile.getVelocity().getZ()) < 0.01) && UtilBlock.getInRadius(_projectile.getLocation(), 2).keySet().stream().filter(block -> !UtilItem.isBoundless(block.getType())).iterator().hasNext() && _projectile.getTicksLived() >= 10)
|
|
||||||
{
|
|
||||||
//Do Explosion;
|
|
||||||
|
|
||||||
new CannonCrater(this, UtilBlock.nearestFloor(_projectile.getLocation()));
|
|
||||||
|
|
||||||
UtilServer.getServer().getOnlinePlayers().forEach(player -> player.playSound(_projectile.getLocation(), Sound.EXPLODE, 1.f, 1.f));
|
|
||||||
|
|
||||||
_projectile.remove();
|
|
||||||
_projectile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void attemptFire()
|
|
||||||
{
|
|
||||||
if (canBeFired())
|
|
||||||
{
|
|
||||||
if (System.currentTimeMillis() - _lastFired < COOLDOWN)
|
|
||||||
{
|
|
||||||
UtilPlayer.message(_rider, F.main("Clans", "Cannon is cooling down. (" + F.time(UtilTime.MakeStr(COOLDOWN - (System.currentTimeMillis() - _lastFired)) + C.mBody + ")")));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fire();
|
return !player.equals(getRider());
|
||||||
}
|
}));
|
||||||
else
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void UpdateState(String state)
|
||||||
|
{
|
||||||
|
((ArmorStand) getEntity("WEAPON")).setHelmet(new ItemStack(getStateInfo(state).getType(), getStateInfo(state).getData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick()
|
||||||
|
{
|
||||||
|
if (getProjectile() != null)
|
||||||
{
|
{
|
||||||
UtilPlayer.message(_rider, F.main("Clans", "Cannon is not correctly loaded."));
|
UtilParticle.PlayParticleToAll(ParticleType.LARGE_SMOKE, getProjectile().getLocation().add(0, .5, 0), new Vector(0, 0, 0), .1f, 3, ViewDist.MAX);
|
||||||
_rider.playSound(_rider.getLocation(), Sound.CLICK, 1.f, 1.f);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleOpenInv(Player player)
|
@Override
|
||||||
|
protected double[] getProjectileVelocityMult()
|
||||||
{
|
{
|
||||||
if (!player.equals(_rider))
|
int firepower = getPowerLevel();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_inventory == null)
|
return new double[] { firepower, firepower };
|
||||||
{
|
|
||||||
cleanup();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_rider.openInventory(_inventory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPower()
|
|
||||||
{
|
|
||||||
int power = 0;
|
|
||||||
|
|
||||||
for (int slot : SULPHUR_SLOTS)
|
|
||||||
{
|
|
||||||
if (_inventory.getItem(slot) != null)
|
|
||||||
{
|
|
||||||
power += _inventory.getItem(slot).getAmount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return power / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getTnt()
|
|
||||||
{
|
|
||||||
return _inventory.getItem(TNT_SLOT) != null ? _inventory.getItem(TNT_SLOT).getAmount() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canBeFired()
|
|
||||||
{
|
|
||||||
return getTnt() > 0 && getPower() > 0 && _projectile == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void updateState(UpdateEvent event)
|
|
||||||
{
|
|
||||||
// if (event.getType() == UpdateType.FASTEST)
|
|
||||||
// {
|
|
||||||
// if (_state == CannonState.LOADED)
|
|
||||||
// {
|
|
||||||
// double yaw = getArmorStand().getHeadPose().getY() - 7.75d;
|
|
||||||
//
|
|
||||||
// Location loc = new Location(_location.getWorld(), getArmorStand().getLocation().getX() + (0.5 * Math.cos(yaw)), _location.getY() + 1.12, getArmorStand().getLocation().getZ() + (0.5 * Math.sin(yaw)));
|
|
||||||
//
|
|
||||||
// loc = UtilAlg.moveForward(loc, 0.1, (float) Math.toDegrees(yaw + 7.75), false);
|
|
||||||
//
|
|
||||||
// UtilParticle.PlayParticleToAll(ParticleType.FLAME, loc, new Vector(0, 0, 0), 0.f, 1, ViewDist.MAX);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (event.getType() != UpdateType.TICK)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CannonState newState = _inventory.getItem(TNT_SLOT) != null ? CannonState.LOADED : CannonState.UNLOADED;
|
|
||||||
|
|
||||||
if (_state != newState)
|
|
||||||
{
|
|
||||||
setState(newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
checkInv();
|
|
||||||
|
|
||||||
updateProjectile();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkInv()
|
|
||||||
{
|
|
||||||
for (int slot = 0; slot < 9; slot++)
|
|
||||||
{
|
|
||||||
ItemStack item = _inventory.getItem(slot);
|
|
||||||
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot == TNT_SLOT)
|
|
||||||
{
|
|
||||||
if (item.getType() != Material.TNT)
|
|
||||||
{
|
|
||||||
_rider.getInventory().addItem(item);
|
|
||||||
_inventory.setItem(slot, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (item.getAmount() > MAX_TNT)
|
|
||||||
{
|
|
||||||
_rider.getInventory().addItem(new ItemStack(Material.TNT, item.getAmount() - MAX_TNT));
|
|
||||||
_inventory.setItem(slot, new ItemStack(Material.TNT, MAX_TNT));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (SULPHUR_SLOTS.contains(slot))
|
|
||||||
{
|
|
||||||
if (item.getType() != Material.SULPHUR)
|
|
||||||
{
|
|
||||||
_rider.getInventory().addItem(item);
|
|
||||||
_inventory.setItem(slot, null);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (item.getAmount() > MAX_SULPHUR)
|
|
||||||
{
|
|
||||||
_rider.getInventory().addItem(new ItemStack(Material.SULPHUR, item.getAmount() - MAX_SULPHUR));
|
|
||||||
_inventory.setItem(slot, new ItemStack(Material.SULPHUR, MAX_SULPHUR));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (EMPTY_SLOTS.contains(slot)) // also classes as just an 'else{}'
|
|
||||||
{
|
|
||||||
_rider.getInventory().addItem(item);
|
|
||||||
_inventory.setItem(slot, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
|
||||||
public void onDmg(EntityDamageByEntityEvent event)
|
|
||||||
{
|
|
||||||
if (!_entities.contains(event.getEntity()))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(event.getDamager() instanceof Player))
|
|
||||||
{
|
|
||||||
handleLeftClick((Player) event.getDamager(), event.getFinalDamage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onInteract(PlayerInteractAtEntityEvent event)
|
|
||||||
{
|
|
||||||
if (_entities.contains(event.getRightClicked()))
|
|
||||||
{
|
|
||||||
handleRightClick(event.getPlayer());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onInteract(PlayerInteractEntityEvent event)
|
|
||||||
{
|
|
||||||
if (_entities.contains(event.getRightClicked()))
|
|
||||||
{
|
|
||||||
handleRightClick(event.getPlayer());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onInteract(PlayerArmorStandManipulateEvent event)
|
|
||||||
{
|
|
||||||
if (_entities.contains(event.getRightClicked()))
|
|
||||||
{
|
|
||||||
handleRightClick(event.getPlayer());
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleLeftClick(Player player, double damage)
|
|
||||||
{
|
|
||||||
if (!_clan.isMember(player))
|
|
||||||
{
|
|
||||||
removeHealth(damage == -1 ? calcDmg(player) : damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!player.equals(_rider))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
attemptFire();
|
|
||||||
}
|
|
||||||
|
|
||||||
private double calcDmg(Player player)
|
|
||||||
{
|
|
||||||
ItemStack item = player.getItemInHand();
|
|
||||||
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
double dmg = UtilItem.getAttackDamage(item.getType());
|
|
||||||
|
|
||||||
switch(item.getType())
|
|
||||||
{
|
|
||||||
case RECORD_4:
|
|
||||||
dmg += 7;
|
|
||||||
case GREEN_RECORD:
|
|
||||||
dmg += 6;
|
|
||||||
case GOLD_RECORD:
|
|
||||||
dmg += 9;
|
|
||||||
case RECORD_3:
|
|
||||||
dmg += 1;
|
|
||||||
case RECORD_5:
|
|
||||||
dmg += 7;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
return dmg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleRightClick(Player player)
|
|
||||||
{
|
|
||||||
if (!_clan.isMember(player))
|
|
||||||
{
|
|
||||||
UtilPlayer.message(player, F.main("Clans", "This Cannon does not belong to your Clan."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entity passenger = UtilMath.getLast(_entities).getPassenger();
|
|
||||||
if (passenger == null)
|
|
||||||
{
|
|
||||||
UtilMath.getLast(_entities).setPassenger(player);
|
|
||||||
|
|
||||||
_rider = player;
|
|
||||||
|
|
||||||
ClansManager.getInstance().ClanTips.displayTip(TipType.MOUNT_CANNON, _rider);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handleOpenInv(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void update(UpdateEvent event)
|
|
||||||
{
|
|
||||||
if (event.getType() != UpdateType.TICK)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rider != null && !_rider.equals(UtilMath.getLast(_entities).getPassenger()))
|
|
||||||
{
|
|
||||||
_rider = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rider != null)
|
|
||||||
{
|
|
||||||
if (System.currentTimeMillis() - _lastFired < 5000)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArmorStand armorStand = (ArmorStand) UtilMath.getFirst(_entities);
|
|
||||||
double standYaw = Math.toDegrees(armorStand.getHeadPose().getY()) % 360;
|
|
||||||
double riderYaw = _rider.getLocation().getYaw() % 360;
|
|
||||||
|
|
||||||
// riderYaw = 350 and standYaw = 20
|
|
||||||
// dif should be -30 and not 330
|
|
||||||
double dif = riderYaw - standYaw;
|
|
||||||
if (dif > 180) dif -= 360;
|
|
||||||
if (dif < -180) dif += 360;
|
|
||||||
|
|
||||||
double yaw = standYaw + Math.min(dif / 20.f, 4f);
|
|
||||||
|
|
||||||
armorStand.setHeadPose(new EulerAngle(0, Math.toRadians(yaw), 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onDamage(EntityDamageEvent event)
|
|
||||||
{
|
|
||||||
if (_entities.contains(event.getEntity()))
|
|
||||||
{
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Health Managemnet
|
|
||||||
public double getHealth()
|
|
||||||
{
|
|
||||||
return _health;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayHealth()
|
|
||||||
{
|
|
||||||
return UtilText.getProgress(null, _health / MAX_HEALTH, null, false, 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHealth(double health)
|
|
||||||
{
|
|
||||||
_health = UtilMath.clamp(health, 0, MAX_HEALTH);
|
|
||||||
|
|
||||||
_healthHologram.setText("Cannon Health", getDisplayHealth());
|
|
||||||
|
|
||||||
if (_health == 0)
|
|
||||||
{
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeHealth(double health)
|
|
||||||
{
|
|
||||||
setHealth(_health - health);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addHealth(double health)
|
|
||||||
{
|
|
||||||
setHealth(_health + health);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package mineplex.game.clans.clans.siege.weapon;
|
||||||
|
|
||||||
|
public enum AccessType
|
||||||
|
{
|
||||||
|
RCLICK_BB,
|
||||||
|
LCLICK_BB,
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package mineplex.game.clans.clans.siege.weapon;
|
||||||
|
|
||||||
|
public enum ProjectileType
|
||||||
|
{
|
||||||
|
PRIMED_TNT,
|
||||||
|
FALLING_BLOCK;
|
||||||
|
}
|
@ -0,0 +1,283 @@
|
|||||||
|
package mineplex.game.clans.clans.siege.weapon;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import mineplex.core.common.util.UtilMath;
|
||||||
|
import mineplex.core.common.util.UtilServer;
|
||||||
|
import mineplex.core.common.util.UtilText;
|
||||||
|
import mineplex.core.hologram.Hologram;
|
||||||
|
import mineplex.core.updater.UpdateType;
|
||||||
|
import mineplex.core.updater.event.UpdateEvent;
|
||||||
|
import mineplex.game.clans.clans.ClanInfo;
|
||||||
|
import mineplex.game.clans.clans.ClansManager;
|
||||||
|
import mineplex.game.clans.clans.siege.BarrierCollisionBox;
|
||||||
|
import mineplex.game.clans.clans.siege.cannon.AccessRule;
|
||||||
|
|
||||||
|
public abstract class SiegeWeapon implements Listener
|
||||||
|
{
|
||||||
|
private ClansManager _clans;
|
||||||
|
|
||||||
|
protected ClanInfo _owner;
|
||||||
|
protected final String _name;
|
||||||
|
protected final double _maxHealth;
|
||||||
|
protected double _health;
|
||||||
|
|
||||||
|
protected Inventory _inventory;
|
||||||
|
protected AccessRule _inventoryAccess;
|
||||||
|
|
||||||
|
private Hologram _infoHologram;
|
||||||
|
private BarrierCollisionBox _collisionBox;
|
||||||
|
|
||||||
|
private Location _location;
|
||||||
|
|
||||||
|
private final Map<String, WeaponStateInfo> _registeredStates;
|
||||||
|
private String _currentState;
|
||||||
|
|
||||||
|
private final List<Entity> _comprisedOf;
|
||||||
|
|
||||||
|
// Friendly-name mapping to index in _comprisedOf for easier management of entities.
|
||||||
|
private final Map<String, Integer> _entityMapping;
|
||||||
|
|
||||||
|
private boolean _isRideable;
|
||||||
|
private AccessRule _mountAccess;
|
||||||
|
|
||||||
|
private Player _rider;
|
||||||
|
|
||||||
|
public SiegeWeapon(Location location, double maxHealth, String name, ClanInfo owner, ClansManager clansManager)
|
||||||
|
{
|
||||||
|
_location = location;
|
||||||
|
_name = name;
|
||||||
|
_health = _maxHealth = maxHealth;
|
||||||
|
_owner = owner;
|
||||||
|
|
||||||
|
_comprisedOf = Lists.newArrayList();
|
||||||
|
_registeredStates = Maps.newHashMap();
|
||||||
|
_entityMapping = Maps.newHashMap();
|
||||||
|
|
||||||
|
_infoHologram = new Hologram(ClansManager.getInstance().getHologramManager(), _location.clone().add(.5, 3, .5), _name + " Health", getDisplayHealth());
|
||||||
|
_infoHologram.start();
|
||||||
|
|
||||||
|
UtilServer.getPluginManager().registerEvents(this, clansManager.getPlugin());
|
||||||
|
|
||||||
|
_clans = clansManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void enableInventory(Inventory inventory, AccessRule accessRule)
|
||||||
|
{
|
||||||
|
_inventory = inventory;
|
||||||
|
_inventoryAccess = accessRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setBoundingBox(int size)
|
||||||
|
{
|
||||||
|
Validate.isTrue(UtilMath.isOdd(size), "Size must be an odd number.");
|
||||||
|
Validate.isTrue(size > 0, "Size must be a positive number.");
|
||||||
|
|
||||||
|
_collisionBox = size == 1 ? BarrierCollisionBox.single(_location.clone()) : BarrierCollisionBox.all(_location.clone().subtract((size - 1) / 2, 0, (size - 1) / 2), _location.clone().add(((size - 1) / 2) + .5, size - 1, ((size - 1) / 2) + .5));
|
||||||
|
_collisionBox.Construct();
|
||||||
|
_collisionBox.registerRight((block, player) -> handleRightClick(player));
|
||||||
|
_collisionBox.registerLeft((block, player) -> handleLeftClick(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Riding
|
||||||
|
|
||||||
|
protected Player getRider()
|
||||||
|
{
|
||||||
|
return _rider;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setRideable(AccessRule accessRule)
|
||||||
|
{
|
||||||
|
_isRideable = true;
|
||||||
|
_mountAccess = accessRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
|
||||||
|
private void kill()
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
|
||||||
|
_comprisedOf.forEach(Entity::remove);
|
||||||
|
|
||||||
|
_entityMapping.clear();
|
||||||
|
_comprisedOf.clear();
|
||||||
|
_infoHologram.stop();
|
||||||
|
|
||||||
|
HandlerList.unregisterAll(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleMount(Player player)
|
||||||
|
{
|
||||||
|
getEntity("PLAYERMOUNT").setPassenger(player);
|
||||||
|
OnMount(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleInventoryOpen(Player player)
|
||||||
|
{
|
||||||
|
player.openInventory(_inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleRightClick(Player player)
|
||||||
|
{
|
||||||
|
RightClick(player);
|
||||||
|
|
||||||
|
if (_isRideable && _mountAccess.allow(AccessType.RCLICK_BB, player))
|
||||||
|
{
|
||||||
|
handleMount(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_inventory != null && _inventoryAccess.allow(AccessType.RCLICK_BB, player))
|
||||||
|
{
|
||||||
|
handleInventoryOpen(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleLeftClick(Player player)
|
||||||
|
{
|
||||||
|
LeftClick(player);
|
||||||
|
|
||||||
|
if (_isRideable && _mountAccess.allow(AccessType.LCLICK_BB, player))
|
||||||
|
{
|
||||||
|
handleMount(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_inventory != null && _inventoryAccess.allow(AccessType.LCLICK_BB, player))
|
||||||
|
{
|
||||||
|
handleInventoryOpen(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods for implementation by sub-classes
|
||||||
|
|
||||||
|
protected void Tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnMount(Player player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void LeftClick(Player player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RightClick(Player player)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Cleanup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateState(String state)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entity Management
|
||||||
|
|
||||||
|
protected final boolean addEntity(Entity entity, String uniqueName)
|
||||||
|
{
|
||||||
|
boolean success = _comprisedOf.add(entity);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
_entityMapping.put(uniqueName, _comprisedOf.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Entity getEntity(String uniqueName)
|
||||||
|
{
|
||||||
|
return _comprisedOf.get(_entityMapping.get(uniqueName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Health Management
|
||||||
|
|
||||||
|
public final double getHealth()
|
||||||
|
{
|
||||||
|
return _health;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getDisplayHealth()
|
||||||
|
{
|
||||||
|
return UtilText.getProgress(null, _health / _maxHealth, null, false, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setHealth(double health)
|
||||||
|
{
|
||||||
|
_health = UtilMath.clamp(health, 0, _maxHealth);
|
||||||
|
|
||||||
|
_infoHologram.setText(_name + " Health", getDisplayHealth());
|
||||||
|
|
||||||
|
if (_health == 0)
|
||||||
|
{
|
||||||
|
kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void removeHealth(double health)
|
||||||
|
{
|
||||||
|
setHealth(_health - health);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void addHealth(double health)
|
||||||
|
{
|
||||||
|
setHealth(_health + health);
|
||||||
|
}
|
||||||
|
|
||||||
|
//State Management
|
||||||
|
|
||||||
|
public final void setState(String state)
|
||||||
|
{
|
||||||
|
Validate.isTrue(_registeredStates.containsKey(state), "Provided state has not yet been registered.");
|
||||||
|
|
||||||
|
_currentState = state;
|
||||||
|
|
||||||
|
UpdateState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setStateInfo(String state, WeaponStateInfo info)
|
||||||
|
{
|
||||||
|
_registeredStates.put(state, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final WeaponStateInfo getStateInfo(String state)
|
||||||
|
{
|
||||||
|
if (!_registeredStates.containsKey(state))
|
||||||
|
{
|
||||||
|
_registeredStates.put(state, new WeaponStateInfo(Material.STONE, (byte) 101));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _registeredStates.get(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void update(UpdateEvent event)
|
||||||
|
{
|
||||||
|
if (event.getType() != UpdateType.TICK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package mineplex.game.clans.clans.siege.weapon;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
|
public class WeaponStateInfo
|
||||||
|
{
|
||||||
|
private Material _material;
|
||||||
|
private byte _data;
|
||||||
|
|
||||||
|
public WeaponStateInfo(Material material, byte data)
|
||||||
|
{
|
||||||
|
_material = material;
|
||||||
|
_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getType()
|
||||||
|
{
|
||||||
|
return _material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getData()
|
||||||
|
{
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user