recovery of lost data down to an hour in precision if anything were to go wrong without using ridiculous amounts of hard drive space. ->Gladomain Lifesaver cooldown increased from 3 minutes -> 5 minutes. ->Critical Chance % on Moonshadow's set base crit increased from 10%->15%, crit increase per tier 5%->7%. ->All damage that is meant to be true damage in Minecraft once again deals true damage. This includes Poison, Wither, Fall Damage, Fire Damage, Void Damage, Contact, Suffocation, Falling Blocks. ->Fixed a bug where players leaving and rejoining would cause all glows to become white due to not properly resetting glow color. ->Fixed a bug where some damage events did not use custom death messages. ->Added isArrowQuiver() and getArrowQuiverContents() to API. ->'Greed' artifact ability now has a chance to knock off per kill. The chance a level of Greed gets knocked off has been increased significantly. ->Wolfsbane and Alustine sets added to the Slayer set arsenal. Both of these are weaker tiers of Moonshadow and Gladomain, but have their own unique properties. ->Gladomain and Moonshadow sets drop at Hellfire and Deadly tiers respectively now. ->Dawntracker main stat changed from Health to "Health taken per hit", going down with higher tiers. ->Dawntracker 4-piece set bonus changed from Damage bonus to Health bonus. ->Panros base Damage stat buffed significantly. ->Jamdak 4-Piece set bonus now grants absorption health for each successful dodge. ->Lorasaadi Damage set bonus values significantly increased. ->Custom arrow damage has been changed from a multiplier to a flat damage bonus. Diamond-Tipped arrows increase base damage by 15, Hand-made arrows increase base damage by 5. ->Explosion arrow base damage increased from 40 -> 60 damage. ->Piercing arrows have been added. Piercing arrows provide similar damage to Handmade arrows, but have infinite speed and hits all targets aimed in a line. See /craft for the crafting recipe. ->Arrow Quivers have been redone. All old item quivers will automatically convert to the new type. Arrow Quivers only shoot from your off-hand now. --- When Arrow Quivers are equipped in the off-hand, you can press the 'swap items' key to change which arrow is fired from the Arrow Quiver's inventory. In addition, you can hold shift while pressing the 'swap' key to toggle the opposite way. --- Arrow Quiver modes will automatically switch when you run out of arrows in one mode. --- Collecting arrows will attempt to place them back in your arrow quiver's inventory if possible. --- Right-clicking Arrow Quivers will pull up to 64 arrows at a time from your Arrow Quiver's current mode. --- Shift-Clicking a Quiver when not holding anything in your off-hand will now automatically equip it there. ->Custom Arrows work with the Infinity enchantment! For each level of Infinity, there's a 10% increased chance of the arrow remaining in your inventory when fired. This applies to all non-standard arrows. ->Custom Tipped Arrows display their duration properly when linked now. ->The chance of Infinity getting knocked off of a Bow has been increased significantly. ->Rangers can now hold either a Bow or a Quiver in either hand to be considered in Ranger mode. ->Rangers now have an active ability for Sniping and Debilitation mode as well. --- Sniping Mode Active: Arrow Barrage - 2 Minute Cooldown: The player becomes still as they fire 26 piercing shots extremely quickly in the direction they are facing. All arrows from Arrow Barrage ignore no damage ticks. --- Debilitation Mode Active: Siphon - 35 Second Cooldown: Can be used when at least 1 poisoned target is nearby. Deals (Poison Level x 10) True Damage and Slows all targets the same level as the number of poison stacks applied to nearby targets for 15 seconds, and grants 4 Absorption health (2 hearts) to the Ranger per poison stack. Refreshes Poison duration on all nearby poisoned targets. ->Toggling between Bow modes shows the proper cooldown for that mode. ->Base Dodge Chance increased on all Ranger Set Pieces. ->Important Action Bar messages now have priority over the auto-updating action bar buff indicator to make action bar sensitive actions more clear. ->The Absorption Potion Effect now re-applies all base absorption hearts once every 30 seconds. ->Future Life Vial drops have Absorption effect nerfs applied appropriately. ->Hellfire Spiders now have a cooldown on their Web Throw. (4 seconds) ->Higher tier Cave Spiders (which do not naturally spawn yet) will apply Poison 3 (Dangerous), Poison 4 (Deadly), or Poison 5 (Hellfire). ->Higher tier Wither Skeletons will apply Wither 3 (Dangerous), Wither 4 (Deadly), or Wither 5 (Hellfire). ->Hits made with Highwinder now stay on-screen for a moment, allowing you to see how much the last damage value from Highwinder was. ->Buying back or picking up a shield when not holding anything will automatically place the shield in your holding hand instead of your off-hand, putting you in Defender mode. ->Buying back or picking up a quiver will automatically place it in your off-hand if nothing is already there. ->All buff displays now show up as regular numbers instead of roman numerals. ->Monster AI has been improved to no longer get stuck while being directly in front of you. ->Wither Skeletons that spawn in the Nether now have a very high chance of being Deadly or Hellfire tier. Barbarian Mode has been released! ============== ->Defined by wielding an axe in both the main hand and the offhand. ->Barbarians swing their off-hand by right-clicking. ->Barbarians gain 2 HP (1 Heart) per 1% of Damage reduction. ->When Barbarians are hit, they take damage as if they had 0% Damage reduction. ->Barbarians deal 20% more damage for every 20% of an enemy's missing health. ->Barbarians gain Bonus Lifesteal stacks as they hit enemies. Each stack increases Lifesteal by 1%, up to a cap of 100% extra Lifesteal. The stacks refresh every hit, but wear off after 5 seconds. ->Barbarians do not instantly take full damage when hit. Instead, the HP is stored in a 'Damage Pool' and distributed every second. ->If Barbarians have points in their 'Damage Pool', they will take up to 15 damage every second. The amount taken goes down by wearing Barbarian gear. ->When a monster is killed by a Barbarian, the amount of remaining damage in their Damage Pool is divided by 4. ->Barbarians automatically consume Rotten Flesh and Spider Eyes that are picked up. Each one heals for 1% of their health. Rotten Flesh and Spider Eyes in a Barbarian's inventory will automatically be consumed as the Barbarian gets hungry. ->Barbarians build up Weapon Charges in two ways: +1 Charge for attacking an enemy with the main hand weapon and +2 Charges for taking damage. ->Barbarians have 70% knockback resistance. ->Barbarians can release their Weapon Charges by using a variety of commands: ->Right-Click (Costs 10 Charges): Power Swing - Swing your off-hand weapon to deal an attack with +100% Lifesteal and +100% Crit Chance bonus. Gives 10 Bonus Lifesteal stacks. ->Shift Left-Click (Costs 30 Charges): Forceful Strike - Hit all enemies in a line in front of you, dealing double damage and suppressing them for 3 seconds. ->Shift Right-Click (Costs 30 Charges): Sweep Up - Performs a sweeping attack which knocks up and damages all enemies within a 4m radius of you. Doubles your Bonus Lifesteal stacks. Lifesteal effects are doubled during this attack. ->Swap Item Key (100 Charges Minimum, Costs ALL Charges): Barbarian's Rage - Converts your missing health into Absorption Hearts and applies powerful buffs. This ability is stronger the more stacks consumed. Barbarian's Rage: -- Strength Level: +1 per 10 charges -- LifeSteal: +1% per 2 charges -- Speed V -- 100% Knockback Resistance -- Duration of Rage: +1 second per 10 charges -- +2 seconds of invulnerability per 100 charges During Rage you gain double the number of Bonus Lifesteal stacks. You do not gain Weapon Charges during Barbarian's Rage. ->Leaping Strike: Barbarians that take fall damage deal triple the damage taken from the fall as damage to all enemies nearby. The range of this attack increases based on how fast the Barbarian falls. ->Mock: Press the drop key to perform a Mock attack to all enemies near you. Affected enemies become aggro'd to the Barbarian for 15 seconds and receive 2 stacks of Weakness that lasts 15 seconds. This can stack up to Weakness VI. 20 second cooldown. ->Fixed a bug where overworld Enderman would deal damage equal to an End Enderman. ->Fixed a bug where certain monsters that were suppressed still performed attacks. ->Fixed a bug where Slayers would get the remove stealth effect / sound for every single hit regardless if they were stealthed or not. ->Fixed a bug allowing Slayers to perform Assassinate on dead targets. ->Fixed a bug where deaths would not keep your inventory, leading to dropped items on the ground and nothing to buy back. ->Fixed a bug causing the Yellow Glass to not consistently appear when an Elite Zombie performs the Leap attack. ->Fixed a bug causing regular arrow shots from bows to always hit targets when looking at them, regardless if you are actually aiming the arrow properly or not. ->Fixed a bug preventing players from being hit by multiple unique damage sources at the same time. ->Fixed a bug causing Debilitation mode to not apply the first stack of poison with a normal hit. (Clarification: Only further stacks of poison require headshots.) ->Fixed a bug where mobs would ignore aggro rules when hitting each other. ->Added convertPotionEffectsToLore() to API. ->Added PlayerTumbleEvent() for plugin event listening. - Called each time a player performs Tumble. Cancellable. ->Added PlayerDodgeEvent() for plugin event listening. - Called each time a player successfully dodges an attack. Cancellable. ->Added PlayerLineDriveEvent() for plugin event listening. - Called each time a player performs a Line Drive. Cancellable.dev
parent
77efdd3fcc
commit
18aff61a01
Binary file not shown.
@ -0,0 +1,60 @@ |
||||
package sig.plugin.TwosideKeeper.Events; |
||||
|
||||
import org.bukkit.entity.Entity; |
||||
import org.bukkit.entity.Player; |
||||
import org.bukkit.event.Cancellable; |
||||
import org.bukkit.event.Event; |
||||
import org.bukkit.event.HandlerList; |
||||
import org.bukkit.inventory.ItemStack; |
||||
|
||||
public class PlayerDodgeEvent extends Event implements Cancellable{ |
||||
private Player p; |
||||
private Entity damager; |
||||
private String reason; |
||||
private int flags; |
||||
private boolean cancelled; |
||||
private static final HandlerList handlers = new HandlerList(); |
||||
|
||||
public PlayerDodgeEvent(Player p, Entity damager, String reason, int flags) { |
||||
this.p=p; |
||||
this.damager=damager; |
||||
this.reason=reason; |
||||
this.flags=flags; |
||||
} |
||||
|
||||
public Player getPlayer() { |
||||
return p; |
||||
} |
||||
|
||||
public Entity getDamager() { |
||||
return damager; |
||||
} |
||||
|
||||
public String getReason() { |
||||
return reason; |
||||
} |
||||
|
||||
public int getFlags() { |
||||
return flags; |
||||
} |
||||
|
||||
@Override |
||||
public HandlerList getHandlers() { |
||||
return handlers; |
||||
} |
||||
|
||||
public static HandlerList getHandlerList() { |
||||
return handlers; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isCancelled() { |
||||
return this.cancelled; |
||||
} |
||||
|
||||
@Override |
||||
public void setCancelled(boolean cancelled) { |
||||
this.cancelled=cancelled; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
package sig.plugin.TwosideKeeper.Events; |
||||
|
||||
import org.bukkit.entity.Player; |
||||
import org.bukkit.event.Cancellable; |
||||
import org.bukkit.event.Event; |
||||
import org.bukkit.event.HandlerList; |
||||
|
||||
public final class PlayerLineDriveEvent extends Event implements Cancellable{ |
||||
private Player p; |
||||
private boolean cancelled; |
||||
private static final HandlerList handlers = new HandlerList(); |
||||
|
||||
public PlayerLineDriveEvent(Player p) { |
||||
this.p=p; |
||||
} |
||||
|
||||
public Player getPlayer() { |
||||
return p; |
||||
} |
||||
|
||||
@Override |
||||
public HandlerList getHandlers() { |
||||
return handlers; |
||||
} |
||||
|
||||
public static HandlerList getHandlerList() { |
||||
return handlers; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isCancelled() { |
||||
return this.cancelled; |
||||
} |
||||
|
||||
@Override |
||||
public void setCancelled(boolean cancelled) { |
||||
this.cancelled=cancelled; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,40 @@ |
||||
package sig.plugin.TwosideKeeper.Events; |
||||
|
||||
import org.bukkit.entity.Player; |
||||
import org.bukkit.event.Cancellable; |
||||
import org.bukkit.event.Event; |
||||
import org.bukkit.event.HandlerList; |
||||
|
||||
public class PlayerTumbleEvent extends Event implements Cancellable{ |
||||
private Player p; |
||||
private boolean cancelled; |
||||
private static final HandlerList handlers = new HandlerList(); |
||||
|
||||
public PlayerTumbleEvent(Player p) { |
||||
this.p=p; |
||||
} |
||||
|
||||
public Player getPlayer() { |
||||
return p; |
||||
} |
||||
|
||||
@Override |
||||
public HandlerList getHandlers() { |
||||
return handlers; |
||||
} |
||||
|
||||
public static HandlerList getHandlerList() { |
||||
return handlers; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isCancelled() { |
||||
return this.cancelled; |
||||
} |
||||
|
||||
@Override |
||||
public void setCancelled(boolean cancelled) { |
||||
this.cancelled=cancelled; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@ |
||||
package sig.plugin.TwosideKeeper.HelperStructures; |
||||
|
||||
import org.bukkit.Bukkit; |
||||
import org.bukkit.entity.Arrow; |
||||
import org.bukkit.entity.Player; |
||||
import org.bukkit.potion.PotionEffectType; |
||||
|
||||
import sig.plugin.TwosideKeeper.TwosideKeeper; |
||||
import sig.plugin.TwosideKeeper.HelperStructures.Common.GenericFunctions; |
||||
|
||||
public class ArrowBarrage implements Runnable{ |
||||
int shots_left=20; |
||||
Player p; |
||||
int tick_spd = 3; |
||||
|
||||
public ArrowBarrage(int shots, Player p, int spd) { |
||||
this.shots_left=shots; |
||||
this.p = p; |
||||
this.tick_spd=spd; |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
shots_left--; |
||||
Arrow arr = p.launchProjectile(Arrow.class); |
||||
arr.setVelocity(p.getLocation().getDirection().multiply(2)); |
||||
TwosideKeeper.ShootPiercingArrow(arr, p); |
||||
arr.remove(); |
||||
GenericFunctions.logAndApplyPotionEffectToEntity(PotionEffectType.SLOW, 4, 9, p, true); |
||||
if (shots_left>0) { |
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(TwosideKeeper.plugin, this, 3); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,307 @@ |
||||
package sig.plugin.TwosideKeeper.HelperStructures.Common; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.bukkit.Bukkit; |
||||
import org.bukkit.ChatColor; |
||||
import org.bukkit.Material; |
||||
import org.bukkit.configuration.file.FileConfiguration; |
||||
import org.bukkit.configuration.file.YamlConfiguration; |
||||
import org.bukkit.enchantments.Enchantment; |
||||
import org.bukkit.entity.Entity; |
||||
import org.bukkit.entity.EntityType; |
||||
import org.bukkit.entity.Item; |
||||
import org.bukkit.entity.Player; |
||||
import org.bukkit.entity.Projectile; |
||||
import org.bukkit.inventory.Inventory; |
||||
import org.bukkit.inventory.ItemFlag; |
||||
import org.bukkit.inventory.ItemStack; |
||||
import org.bukkit.inventory.meta.ItemMeta; |
||||
import org.bukkit.metadata.MetadataValue; |
||||
|
||||
import sig.plugin.TwosideKeeper.TwosideKeeper; |
||||
|
||||
public class ArrowQuiver { |
||||
public final static String ARROW_QUIVER_IDENTIFIER = ChatColor.AQUA+"Arrow Quiver"; |
||||
public final static String ID_PREFIX = ChatColor.DARK_AQUA+""+ChatColor.BOLD+"ID "; |
||||
public final static String FIRINGMODE_IDENTIFIER = ChatColor.BLACK+""+ChatColor.MAGIC+"MODE "; |
||||
|
||||
public static boolean isValidQuiver(ItemStack item) { |
||||
return (item!=null && item.getType()==Material.TIPPED_ARROW && |
||||
item.hasItemMeta() && item.getItemMeta().hasLore() && |
||||
item.getItemMeta().getLore().contains(ARROW_QUIVER_IDENTIFIER)); |
||||
} |
||||
|
||||
public static int getID(ItemStack quiver) { |
||||
//Try to find the ID line.
|
||||
List<String> lore = quiver.getItemMeta().getLore(); |
||||
for (int i=0;i<lore.size();i++) { |
||||
if (lore.get(i).contains(ID_PREFIX)) { |
||||
return Integer.parseInt(lore.get(i).replace(ID_PREFIX, "")); |
||||
} |
||||
} |
||||
TwosideKeeper.log("Could not find ID for "+quiver.toString()+". Something went horribly wrong here!!!", 0); |
||||
return -1; |
||||
} |
||||
|
||||
public static void setID(ItemStack quiver) { |
||||
List<String> lore = quiver.getItemMeta().getLore(); |
||||
for (int i=0;i<lore.size();i++) { |
||||
if (lore.get(i).contains(ID_PREFIX)) { |
||||
//This line needs to be replaced.
|
||||
lore.set(i, ID_PREFIX+TwosideKeeper.ARROWQUIVERID); |
||||
TwosideKeeper.ARROWQUIVERID++; |
||||
ItemMeta meta = quiver.getItemMeta(); |
||||
meta.setLore(lore); |
||||
quiver.setItemMeta(meta); |
||||
return; |
||||
} |
||||
} |
||||
TwosideKeeper.log("Could not find ID for "+quiver.toString()+". Something went horribly wrong here!!!", 0); |
||||
return; |
||||
} |
||||
|
||||
public static List<ItemStack> getContents(int id) { |
||||
File arrowquiver_dir = new File(TwosideKeeper.filesave+"/arrowquivers/"); |
||||
if (!arrowquiver_dir.exists()) { |
||||
arrowquiver_dir.mkdir(); |
||||
} |
||||
File config; |
||||
config = new File(TwosideKeeper.filesave,"/arrowquivers/"+id+".data"); |
||||
if (!config.exists()) { |
||||
try { |
||||
config.createNewFile(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
List<ItemStack> inv = new ArrayList<ItemStack>(); |
||||
|
||||
FileConfiguration workable = YamlConfiguration.loadConfiguration(config); |
||||
for (String key : workable.getKeys(false)) { |
||||
inv.add(workable.getItemStack(key)); |
||||
} |
||||
return inv; |
||||
} |
||||
|
||||
public static void addContents(ItemStack quiver, ItemStack...item) { |
||||
addContents(getID(quiver),item); |
||||
} |
||||
|
||||
public static void addContents(int id, ItemStack...item) { |
||||
List<ItemStack> currentinv = getContents(id); |
||||
for (ItemStack it : item) { |
||||
if (it!=null) { |
||||
addItemToQuiver(currentinv, it); |
||||
} |
||||
} |
||||
saveInventory(id, currentinv); |
||||
} |
||||
|
||||
public static void removeContents(ItemStack quiver, ItemStack...item) { |
||||
removeContents(getID(quiver),item); |
||||
} |
||||
|
||||
public static void removeContents(int id, ItemStack...item) { |
||||
List<ItemStack> currentinv = getContents(id); |
||||
for (ItemStack it : item) { |
||||
if (it!=null) { |
||||
removeItemFromQuiver(currentinv, it); |
||||
} |
||||
} |
||||
saveInventory(id, currentinv); |
||||
} |
||||
|
||||
private static void saveInventory(int id, List<ItemStack> currentinv) { |
||||
File arrowquiver_dir = new File(TwosideKeeper.filesave+"/arrowquivers/"); |
||||
if (!arrowquiver_dir.exists()) { |
||||
arrowquiver_dir.mkdir(); |
||||
} |
||||
File config; |
||||
config = new File(TwosideKeeper.filesave,"/arrowquivers/"+id+".data"); |
||||
if (config.exists()) { |
||||
config.delete(); |
||||
try { |
||||
config.createNewFile(); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
FileConfiguration workable = YamlConfiguration.loadConfiguration(config); |
||||
for (ItemStack item : currentinv) { |
||||
workable.set(item.getType().name()+"_"+item.hashCode(), item); |
||||
} |
||||
|
||||
try { |
||||
workable.save(config); |
||||
} catch (IOException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
//updateQuiverLore(id, currentinv);
|
||||
} |
||||
|
||||
private static List<String> getBaseQuiverLore(int id, int mode) { |
||||
List<String> baselore = new ArrayList<String>(); |
||||
baselore.add(ARROW_QUIVER_IDENTIFIER); |
||||
baselore.add(FIRINGMODE_IDENTIFIER+mode); |
||||
baselore.add(ID_PREFIX+id); |
||||
return baselore; |
||||
} |
||||
|
||||
public static void updateQuiverLore(ItemStack quiver) { |
||||
ItemMeta m = quiver.getItemMeta(); |
||||
List<ItemStack> contents = getContents(getID(quiver)); |
||||
List<String> lore = getBaseQuiverLore(getID(quiver), getArrowQuiverMode(quiver)); |
||||
if (contents.size()>0) { |
||||
lore.add(""); |
||||
lore.add(ChatColor.WHITE+"Contains:"); |
||||
for (ItemStack item : contents) { |
||||
lore.add(ChatColor.GRAY+""+ChatColor.ITALIC+" - "+GenericFunctions.UserFriendlyMaterialName(item)+" x"+item.getAmount()); |
||||
} |
||||
} else { |
||||
lore.add(ChatColor.WHITE+"This quiver is empty!"); |
||||
lore.add(ChatColor.AQUA+"Click arrows into the quiver or"); |
||||
lore.add(ChatColor.AQUA+"pick up arrows off the ground"); |
||||
lore.add(ChatColor.AQUA+"to load them up!"); |
||||
} |
||||
m.setLore(lore); |
||||
m.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS); |
||||
m.addItemFlags(ItemFlag.HIDE_ENCHANTS); |
||||
quiver.setItemMeta(m); |
||||
quiver.addUnsafeEnchantment(Enchantment.ARROW_INFINITE, 5); |
||||
} |
||||
|
||||
private static void removeItemFromQuiver(List<ItemStack> currentitems, ItemStack it) { |
||||
//First compare all items that exist.
|
||||
int slot = getItemSlot(currentitems, it); |
||||
if (slot!=-1) { //Remove from the previous amount in the list.
|
||||
if (currentitems.get(slot).getAmount()-it.getAmount()<1) { //Delete it if we run out of these arrows.
|
||||
currentitems.remove(slot); |
||||
} else { |
||||
currentitems.get(slot).setAmount(currentitems.get(slot).getAmount()-it.getAmount()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static void addItemToQuiver(List<ItemStack> currentitems, ItemStack it) { |
||||
//First compare all items that exist.
|
||||
int slot = getItemSlot(currentitems, it); |
||||
if (slot==-1) { //No similar item found, add a new entry.
|
||||
TwosideKeeper.log("No slot found. Adding this way.", 5); |
||||
currentitems.add(it); |
||||
} else { //Add to the previous amount in the list.
|
||||
currentitems.get(slot).setAmount(currentitems.get(slot).getAmount()+it.getAmount()); |
||||
} |
||||
} |
||||
|
||||
private static int getItemSlot(List<ItemStack> currentitems, ItemStack it) { |
||||
for (int i=0;i<currentitems.size();i++) { |
||||
if (currentitems.get(i).isSimilar(it)) { |
||||
return i; |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
public static List<ItemStack> getContentsAPI(ItemStack i) { |
||||
return getContents(getID(i)); |
||||
} |
||||
|
||||
public static int getArrowQuiverMode(ItemStack item) { |
||||
//Arrow quiver mode will be determined by an integer dictating which item slot we are on.
|
||||
//If the slot is non-existent or out-of-bounds, we set it to 0 to indicate the first slot.
|
||||
List<String> lore = item.getItemMeta().getLore(); |
||||
List<ItemStack> contents = getContents(getID(item)); |
||||
for (String text : lore) { |
||||
if (text.contains(FIRINGMODE_IDENTIFIER)) { |
||||
int mode = Integer.parseInt(text.replace(FIRINGMODE_IDENTIFIER, "")); |
||||
if (mode>=0 && contents.size()-1>=mode) { |
||||
return setArrowQuiverMode(item,mode); |
||||
} else { |
||||
return setArrowQuiverMode(item,0); |
||||
} |
||||
} |
||||
} |
||||
return setArrowQuiverMode(item,0); |
||||
} |
||||
|
||||
public static int setArrowQuiverMode(ItemStack item, int mode) { |
||||
ItemMeta m = item.getItemMeta(); |
||||
List<String> lore = m.getLore(); |
||||
List<ItemStack> contents = getContents(getID(item)); |
||||
int arrow_quiver_identifier_line = 0; |
||||
for (int i=0;i<lore.size();i++) { |
||||
if (lore.get(i).contains(FIRINGMODE_IDENTIFIER)) { |
||||
if (contents.size()-1>=mode) { |
||||
lore.set(i,FIRINGMODE_IDENTIFIER+mode); |
||||
} else { |
||||
lore.set(i,FIRINGMODE_IDENTIFIER+0); |
||||
} |
||||
m.setLore(lore); |
||||
item.setItemMeta(m); |
||||
return mode; |
||||
} |
||||
if (lore.get(i).contains(ARROW_QUIVER_IDENTIFIER)) { |
||||
arrow_quiver_identifier_line = i; |
||||
} |
||||
} |
||||
//Firing mode does not exist in the lore yet. Add it under the arrow quiver line.
|
||||
TwosideKeeper.log("Adding a line @ "+arrow_quiver_identifier_line, 5); |
||||
lore.add(arrow_quiver_identifier_line+1,FIRINGMODE_IDENTIFIER+mode); |
||||
m.setLore(lore); |
||||
item.setItemMeta(m); |
||||
return mode; |
||||
} |
||||
|
||||
public static boolean isQuiverEmpty(ItemStack quiver) { |
||||
return getContents(getID(quiver)).size()==0; |
||||
} |
||||
|
||||
public static ItemStack ReturnAndRemoveShotArrow(ItemStack quiver) { |
||||
return ReturnAndRemoveShotArrow(quiver,null); |
||||
} |
||||
|
||||
/** |
||||
* Returns the first arrow quiver in the player's inventory following the same |
||||
* arrow check rules as Minecraft does. Off-hand slot, then hotbar, then inventory. |
||||
* |
||||
* Returns null if it cannot find an arrow quiver at all. |
||||
*/ |
||||
public static ItemStack getArrowQuiverInPlayerInventory(Player p) { |
||||
ItemStack offhandslot = p.getInventory().getExtraContents()[0]; |
||||
ItemStack[] storagecontents = p.getInventory().getStorageContents(); |
||||
if (offhandslot!=null && ArrowQuiver.isValidQuiver(offhandslot)) { |
||||
return offhandslot; |
||||
} else { |
||||
for (int i=0;i<storagecontents.length;i++) { |
||||
if (storagecontents[i]!=null && ArrowQuiver.isValidQuiver(storagecontents[i])) { |
||||
return storagecontents[i]; |
||||
} |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Same as normal version of this method, but checks a bow item to determine if we really are supposed to remove |
||||
* an arrow by using Infinity as a formula. |
||||
*/ |
||||
public static ItemStack ReturnAndRemoveShotArrow(ItemStack quiver, ItemStack bow) { |
||||
List<ItemStack> contents = getContents(getID(quiver)); |
||||
if (contents.size()>0) { |
||||
ItemStack arrow = contents.get(getArrowQuiverMode(quiver)).clone(); |
||||
arrow.setAmount(1); |
||||
if (bow==null) { |
||||
ArrowQuiver.removeContents(getID(quiver), arrow); |
||||
} |
||||
return arrow; |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue