Add explosive bows & improve source code (#7)

* Add explosive bow item

* Fix buggy inventory management code

* Use crossbow instead of bow to support multishot

* Add weapon item builder

* Make the explosive crossbow shoot faster & more
This commit is contained in:
Allink 2022-12-27 17:51:10 +00:00 committed by GitHub
parent 440dc4091c
commit 17b34d3bdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 243 additions and 36 deletions

View File

@ -4,17 +4,16 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.plugin.java.JavaPlugin;
import pw.kaboom.weapons.commands.CommandWeapons;
import pw.kaboom.weapons.modules.player.PlayerReceiveWeapon;
import pw.kaboom.weapons.modules.player.PlayerUseWeapon;
import pw.kaboom.weapons.modules.weapons.WeaponArcher;
import pw.kaboom.weapons.modules.weapons.WeaponArmageddon;
import pw.kaboom.weapons.modules.weapons.WeaponBlobinator;
import pw.kaboom.weapons.modules.weapons.WeaponExplosiveCrossbow;
import pw.kaboom.weapons.modules.weapons.WeaponGrenade;
import pw.kaboom.weapons.modules.weapons.WeaponMachineGun;
@ -71,6 +70,7 @@ public final class Main extends JavaPlugin {
this.getServer().getPluginManager().registerEvents(new WeaponBlobinator(), this);
this.getServer().getPluginManager().registerEvents(new WeaponGrenade(), this);
this.getServer().getPluginManager().registerEvents(new WeaponMachineGun(), this);
this.getServer().getPluginManager().registerEvents(new WeaponExplosiveCrossbow(), this);
}
public static HashSet<BlockFace> getBlockFaces() {

View File

@ -0,0 +1,47 @@
package pw.kaboom.weapons;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class WeaponItemBuilder {
private final ItemStack itemStack;
private final ItemMeta itemMeta;
private WeaponItemBuilder(Material material) {
this.itemStack = new ItemStack(material);
this.itemMeta = this.itemStack.getItemMeta();
}
public WeaponItemBuilder enchantment(Enchantment enchantment) {
return enchantment(enchantment, enchantment.getStartLevel());
}
public WeaponItemBuilder enchantment(Enchantment enchantment, int level) {
this.itemMeta.addEnchant(enchantment, level, true);
return this;
}
public WeaponItemBuilder name(String name) {
final Component component = Component.text(name)
.decoration(TextDecoration.ITALIC, false);
this.itemMeta.displayName(component);
return this;
}
public static WeaponItemBuilder builder(Material material) {
return new WeaponItemBuilder(material);
}
public ItemStack build() {
this.itemStack.setItemMeta(this.itemMeta);
return this.itemStack;
}
}

View File

@ -1,27 +1,20 @@
package pw.kaboom.weapons.commands;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration;
import pw.kaboom.weapons.WeaponItemBuilder;
public final class CommandWeapons implements CommandExecutor {
private void addWeapon(final Inventory inventory, final Material material,
final Component name) {
final ItemStack item = new ItemStack(material, 1);
final ItemMeta itemMeta = item.getItemMeta();
itemMeta.displayName(name);
item.setItemMeta(itemMeta);
private void addWeapon(final Inventory inventory, final ItemStack item) {
inventory.addItem(item);
}
@ -34,26 +27,42 @@ public final class CommandWeapons implements CommandExecutor {
final Player player = (Player) sender;
final Inventory inventory = Bukkit.createInventory(null, 18, Component.text("Weapons"));
addWeapon(inventory, Material.ANVIL, Component.text("Anvil Dropper")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.SPECTRAL_ARROW, Component.text("Archer")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.FIRE_CHARGE, Component.text("Armageddon")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.MAGMA_CREAM, Component.text("Blobinator")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.EGG, Component.text("Grenade")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.BLAZE_POWDER, Component.text("Laser")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.STICK, Component.text("Lightning Stick")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.GOLDEN_HORSE_ARMOR, Component.text("Machine Gun")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.BLAZE_ROD, Component.text("Nuker")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, Material.IRON_HORSE_ARMOR, Component.text("Sniper")
.decoration(TextDecoration.ITALIC, false));
addWeapon(inventory, WeaponItemBuilder.builder(Material.ANVIL)
.name("Anvil Dropper")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.SPECTRAL_ARROW)
.name("Archer")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.FIRE_CHARGE)
.name("Armageddon")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.MAGMA_CREAM)
.name("Blobinator")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.EGG)
.name("Grenade")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.BLAZE_POWDER)
.name("Laser")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.STICK)
.name("Lightning Stick")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.GOLDEN_HORSE_ARMOR)
.name("Machine Gun")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.BLAZE_ROD)
.name("Nuker")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.IRON_HORSE_ARMOR)
.name("Sniper")
.build());
addWeapon(inventory, WeaponItemBuilder.builder(Material.CROSSBOW)
.name("Explosive Crossbow")
.enchantment(Enchantment.MULTISHOT)
.enchantment(Enchantment.QUICK_CHARGE, 5)
.build());
player.openInventory(inventory);
}
return true;

