mirror of
https://github.com/TotalFreedomMC/TF-ProjectKorra.git
synced 2024-05-15 17:31:26 +00:00
787b303c9f
## Additions * Adds a built-in bending board sidebar to visualize bound abilities and cooldowns. * The board respects worlds where bending is disabled. * Players can use the command `/pk board` to toggle the visibility of their board. * Includes an API that community developers can use in BendingBoardManager. * Adds the `"Properties.BendingBoard"` config option to enable or disable the board server. * Adds language file configuration options to control BendingBoard visuals. * `"Board.Title"` * Controls the title at the top of the board. * Supports the standard Minecraft color codes. * `"Board.SelectionPrefix"` * Controls the prefix shown corresponding to your current hot bar slot. * Supports the standard Minecraft color codes. * `"Board.EmptySlot"` * Controls what is shown for empty slots. * Supports the standard Minecraft color codes. * `{slot_number}` can be used as a placeholder for the slot number. * `"Board.MiscSeparator"` * Controls the separation between hot bar binds and temporary cooldowns such as Combos. * Supports the standard Minecraft color codes. * Adds support for KingdomsX version 1.10.19.1 * Adds ability permission check to passive abilities. They should now respect their `bending.ability.<ability name>` permissions. * Adds `AbilityVelocityAffectEntityEvent` * A cancellable event that will fire whenever an ability would alter the velocity of an entity. * Adds the `Abilities.Earth.EarthSmash.Shoot.CollisionRadius` configuration option * Sets the collision radius of shot EarthSmash. ## Fixes * Fixes FireBlast going through liquids. * Fixes duplication involving waterlogged containers. * Fixes being able to not enter the name of a Preset when using the `/pk preset create <name>` command. * Fixes getDayFactor() not being applied correctly and occasionally producing the wrong value. * Fixes a rounding issue with some Fire ability damage configuration options. * Fixes an error when attempting to start EarthGrab. * Fixes PhaseChange error when melting snow. * Fixes a memory/process leak in how cooldowns were removed. * A player's cooldowns could only be removed when they were online. If a player's cooldown expired while they weren't online, their cooldown would attempt to revert every tick until the player rejoined. This has been resolved so cooldowns can revert while a player is offline. * A side effect of this fix is that it is now possible for `PlayerCooldownChangeEvents` to fire while their corresponding Player is offline. * Fixes an issue with `MultiAbilityManager#hasMultiAbilityBound` where it would return true if any MultiAbility is bound, not if the specified MultiAbility was bound. ## Misc Changes * Updates Towny version to 0.96.2.0 * DensityShift sand blocks can now be used as a bendable source. * Changes AvatarState so that its cooldown is applied when the ability ends instead of when it starts. * Changes togglable abilities such as AvatarState, Illumination, and TremorSense to visually show when they are enabled in the BendingBoard and on BendingPreview in the same way as the ChiBlocking Stances. * Updated the text of some ability descriptions and instructions. * Adds new cache to PhaseChange to greatly improve the performance of water/ice updates.
284 lines
8.3 KiB
Java
284 lines
8.3 KiB
Java
package com.projectkorra.projectkorra.ability.util;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.ChatColor;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
|
|
|
import com.projectkorra.projectkorra.BendingPlayer;
|
|
import com.projectkorra.projectkorra.Element;
|
|
import com.projectkorra.projectkorra.GeneralMethods;
|
|
import com.projectkorra.projectkorra.ProjectKorra;
|
|
import com.projectkorra.projectkorra.event.PlayerBindChangeEvent;
|
|
|
|
public class MultiAbilityManager {
|
|
|
|
public static Map<Player, HashMap<Integer, String>> playerAbilities = new ConcurrentHashMap<>();
|
|
public static Map<Player, Integer> playerSlot = new ConcurrentHashMap<>();
|
|
public static Map<Player, String> playerBoundAbility = new ConcurrentHashMap<>();
|
|
public static ArrayList<MultiAbilityInfo> multiAbilityList = new ArrayList<MultiAbilityInfo>();
|
|
|
|
public MultiAbilityManager() {
|
|
final ArrayList<MultiAbilityInfoSub> waterArms = new ArrayList<MultiAbilityInfoSub>();
|
|
waterArms.add(new MultiAbilityInfoSub("Pull", Element.WATER));
|
|
waterArms.add(new MultiAbilityInfoSub("Punch", Element.WATER));
|
|
waterArms.add(new MultiAbilityInfoSub("Grapple", Element.WATER));
|
|
waterArms.add(new MultiAbilityInfoSub("Grab", Element.WATER));
|
|
waterArms.add(new MultiAbilityInfoSub("Freeze", Element.ICE));
|
|
waterArms.add(new MultiAbilityInfoSub("Spear", Element.ICE));
|
|
multiAbilityList.add(new MultiAbilityInfo("WaterArms", waterArms));
|
|
}
|
|
|
|
/**
|
|
* Sets up a player's binds for a MultiAbility.
|
|
*
|
|
* @param player Player having the multiability bound
|
|
* @param multiAbility MultiAbility being bound
|
|
*/
|
|
public static void bindMultiAbility(final Player player, final String multiAbility) {
|
|
final PlayerBindChangeEvent event = new PlayerBindChangeEvent(player, multiAbility, true);
|
|
Bukkit.getServer().getPluginManager().callEvent(event);
|
|
if (event.isCancelled()) {
|
|
return;
|
|
}
|
|
|
|
if (playerAbilities.containsKey(player)) {
|
|
unbindMultiAbility(player);
|
|
}
|
|
playerSlot.put(player, player.getInventory().getHeldItemSlot());
|
|
playerBoundAbility.put(player, multiAbility);
|
|
final BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player);
|
|
final HashMap<Integer, String> currAbilities = new HashMap<Integer, String>();
|
|
for (final int i : bPlayer.getAbilities().keySet()) {
|
|
currAbilities.put(i, bPlayer.getAbilities().get(i));
|
|
}
|
|
playerAbilities.put(player, currAbilities);
|
|
|
|
final List<MultiAbilityInfoSub> modes = getMultiAbility(multiAbility).getAbilities();
|
|
|
|
bPlayer.getAbilities().clear();
|
|
for (int i = 0; i < modes.size(); i++) {
|
|
if (!player.hasPermission("bending.ability." + multiAbility + "." + modes.get(i).getName())) {
|
|
bPlayer.getAbilities().put(i + 1, new StringBuilder().append(modes.get(i).getAbilityColor()).append(ChatColor.STRIKETHROUGH).append(modes.get(i).getName()).toString());
|
|
} else {
|
|
bPlayer.getAbilities().put(i + 1, modes.get(i).getAbilityColor() + modes.get(i).getName());
|
|
}
|
|
}
|
|
|
|
if (player.isOnline()) {
|
|
bPlayer.addCooldown("MAM_Setup", 1L); // Support for bending scoreboards.
|
|
player.getInventory().setHeldItemSlot(0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the MultiAbility the player has bound. Returns null if no
|
|
* multiability is bound and active.
|
|
*
|
|
* @param player The player to use
|
|
* @return name of multi ability bounded
|
|
*/
|
|
public static String getBoundMultiAbility(final Player player) {
|
|
if (playerBoundAbility.containsKey(player)) {
|
|
return playerBoundAbility.get(player);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Returns a MultiAbility based on name.
|
|
*
|
|
* @param multiAbility Name of the multiability
|
|
* @return the multiability object or null
|
|
*/
|
|
public static MultiAbilityInfo getMultiAbility(final String multiAbility) {
|
|
for (final MultiAbilityInfo ma : multiAbilityList) {
|
|
if (ma.getName().equalsIgnoreCase(multiAbility)) {
|
|
return ma;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Returns a boolean based on whether a player has a MultiAbility active.
|
|
*
|
|
* @param player The player to check
|
|
* @return true If player has a multiability active
|
|
*/
|
|
public static boolean hasMultiAbilityBound(final Player player) {
|
|
if (playerAbilities.containsKey(player)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* MultiAbility equivalent of
|
|
* {@link GeneralMethods#getBoundAbility(Player)}. Returns a boolean based
|
|
* on whether a player has a specific MultiAbility active.
|
|
*
|
|
* @param player The player to check
|
|
* @param multiAbility The multiability name
|
|
* @return true If player has the specified multiability active
|
|
*/
|
|
public static boolean hasMultiAbilityBound(final Player player, final String multiAbility) {
|
|
final BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player);
|
|
if (bPlayer == null) {
|
|
return false;
|
|
}
|
|
|
|
return playerAbilities.containsKey(player) && playerBoundAbility.get(player).equals(multiAbility);
|
|
}
|
|
|
|
/**
|
|
* Clears all MultiAbility data for a player. Called on player quit event.
|
|
*
|
|
* @param player
|
|
*/
|
|
public static void remove(final Player player) {
|
|
playerAbilities.remove(player);
|
|
playerBoundAbility.remove(player);
|
|
playerSlot.remove(player);
|
|
}
|
|
|
|
/**
|
|
* Cleans up all MultiAbilities.
|
|
*/
|
|
public static void removeAll() {
|
|
playerAbilities.clear();
|
|
playerSlot.clear();
|
|
playerBoundAbility.clear();
|
|
}
|
|
|
|
/**
|
|
* Keeps track of the player's selected slot while a MultiAbility is active.
|
|
*/
|
|
public static boolean canChangeSlot(final Player player, int slot) {
|
|
if (playerAbilities.isEmpty()) {
|
|
return true;
|
|
}
|
|
final BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player);
|
|
if (bPlayer != null) {
|
|
if (bPlayer.getBoundAbility() == null && multiAbilityList.contains(getMultiAbility(playerBoundAbility.getOrDefault(player, "")))) {
|
|
return slot < getMultiAbility(playerBoundAbility.get(player)).getAbilities().size();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Reverts a player's binds to a previous state before use of a
|
|
* MultiAbility.
|
|
*
|
|
* @param player
|
|
*/
|
|
public static void unbindMultiAbility(final Player player) {
|
|
if (playerAbilities.containsKey(player)) {
|
|
final HashMap<Integer, String> prevBinds = playerAbilities.get(player);
|
|
final BendingPlayer bPlayer = BendingPlayer.getBendingPlayer(player);
|
|
if (bPlayer == null) {
|
|
return;
|
|
}
|
|
|
|
int lastNonNull = -1;
|
|
for (int i = 1; i < 10; i++) {
|
|
if (prevBinds.get(i) != null) {
|
|
lastNonNull = i;
|
|
}
|
|
bPlayer.getAbilities().put(i, prevBinds.get(i));
|
|
}
|
|
if (lastNonNull > -1) {
|
|
GeneralMethods.saveAbility(bPlayer, lastNonNull, prevBinds.get(lastNonNull));
|
|
}
|
|
|
|
if (player.isOnline()) {
|
|
bPlayer.addCooldown("MAM_Setup", 1L); // Support for bending scoreboards.
|
|
}
|
|
playerAbilities.remove(player);
|
|
}
|
|
|
|
if (playerSlot.containsKey(player)) {
|
|
if (player.isOnline()) {
|
|
player.getInventory().setHeldItemSlot(playerSlot.get(player));
|
|
}
|
|
playerSlot.remove(player);
|
|
} else {
|
|
if (player.isOnline()) {
|
|
player.getInventory().setHeldItemSlot(0);
|
|
}
|
|
}
|
|
|
|
if (playerBoundAbility.containsKey(player)) {
|
|
playerBoundAbility.remove(player);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* MultiAbility class. Manages each MultiAbility's sub abilities.
|
|
*
|
|
*/
|
|
public static class MultiAbilityInfo {
|
|
private String name;
|
|
private ArrayList<MultiAbilityInfoSub> abilities;
|
|
|
|
public MultiAbilityInfo(final String name, final ArrayList<MultiAbilityInfoSub> abilities) {
|
|
this.name = name;
|
|
this.abilities = abilities;
|
|
}
|
|
|
|
public ArrayList<MultiAbilityInfoSub> getAbilities() {
|
|
return this.abilities;
|
|
}
|
|
|
|
public String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
public void setAbilities(final ArrayList<MultiAbilityInfoSub> abilities) {
|
|
this.abilities = abilities;
|
|
}
|
|
|
|
public void setName(final String name) {
|
|
this.name = name;
|
|
}
|
|
}
|
|
|
|
public static class MultiAbilityInfoSub {
|
|
private String name;
|
|
private Element element;
|
|
|
|
public MultiAbilityInfoSub(final String name, final Element element) {
|
|
this.name = name;
|
|
this.element = element;
|
|
}
|
|
|
|
public Element getElement() {
|
|
return this.element;
|
|
}
|
|
|
|
public String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
public void setElement(final Element element) {
|
|
this.element = element;
|
|
}
|
|
|
|
public void setName(final String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
public ChatColor getAbilityColor() {
|
|
return this.element != null ? this.element.getColor() : null;
|
|
}
|
|
}
|
|
|
|
}
|