View File

@ -1,22 +1,47 @@
package pw.kaboom.weapons.modules.player;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import net.kyori.adventure.text.Component;
public final class PlayerReceiveWeapon implements Listener {
@EventHandler
void onInventoryClick(final InventoryClickEvent event) {
if (event.isCancelled() || !Component.text("Weapons").equals(event.getView().title())) {
final Component weaponViewName = Component.text("Weapons");
final InventoryView view = event.getView();
final Component viewTitle = view.title();
if (event.isCancelled() || !viewTitle.equals(weaponViewName)) {
return;
}
final Inventory clickedInventory = event.getClickedInventory();
if (clickedInventory == null) {
return;
}
if (!clickedInventory.equals(view.getTopInventory())) {
return;
}
final ItemStack item = event.getCurrentItem();
if (item == null) {
return;
}
final Component weaponName = item.getItemMeta().displayName();
if (weaponName == null) {
return;
}
final Player player = (Player) event.getWhoClicked();
player.getInventory().addItem(item);

View File

@ -0,0 +1,126 @@
package pw.kaboom.weapons.modules.weapons;
import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent;
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Particle;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.projectiles.ProjectileSource;
public class WeaponExplosiveCrossbow implements Listener {
private static final int PARTICLE_OFFSET = 2;
private final List<Projectile> explosiveProjectiles = new ArrayList<>();
private final SecureRandom secureRandom = new SecureRandom();
@EventHandler
public void onShootArrow(ProjectileLaunchEvent event) {
final Projectile projectile = event.getEntity();
final ProjectileSource source = projectile.getShooter();
if (!(source instanceof final HumanEntity humanEntity)) {
return;
}
final Player player = (Player) humanEntity;
final PlayerInventory playerInventory = player.getInventory();
final ItemStack offHandItem = playerInventory.getItemInOffHand();
final ItemStack mainHandItem = playerInventory.getItemInMainHand();
final Material offHandItemMaterial = offHandItem.getType();
final Material mainHandItemMaterial = mainHandItem.getType();
if (!mainHandItemMaterial.equals(Material.CROSSBOW) && !offHandItemMaterial.equals(
Material.CROSSBOW)) {
return;
}
final Component itemName = Component.text("Explosive Crossbow")
.decoration(TextDecoration.ITALIC, false);
final ItemStack bow = mainHandItemMaterial == Material.CROSSBOW ?
mainHandItem : offHandItem;
final ItemMeta bowMeta = bow.getItemMeta();
final Component displayName = bowMeta.displayName();
if (displayName == null) {
return;
}
if (!(displayName.equals(itemName))) {
return;
}
projectile.customName(Component.text("WeaponExplosiveArrow"));
explosiveProjectiles.add(projectile);
}
@EventHandler
public void onProjectileHit(ProjectileHitEvent event) {
final Projectile projectile = event.getEntity();
final Component customName = projectile.customName();
if (customName == null) {
return;
}
if (!customName.equals(Component.text("WeaponExplosiveArrow"))) {
return;
}
final Entity hitEntity = event.getHitEntity();
final Block hitBlock = event.getHitBlock();
final Location explosionLocation =
(hitBlock != null || hitEntity != null) ?
(hitEntity != null
? hitEntity.getLocation() : hitBlock.getLocation())
: projectile.getLocation();
final World world = projectile.getWorld();
world.createExplosion(explosionLocation, 4.9f, true);
projectile.remove();
}
@EventHandler(priority = EventPriority.MONITOR)
public void onEntityDestroy(EntityRemoveFromWorldEvent event) {
final Entity entity = event.getEntity();
if (!(entity instanceof final Projectile projectile)) {
return;
}
explosiveProjectiles.remove(projectile);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onTickEnd(ServerTickEndEvent event) {
for (Projectile projectile : explosiveProjectiles) {
final World world = projectile.getWorld();
final Location location = projectile.getLocation()
.add(secureRandom.nextDouble(-PARTICLE_OFFSET, PARTICLE_OFFSET),
secureRandom.nextDouble(-PARTICLE_OFFSET, PARTICLE_OFFSET),
secureRandom.nextDouble(-PARTICLE_OFFSET, PARTICLE_OFFSET));
world.spawnParticle(Particle.FLAME, location, 4);
}
}
}