diff --git a/.gitignore b/.gitignore
index f2e64c4b..bde8e30c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
.idea/
out/
*.iml
+lib/
#################
## Eclipse
diff --git a/builder.xml b/builder.xml
new file mode 100644
index 00000000..777cfc50
--- /dev/null
+++ b/builder.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/attributes.yml b/configs/attributes.yml
similarity index 50%
rename from attributes.yml
rename to configs/attributes.yml
index 2f390be1..3d0ddc23 100644
--- a/attributes.yml
+++ b/configs/attributes.yml
@@ -4,14 +4,29 @@
# http://dev.bukkit.org/bukkit-plugins/skillapi/pages/attributes/
#
# List of available stats to modify:
-# health - the max health of the player
-# mana - the amount of mana the player has
-# mana-regen - how much mana the player regenerates over time
-# physical-damage - damage dealt without using skills
-# physical-defense - damage taken from non-skill attacks
-# skill-damage - damage dealt with skills
-# skill-defense - damage taken from skills
-# move-speed - movement speed of the player
+# armor | [PREM, 1.9+] Vanilla damage mitigation
+# armor-toughness | [PREM, 1.9+] Secondary vanilla damage mitigation
+# attack-speed | [PREM, 1.9+] Weapon recharge time
+# cooldown | [PREM] Modifies skill cooldowns
+# defense- | [PREM] Reduces damage taken from various damage sources.
+# | See the DamageCause docs to see supported types.
+# | Use lower-case versions of it, such as "defense-block_explosion".
+# exp | [PREM] increases all class experience gained
+# health | The max health of the player
+# hunger | [PREM] Increases how long hunger lasts. This attribute is always based off of a base value of 1. A resulting value of 2 would double how long the hunger bar lasts, for example.
+# hunger-heal | [PREM] Increases how much you heal while satiated
+# knockback-resist | [PREM, 1.9+] Probability of resisting knockback as a decimal (1.0 is 100% change to resist)
+# luck | [PREM, 1.9+] loot table chances
+# mana | The max mana of the player
+# mana-regen | The amount of mana regeneration the player has
+# move-speed | The movement speed of the player
+# physical-damage | The amount of damage done by physical (basic or projectile) attacks
+# physical-defense | The amount of damage taken by physical (basic or projectile) attacks
+# skill-damage | The amount of damage done by skills
+# skill-defense | The amount of damage taken by skills
+
+# skill-damage- | [PREM] The amount of damage done by skills with the specified classification
+# skill-defense- | [PREM] The amount of damage taken by skills with the specified classification
vitality:
display: 'Vitality'
max: 999
diff --git a/config.yml b/configs/config.yml
similarity index 64%
rename from config.yml
rename to configs/config.yml
index 15267f28..de419500 100644
--- a/config.yml
+++ b/configs/config.yml
@@ -12,7 +12,12 @@ Accounts:
# The main class group used for GUI displays
main-class-group: class
#
- # Currently disabled, ignore this
+ # Allows one "account" per class, providing the "/class switch"
+ # command to change between them. This is an alternative to
+ # using "/class acc " which professes as a class at the same
+ # time and makes it easier to correlate an account to a class.
+ # This will not work well if you have one common class
+ # that turns into the rest.
one-per-class: false
#
# The max number of accounts a normal user can use
@@ -56,6 +61,15 @@ Targeting:
# - world1
# - world2
player-ally: false
+ #
+ # Whether or not to check for player allies via Parties
+ parties-ally: false
+ #
+ # Whether or not for skills to affect NPCs
+ affect-npcs: false
+ #
+ # Whether or not for skills to affect armor stands
+ affect-armor-stands: false
#
Saving:
#
@@ -75,6 +89,11 @@ Saving:
database: plugins
username: username
password: password
+ # Time to wait on loading data from the SQL database in ticks.
+ # Can be used to give time for other servers to synchronize data. Note:
+ # this does not apply when loading player data on server startup since
+ # players wouldn't be coming from another server.
+ delay: 0
#
Classes:
#
@@ -166,10 +185,22 @@ Items:
# The text used for providing attributes
attribute-text: '{attr}: '
#
- # How many players to check for the requirements each tick
- # This should be increased on larger servers to prevent
- # large delays before the same player is checked again
- players-per-check: 1
+ # The slots to check for items in and apply requirements to.
+ # This does not include held item, as that fluctuates and is assumed
+ # Slots are based on the following:
+ # 0-8 = hot bar
+ # 9-35 = main inventory
+ # 36 = boots
+ # 37 = leggings
+ # 38 = chestplate
+ # 39 = helmet
+ # 40 = off hand
+ slots:
+ - 36
+ - 37
+ - 38
+ - 39
+ - 40
#
GUI:
#
@@ -246,12 +277,117 @@ GUI:
# This always appears as {level} {text}
class-level-text: 'Level'
#
- # Whether or not to use map trees instead of the regular ones
- # View map.yml for further customization for this option
- # Also add more schemes by adding folders in the "img" folder
- # Allow for both map skill trees and regular ones by setting
- # this to "partial"
- map-tree-enabled: false
+ # Whether or not to append text to skill icons to show what type of item the skill is bound to
+ show-binds: false
+ #
+ # Text to show for bound materials
+ show-bind-text: 'Bound to {material}'
+#
+Casting:
+ #
+ # Whether or not the main casting option is enabled
+ enabled: false
+ #
+ # Whether or not to use the mult-bar implementation.
+ # When enabled:
+ # - Left/Right clicking on item opens skill bars
+ # - Skills assigned through tree
+ # - Preview when hovering in the skill bar
+ # - Limited number of skills can be put on skill bars
+ # When disabled:
+ # - Left/Right clicking on item cycles through skills
+ # - Preview when hovering the item
+ # - No limit on skills (though makes cycling hard to find skills)
+ bars: true
+ #
+ # Whether or not to use the combat bar implementation. Details:
+ # - Specified slot becomes a toggle item
+ # - Can optionally move over or require interacting (left, right, or drop) to swap modes
+ # - Swaps between combat mode and passive mode
+ # - In combat mode, works like the classic skill bar
+ # - In passive mode, no skills are shown
+ # - Passive and combat modes each have their own stored contents
+ # - combat mode uses the skill bar settings
+ combat: false
+ #
+ # Global cooldown between skill casts in seconds
+ cooldown: 0
+ #
+ # Settings for skill target indicators that play effects
+ # to show where a skill will hit
+ cast-indicator:
+ #
+ # Whether or not the feature is enabled
+ enabled: true
+ #
+ # How tightly to pack particles in the effect. A higher
+ # density will play more particles. It represents the
+ # amount of particles played per block units
+ density: 1
+ #
+ # How often the particles are played for the effect
+ # in plays per second
+ frequency: 10
+ #
+ # How fast position animations happen in blocks per second
+ animation: 1
+ #
+ # Particle to use when it has a target
+ particle:
+ particle: 'crit'
+ dx: 0
+ dy: 0
+ dz: 0
+ speed: 0
+ amount: 1
+ #
+ # The slot the item is kept in, must be in the range 1-9
+ slot: 9
+ #
+ # The item to use in the cast slot.
+ # When not using bars, this only shows up when no skills
+ # are available for use.
+ item:
+ type: BOOK
+ data: 0
+ durability: 0
+ name: '&dSkills'
+ lore:
+ - ''
+ - '&6Left Click&2 - First skill set'
+ - '&6Right Click&2 - Second skill set'
+ - '&6Q&2 - Organize skills'
+ #
+ # The item used in the bar GUI to describe the hover bar
+ hover-item:
+ type: BOOKSHELF
+ data: 0
+ durability: 0
+ name: '&6Hover Bar'
+ lore:
+ - ''
+ - 'Skills in this row will'
+ - 'be usable via left clicking'
+ - 'the cast item and will let'
+ - 'you see where they will hit'
+ - 'before casting them.'
+ #
+ # The item used in the bar GUI to describe the instant bar
+ instant-item:
+ type: BOOKSHELF
+ data: 0
+ durability: 0
+ name: '&6Instant Bar'
+ data: 0
+ durability: 0
+ name: '&6Instant Bar'
+ lore:
+ - ''
+ - 'Skills in this row will'
+ - 'be usable via right clicking'
+ - 'the cast item and will be'
+ - 'cast immediately when switching'
+ - 'to their slot.'
#
Click Combos:
#
@@ -261,6 +397,12 @@ Click Combos:
# Whether or not players can customize their combos
allow-custom: false
#
+ # Whether or not to automatically assign combos to skills
+ # without a combo manually defined. When disabled, only skills
+ # configured to have a combo or have had a combo set by
+ # a command will have combos.
+ auto-assign: true
+ #
# Whether or not left clicks are allowed at all
use-click-left: true
#
@@ -270,6 +412,21 @@ Click Combos:
# Whether or not shift clicks are allowed at all
use-click-shift: false
#
+ # Whether or not right shift clicks are allowed at all
+ # This will disable "use-click-shift" if enabled
+ use-click-right-shift: false
+ #
+ # Whether or not left shift clicks are allowed at all
+ # This will disable "use-click-shift" if enabled
+ use-click-left-shift: false
+ #
+ # Whether or not jump clicks are allowed at all
+ use-click-space: false
+ #
+ # Whether or not Q clicks are allowed at all.
+ # Enabling this disables dropping items via Q outside of menus.
+ use-click-q: false
+ #
# How many clicks are needed to perform a combo
combo-size: 4
#
@@ -350,6 +507,10 @@ Experience:
# Whether or not to show a message when losing exp de to dying
lose-exp-message: true
#
+ # Worlds where experience is not lost on death
+ lose-exp-blacklist:
+ - 'pvpWorld'
+ #
# The formula used for calculating required experience
# The formula is: x*lvl*lvl + y*lvl + z
formula:
@@ -361,34 +522,41 @@ Experience:
use-custom: false
#
# The custom formula to use with 'lvl' being the current player level
+ # Note: this formula does not use x, y, or z. Use numbers directly
+ # in the formula instead.
custom-formula: '25(1.1^(lvl-1))'
#
# The experience yields from each mob type
# When exp orbs are enabled, these values are ignored
yields:
- blaze: 10
- cavespider: 5
- creeper: 3
- elderguardian: 10
- enderdragon: 400
- enderman: 5
- endermite: 3
- ghast: 5
- giant: 20
- guardian: 10
- irongolem: 10
- magmacube: 1
- pigzombie: 5
- player: 5
- shulker: 5
- silverfish: 2
- skeleton: 3
- slime: 1
- spider: 3
- witch: 3
- wither: 500
- witherskeleton: 5
- zombie: 2
+ blaze: '10'
+ cavespider: '5'
+ creeper: '3'
+ elderguardian: '10'
+ enderdragon: '400'
+ enderman: '5'
+ endermite: '3'
+ evoker: '10'
+ ghast: '5'
+ giant: '20'
+ guardian: '10'
+ husk: '2'
+ irongolem: '10'
+ magmacube: '1'
+ pigzombie: '5'
+ player: '5'
+ shulker: '5'
+ silverfish: '2'
+ skeleton: '3'
+ slime: '1'
+ spider: '3'
+ stray: '5'
+ vex: '3'
+ vindicator: '5'
+ witch: '3'
+ wither: '500'
+ witherskeleton: '5'
+ zombie: '2'
#
# How much logging to do when loading SkillAPI
# When testing setting up skills/classes, increase this to 1-5
diff --git a/configs/effects.yml b/configs/effects.yml
new file mode 100644
index 00000000..99384157
--- /dev/null
+++ b/configs/effects.yml
@@ -0,0 +1,128 @@
+single:
+ formula: 0
+ steps: 1
+ copies: 1
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+linear:
+ formula: 1
+ steps: 20
+ copies: 1
+ domain: 0
+ x: 0
+ y: 0
+ z: 0
+linear-quick:
+ formula: 1
+ steps: 10
+ copies: 1
+ domain: 0
+ x: 0
+ y: 0
+ z: 0
+still:
+ formula: 0
+ steps: 20
+ copies: 1
+ domain: 0
+ x: 0
+ y: 0
+ z: 0
+one-point:
+ formula: 1
+ steps: 1
+ copies: 1
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+two-point:
+ formula: 1
+ steps: 2
+ copies: 1
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+three-point:
+ formula: 1
+ steps: 3
+ copies: 1
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+one-circle:
+ formula: 1
+ steps: 20
+ copies: 1
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+two-circle:
+ formula: 1
+ steps: 20
+ copies: 2
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+three-circle:
+ formula: 1
+ steps: 20
+ copies: 3
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+one-spiral:
+ formula: t
+ steps: 20
+ copies: 1
+ domain: 1
+ x: 0
+ y: 0
+ z: 0
+two-spiral:
+ formula: t*0.5
+ steps: 40
+ copies: 1
+ domain: 2
+ x: 0
+ y: 0
+ z: 0
+three-spiral:
+ formula: t*0.333
+ steps: 60
+ copies: 1
+ domain: 3
+ x: 0
+ y: 0
+ z: 0
+square:
+ formula: 1/c
+ steps: 5
+ copies: 8
+ domain: 0.125
+ x: 0
+ y: 0
+ z: 0
+pentagon:
+ formula: 1/c
+ steps: 5
+ copies: 10
+ domain: 0.1
+ x: 0
+ y: 0
+ z: 0
+hexagon:
+ formula: 1/c
+ steps: 4
+ copies: 12
+ domain: 0.08333
+ x: 0
+ y: 0
+ z: 0
\ No newline at end of file
diff --git a/configs/exp.yml b/configs/exp.yml
new file mode 100644
index 00000000..ba395697
--- /dev/null
+++ b/configs/exp.yml
@@ -0,0 +1,76 @@
+# Whether or not to enable controlling experience from broken/placed blocks or crafted items
+enabled: false
+
+# Experience yields for anything except combat. Combat experience is either controlled
+# via vanilla experience dropped or the yields defined in config.yml.
+#
+# These are experience values provided when a player breaks a block.
+break:
+ #
+ # Whether or not to allow players to place a block back down and break it again
+ # to get additional experience. Note that disabling this will cause all block
+ # changes to be tracked in order to remember what was placed or not. Blocks
+ # existing before this is disabled will not be protected from experience yields.
+ allow-replace: true
+ #
+ # The yields per block type. You can add any block types not in this list by simply
+ # appending the bukkit name of the block type. See
+ # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html
+ # for valid types. This list is not case-sensitive.
+ types:
+ #
+ # You can add classes as well that allow certain blocks only to benefit
+ # that class. For example, if you want a miner to benefit from ore but
+ # a farmer to benefit from crops, you can add a "miner" section containing
+ # the ore and a "farmer" section containing the crops. This would look something
+ # like:
+ #
+ # # Blocks only for miners
+ # miner:
+ # COAL: 1
+ # IRON_ORE: 10
+ # # Blocks only for farmers
+ # farmer:
+ # CROPS: 5
+ default:
+ COAL: 1
+ QUARTZ_ORE: 1
+ IRON_ORE: 10
+ GOLD_ORE: 15
+ REDSTONE_ORE: 20
+ LAPIS_ORE: 25
+ DIAMOND_ORE: 50
+ EMERALD_ORE: 100
+#
+# Experience yields when a player places a block. There's not a built-in way to check
+# for players repeatedly placing down the same block, so use this type of experience
+# with caution. Works similar to break, just without the replace option.
+place:
+ default:
+ DIAMOND_BLOCK: 1
+#
+# Experience yields when a player crafts items.
+craft:
+ #
+ # Similar to above, you can specify classes to get
+ # experience from different crafts.
+ default:
+ BOW: 5
+ IRON_CHESTPLATE: 80
+ IRON_LEGGINGS: 70
+ IRON_HELMET: 50
+ IRON_BOOTS: 40
+ IRON_SWORD: 20
+ IRON_AXE: 30
+ GOLD_CHESTPLATE: 120
+ GOLD_LEGGINGS: 105
+ GOLD_HELMET: 75
+ GOLD_BOOTS: 60
+ GOLD_SWORD: 30
+ GOLD_AXE: 45
+ DIAMOND_CHESTPLATE: 400
+ DIAMOND_LEGGINGS: 350
+ DIAMOND_HELMET: 250
+ DIAMOND_BOOTS: 200
+ DIAMOND_SWORD: 100
+ DIAMOND_AXE: 150
\ No newline at end of file
diff --git a/configs/internal/mobSizes.yml b/configs/internal/mobSizes.yml
new file mode 100644
index 00000000..0d3c3c08
--- /dev/null
+++ b/configs/internal/mobSizes.yml
@@ -0,0 +1,249 @@
+Baby Turtle:
+ size: 0.32
+ height: 0.12
+Baby Rabbit:
+ size: 0.2
+ height: 0.25
+Cod:
+ size: 0.5
+ height: 0.3
+Baby Chicken:
+ size: 0.2
+ height: 0.35
+Baby Ocelot/Cat:
+ size: 0.3
+ height: 0.35
+Tropical Fish:
+ size: 0.5
+ height: 0.4
+Salmon:
+ size: 0.7
+ height: 0.4
+Turtle:
+ size: 1.1
+ height: 0.4
+Baby Wolf:
+ size: 0.3
+ height: 0.425
+Baby Pig:
+ size: 0.45
+ height: 0.45
+Rabbit:
+ size: 0.4
+ height: 0.5
+Pufferfish:
+ size: 0.7
+ height: 0.7
+Dolphin:
+ size: 0.9
+ height: 0.6
+Baby Panda:
+ size: 0.65
+ height: 0.625
+Baby Sheep:
+ size: 0.45
+ height: 0.675
+Chicken:
+ size: 0.4
+ height: 0.7
+Baby Cow:
+ size: 0.45
+ height: 0.7
+Baby Mooshroom:
+ size: 0.45
+ height: 0.7
+Baby Polar Bear:
+ size: 0.65
+ height: 0.7
+Ocelot:
+ size: 0.6
+ height: 0.7
+Cat:
+ size: 0.6
+ height: 0.7
+Baby Horses:
+ size: 0.6982
+ height: 0.8
+Wolf:
+ size: 0.6
+ height: 0.85
+Dog:
+ size: 0.6
+ height: 0.85
+Pig:
+ size: 0.9
+ height: 0.9
+Baby Llama:
+ size: 0.45
+ height: 0.9375
+Panda:
+ size: 1.3
+ height: 1.25
+Sheep:
+ size: 0.9
+ height: 1.3
+Cow:
+ size: 0.9
+ height: 1.4
+Mooshroom:
+ size: 0.9
+ height: 1.4
+Polar Bear:
+ size: 1.3
+ height: 1.4
+Horse:
+ size: 1.3964
+ height: 1.6
+Llama:
+ size: 0.9
+ height: 1.875
+Ravager:
+ size: 1.95
+ height: 2.2
+Endermite:
+ size: 0.4
+ height: 0.3
+Silverfish:
+ size: 0.4
+ height: 0.3
+Cave Spider:
+ size: 0.7
+ height: 0.5
+Phantom:
+ size: 0.8
+ height: 0.5
+Small Slime:
+ size: 0.51
+ height: 0.51
+Magma Cube:
+ size: 0.51
+ height: 0.51
+Vex:
+ size: 0.4
+ height: 0.8
+Guardian:
+ size: 0.85
+ height: 0.85
+Spider:
+ size: 1.4
+ height: 0.9
+Baby Zombie:
+ size: 0.3
+ height: 0.975
+Baby Husk:
+ size: 0.3
+ height: 0.975
+Baby Drowned:
+ size: 0.3
+ height: 0.975
+Shulker:
+ size: 1
+ height: 1
+Medium Slime:
+ size: 1.02
+ height: 1.02
+Medium Magma Cube:
+ size: 1.02
+ height: 1.02
+Creeper:
+ size: 0.6
+ height: 1.7
+Blaze:
+ size: 0.6
+ height: 1.8
+Zombie:
+ size: 0.6
+ height: 1.95
+Evoker:
+ size: 0.6
+ height: 1.95
+Villager:
+ size: 0.6
+ height: 1.95
+Husk:
+ size: 0.6
+ height: 1.95
+Witch:
+ size: 0.6
+ height: 1.95
+Vindicator:
+ size: 0.6
+ height: 1.95
+Illusioner:
+ size: 0.6
+ height: 1.95
+Drowned:
+ size: 0.6
+ height: 1.95
+Pigman:
+ size: 0.6
+ height: 1.95
+Pillager:
+ size: 0.6
+ height: 1.95
+Skeleton/Stray:
+ size: 0.6
+ height: 1.99
+Elder Guardian:
+ size: 2
+ height: 2
+Large Slime:
+ size: 2.04
+ height: 2.04
+Large Magma Cube:
+ size: 2.04
+ height: 2.04
+Wither Skeleton:
+ size: 0.7
+ height: 2.4
+Enderman:
+ size: 0.6
+ height: 2.9
+Wither:
+ size: 0.9
+ height: 3.5
+Ghast:
+ size: 4
+ height: 4
+Giant:
+ size: 3.6
+ height: 11.7
+Ender Dragon:
+ size: 16
+ height: 8
+Squid:
+ size: 0.8
+ height: 0.8
+Bat/Parrot:
+ size: 0.5
+ height: 0.9
+Snow Golem:
+ size: 0.7
+ height: 1.9
+Iron Golem:
+ size: 1.4
+ height: 2.7
+Minecart:
+ size: 0.98
+ height: 0.7
+Boat:
+ size: 1.375
+ height: 0.5625
+Armor Stand:
+ size: 0.5
+ height: 1.975
+Falling Block:
+ size: 0.98
+ height: 0.98
+Xp Orb:
+ size: 0.5
+ height: 0.5
+Item:
+ size: 0.25
+ height: 0.25
+Ender Crystal:
+ size: 2
+ height: 2
+Player:
+ size: 0.6
+ height: 1.8
\ No newline at end of file
diff --git a/language.yml b/configs/language.yml
similarity index 95%
rename from language.yml
rename to configs/language.yml
index 20d18e99..672001b7 100644
--- a/language.yml
+++ b/configs/language.yml
@@ -20,6 +20,7 @@ Errors:
cannot-use: '&4You cannot equip that item'
GUI:
attribute-title: 'Attributes ({points} points)'
+ profess-title: 'Profess'
skill-tree: '{class}'
skill-class-list: '{player}'
Skill Tree:
@@ -62,3 +63,8 @@ Combo:
left: '&6Left'
right: '&6Right'
shift: '&6Shift'
+ left_shift: '&6Shift L'
+ right_shift: '&6Shift R'
+ space: '&6Jump'
+ q: '&6Drop'
+
diff --git a/plugin.yml b/configs/plugin.yml
similarity index 87%
rename from plugin.yml
rename to configs/plugin.yml
index a4059bc8..49f92ef5 100644
--- a/plugin.yml
+++ b/configs/plugin.yml
@@ -1,18 +1,16 @@
name: SkillAPI
main: com.sucy.skill.SkillAPI
-version: 3.99
+version: 1.90
author: Eniripsa96
depend: [MCCore]
softdepend: [Vault]
loadbefore: [Quests]
+api-version: 1.13
permissions:
skillapi.basic:
description: access to skill trees and using skills
default: true
- skillapi.backup:
- dscription: allows backing up the SQL database
- default: op
skillapi.reset:
description: access to resetting your class
default: true
@@ -46,9 +44,12 @@ permissions:
skillapi.attrib:
description: access to giving attribute points
default: op
+ skillapi.gui:
+ description: access to GUI editor menu
+ default: op
skillapi.*:
- description: access to all commands
+ description: access to all commands and features
default: op
children:
skillapi.basic: true
@@ -60,4 +61,5 @@ permissions:
skillapi.reload: true
skillapi.class: true
skillapi.skill: true
- skillapi.lore: true
\ No newline at end of file
+ skillapi.lore: true
+ skillapi.gui: true
diff --git a/configs/tool.yml b/configs/tool.yml
new file mode 100644
index 00000000..646281f4
--- /dev/null
+++ b/configs/tool.yml
@@ -0,0 +1,17 @@
+# Define extra items usable in the GUI editor here.
+# NEXT_PAGE nad PREV_PAGE are provided as the items
+# used for pages. Do not remove them.
+NEXT_PAGE:
+ type: 'Book'
+ data: 0
+ durability: 0
+ name: '&6Next Page'
+ lore:
+ - ''
+PREV_PAGE:
+ type: 'Book'
+ data: 0
+ durability: 0
+ name: '&6Prev Page'
+ lore:
+ - ''
\ No newline at end of file
diff --git a/configs/worldGuard.yml b/configs/worldGuard.yml
new file mode 100644
index 00000000..77bf9ebe
--- /dev/null
+++ b/configs/worldGuard.yml
@@ -0,0 +1,10 @@
+#
+# WorldGuard region IDs that players cannot cast skills in
+disable-skills:
+- fakeZoneId1
+- fakeZoneId2
+#
+# WorldGuard region IDs that players cannot earn experience in
+disable-exp:
+- fakeZoneId1
+- fakeZoneId2
\ No newline at end of file
diff --git a/editor/builderStyle.css b/editor/builderStyle.css
index 0b4dda4d..3669a6cd 100644
--- a/editor/builderStyle.css
+++ b/editor/builderStyle.css
@@ -2,8 +2,8 @@
h3 {
padding: 5px;
- border-radius: 8px;
- background-color: #111;
+ border-radius: 5px;
+ background-color: transparent;
transition: background-color 600ms;
}
@@ -41,10 +41,10 @@ h3:hover {
.component {
padding: 5px;
margin: 5px;
- border: 2px solid #ccc;
+ border: 2px solid #333;
border-radius: 10px;
font: 18px Sertig-Web;
- background-color: #111;
+ background-color: #181818;
width: 260px;
height: 90px;
}
@@ -55,17 +55,16 @@ h3:hover {
.builderButton {
float: left;
- background-color: #222;
+ background-color: #043;
width: 90px;
height: 32px;
font: 16px Sertig-Web;
- border-radius: 8px;
+ border-radius: 5px;
padding: 5px;
padding-left: 10px;
color: white;
cursor: pointer;
margin: 5px;
- border: 1px solid #ccc;
transition: background-color 600ms;
}
diff --git a/editor/js/class.js b/editor/js/class.js
index f38ec2a5..190f38bf 100644
--- a/editor/js/class.js
+++ b/editor/js/class.js
@@ -30,7 +30,9 @@ function Class(name)
new IntValue('Icon Data', 'icon-data', 0).setTooltip('The data/durability value of the item that represents the class in GUIs'),
new StringListValue('Icon Lore', 'icon-lore', [
'&d' + name
- ]).setTooltip('The text shown on the item for the class in GUIs')
+ ]),
+ new StringListValue('Unusable Items', 'blacklist', [ ]).setTooltip('The types of items that the class cannot use (one per line)'),
+ new StringValue('Action Bar', 'action-bar', '').setTooltip('The format for the action bar. Leave blank to use the default formatting.')
];
this.updateAttribs(10);
@@ -94,6 +96,10 @@ Class.prototype.createFormHTML = function()
// Append attributes
if (this.data[i].name == 'Mana')
{
+ var dragInstructions = document.createElement('label');
+ dragInstructions.id = 'attribute-label';
+ dragInstructions.innerHTML = 'Drag/Drop your attributes.yml file to see custom attributes';
+ form.appendChild(dragInstructions);
this.updateAttribs(i + 1);
}
}
@@ -102,7 +108,7 @@ Class.prototype.createFormHTML = function()
form.appendChild(hr);
var save = document.createElement('h5');
- save.innerHTML = 'Save',
+ save.innerHTML = 'Save Class',
save.classData = this;
save.addEventListener('click', function(e) {
this.classData.update();
diff --git a/editor/js/component.js b/editor/js/component.js
index a227b63a..7d810fd6 100644
--- a/editor/js/component.js
+++ b/editor/js/component.js
@@ -27,6 +27,8 @@ var Type = {
* Available triggers for activating skill effects
*/
var Trigger = {
+ BLOCK_BREAK : { name: 'Block Break', container: true, construct: TriggerBlockBreak, premium: true },
+ BLOCK_PLACE : { name: 'Block Place', container: true, construct: TriggerBlockPlace, premium: true },
CAST : { name: 'Cast', container: true, construct: TriggerCast },
CLEANUP : { name: 'Cleanup', container: true, construct: TriggerCleanup },
CROUCH : { name: 'Crouch', container: true, construct: TriggerCrouch },
@@ -36,6 +38,7 @@ var Trigger = {
KILL : { name: 'Kill', container: true, construct: TriggerKill },
LAND : { name: 'Land', container: true, construct: TriggerLand },
LAUNCH : { name: 'Launch', container: true, construct: TriggerLaunch },
+ MOVE : { name: 'Move', container: true, construct: TriggerMove, premium: true },
PHYSICAL_DAMAGE : { name: 'Physical Damage', container: true, construct: TriggerPhysicalDamage },
SKILL_DAMAGE : { name: 'Skill Damage', container: true, construct: TriggerSkillDamage },
TOOK_PHYSICAL_DAMAGE : { name: 'Took Physical Damage', container: true, construct: TriggerTookPhysicalDamage },
@@ -65,6 +68,7 @@ var Condition = {
ATTRIBUTE: { name: 'Attribute', container: true, construct: ConditionAttribute },
BIOME: { name: 'Biome', container: true, construct: ConditionBiome },
BLOCK: { name: 'Block', container: true, construct: ConditionBlock },
+ CEILING: { name: 'Ceiling', container: true, construct: ConditionCeiling, premium: true },
CHANCE: { name: 'Chance', container: true, construct: ConditionChance },
CLASS: { name: 'Class', container: true, construct: ConditionClass },
CLASS_LEVEL: { name: 'Class Level', container: true, construct: ConditionClassLevel },
@@ -76,6 +80,7 @@ var Condition = {
ENTITY_TYPE: { name: 'Entity Type', container: true, construct: ConditionEntityType,premium: true },
FIRE: { name: 'Fire', container: true, construct: ConditionFire },
FLAG: { name: 'Flag', container: true, construct: ConditionFlag },
+ GROUND: { name: 'Ground', container: true, construct: ConditionGround, premium: true },
HEALTH: { name: 'Health', container: true, construct: ConditionHealth },
INVENTORY: { name: 'Inventory', container: true, construct: ConditionInventory },
ITEM: { name: 'Item', container: true, construct: ConditionItem },
@@ -91,7 +96,8 @@ var Condition = {
TIME: { name: 'Time', container: true, construct: ConditionTime },
TOOL: { name: 'Tool', container: true, construct: ConditionTool },
VALUE: { name: 'Value', container: true, construct: ConditionValue },
- WATER: { name: 'Water', container: true, construct: ConditionWater }
+ WATER: { name: 'Water', container: true, construct: ConditionWater },
+ WEATHER: { name: 'Weather', container: true, construct: ConditionWeather, premium: true }
};
/**
@@ -100,6 +106,7 @@ var Condition = {
var Mechanic = {
ATTRIBUTE: { name: 'Attribute', container: false, construct: MechanicAttribute },
BLOCK: { name: 'Block', container: false, construct: MechanicBlock },
+ BUFF: { name: 'Buff', container: false, construct: MechanicBuff, premium: true },
CANCEL: { name: 'Cancel', container: false, construct: MechanicCancel },
CHANNEL: { name: 'Channel', container: true, construct: MechanicChannel },
CLEANSE: { name: 'Cleanse', container: false, construct: MechanicCleanse },
@@ -111,12 +118,16 @@ var Mechanic = {
DEFENSE_BUFF: { name: 'Defense Buff', container: false, construct: MechanicDefenseBuff },
DELAY: { name: 'Delay', container: true, construct: MechanicDelay },
DISGUISE: { name: 'Disguise', container: false, construct: MechanicDisguise },
+ DURABILITY: { name: 'Durability', container: false, construct: MechanicDurability, premium: true },
EXPLOSION: { name: 'Explosion', container: false, construct: MechanicExplosion },
FIRE: { name: 'Fire', container: false, construct: MechanicFire },
FLAG: { name: 'Flag', container: false, construct: MechanicFlag },
FLAG_CLEAR: { name: 'Flag Clear', container: false, construct: MechanicFlagClear },
FLAG_TOGGLE: { name: 'Flag Toggle', container: false, construct: MechanicFlagToggle },
+ FOOD: { name: 'Food', container: false, construct: MechanicFood, premium: true },
+ FORGET_TARGETS: { name: 'Forget Targets', container: false, construct: MechanicForgetTargets, premium: true },
HEAL: { name: 'Heal', container: false, construct: MechanicHeal },
+ HEALTH_SET: { name: 'Health Set', container: false, construct: MechanicHealthSet, premium: true },
HELD_ITEM: { name: 'Held Item', container: false, construct: MechanicHeldItem, premium: true },
IMMUNITY: { name: 'Immunity', container: false, construct: MechanicImmunity },
INTERRUPT: { name: 'Interrupt', container: false, construct: MechanicInterrupt },
@@ -145,14 +156,18 @@ var Mechanic = {
SPEED: { name: 'Speed', container: false, construct: MechanicSpeed },
STATUS: { name: 'Status', container: false, construct: MechanicStatus },
TAUNT: { name: 'Taunt', container: false, construct: MechanicTaunt },
+ TRIGGER: { name: 'Trigger', container: true, construct: MechanicTrigger, premium: true },
VALUE_ADD: { name: 'Value Add', container: false, construct: MechanicValueAdd },
VALUE_ATTRIBUTE: { name: 'Value Attribute', container: false, construct: MechanicValueAttribute },
+ VALUE_COPY: { name: 'Value Copy', container: false, construct: MechanicValueCopy, premium: true },
+ VALUE_DISTANCE: { name: 'Value Distance', container: false, construct: MechanicValueDistance, premium: true },
VALUE_HEALTH: { name: 'Value Health', container: false, construct: MechanicValueHealth, premium: true },
VALUE_LOCATION: { name: 'Value Location', container: false, construct: MechanicValueLocation },
VALUE_LORE: { name: 'Value Lore', container: false, construct: MechanicValueLore },
VALUE_LORE_SLOT: { name: 'Value Lore Slot', container: false, construct: MechanicValueLoreSlot, premium: true},
VALUE_MANA: { name: 'Value Mana', container: false, construct: MechanicValueMana, premium: true },
VALUE_MULTIPLY: { name: 'Value Multiply', container: false, construct: MechanicValueMultiply },
+ VALUE_PLACEHOLDER: { name: 'Value Placeholder', container: false, construct: MechanicValuePlaceholder, premium: true },
VALUE_RANDOM: { name: 'Value Random', container: false, construct: MechanicValueRandom },
VALUE_SET: { name: 'Value Set', container: false, construct: MechanicValueSet },
WARP: { name: 'Warp', container: false, construct: MechanicWarp },
@@ -168,7 +183,7 @@ var saveIndex;
/**
* Represents a component of a dynamic skill
- *
+ *
* @param {string} name - name of the component
* @param {string} type - type of the component
* @param {boolean} container - whether or not the component can contain others
@@ -199,7 +214,7 @@ function Component(name, type, container, parent)
.setTooltip('Whether or not this trigger requires to be off cooldown to activate')
);
}
-
+
this.dataKey = 'data';
this.componentKey = 'children';
}
@@ -210,12 +225,14 @@ Component.prototype.dupe = function(parent)
var ele = new Component(this.name, this.type, this.container, parent);
for (i = 0; i < this.components.length; i++)
{
- ele.components.push(this.components[i].dupe());
+ ele.components.push(this.components[i].dupe(ele));
}
+ ele.data = ele.data.slice(0, 1);
for (i = ele.data.length; i < this.data.length; i++)
{
- ele.data.push(this.data[i].dupe());
+ ele.data.push(copyRequirements(this.data[i], this.data[i].dupe()));
}
+ ele.description = this.description;
return ele;
}
@@ -233,7 +250,7 @@ Component.prototype.createBuilderHTML = function(target)
if (this.type == Type.TRIGGER) {
container.className = 'componentWrapper';
}
-
+
var div = document.createElement('div');
div.className = 'component ' + this.type;
if (this.type != Type.TRIGGER) {
@@ -244,7 +261,7 @@ Component.prototype.createBuilderHTML = function(target)
if (this.container) {
div.ondragover = this.allowDrop;
}
-
+
// Component label
var label = document.createElement('h3');
label.title = 'Edit ' + this.name + ' options';
@@ -256,20 +273,20 @@ Component.prototype.createBuilderHTML = function(target)
showSkillPage('skillForm');
});
div.appendChild(label);
-
+
// Container components can add children so they get a button
- if (this.container)
+ if (this.container)
{
var add = document.createElement('div');
add.className = 'builderButton';
add.innerHTML = '+ Add Child';
add.component = this;
add.addEventListener('click', function(e) {
- activeComponent = this.component;
+ activeComponent = this.component;
showSkillPage('componentChooser');
});
div.appendChild(add);
-
+
var vision = document.createElement('div');
vision.title = 'Hide Children';
vision.className = 'builderButton smallButton';
@@ -282,7 +299,7 @@ Component.prototype.createBuilderHTML = function(target)
comp.childDiv.style.display = 'block';
this.style.backgroundImage = 'url("editor/img/eye.png")';
}
- else
+ else
{
comp.childDiv.style.display = 'none';
this.style.backgroundImage = 'url("editor/img/eyeShaded.png")';
@@ -292,7 +309,7 @@ Component.prototype.createBuilderHTML = function(target)
div.appendChild(vision);
this.childrenHidden = false;
}
-
+
// Add the duplicate button
if (this.type != Type.TRIGGER)
{
@@ -309,7 +326,7 @@ Component.prototype.createBuilderHTML = function(target)
});
div.appendChild(duplicate);
}
-
+
// Add the remove button
var remove = document.createElement('div');
remove.title = 'Remove';
@@ -318,7 +335,7 @@ Component.prototype.createBuilderHTML = function(target)
remove.component = this;
remove.addEventListener('click', function(e) {
var list = this.component.parent.components;
- for (var i = 0; i < list.length; i++)
+ for (var i = 0; i < list.length; i++)
{
if (list[i] == this.component)
{
@@ -329,26 +346,26 @@ Component.prototype.createBuilderHTML = function(target)
this.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
});
div.appendChild(remove);
-
+
container.appendChild(div);
-
+
// Apply child components
var childContainer = document.createElement('div');
childContainer.className = 'componentChildren';
if (this.components.length > 0) {
- for (var i = 0; i < this.components.length; i++)
+ for (var i = 0; i < this.components.length; i++)
{
this.components[i].createBuilderHTML(childContainer);
}
}
container.appendChild(childContainer);
this.childDiv = childContainer;
-
+
// Append the content
target.appendChild(container);
-
+
this.html = childContainer;
-}
+};
Component.prototype.allowDrop = function(e) {
e.preventDefault();
@@ -390,7 +407,7 @@ Component.prototype.drop = function(e) {
hoverSpace.style.marginBottom = '0px';
hoverSpace = undefined;
}
-
+
e.preventDefault();
var thing = document.getElementById('dragComponent').parentNode;
var target = e.target;
@@ -405,7 +422,7 @@ Component.prototype.drop = function(e) {
target = target.parentNode.childNodes[1];
thing.parentNode.removeChild(thing);
target.appendChild(thing);
-
+
thingComp.parent.components.splice(thingComp.parent.components.indexOf(thingComp), 1);
thingComp.parent = targetComp;
thingComp.parent.components.push(thingComp);
@@ -418,25 +435,25 @@ Component.prototype.drop = function(e) {
Component.prototype.createFormHTML = function()
{
var target = document.getElementById('skillForm');
-
+
var form = document.createElement('form');
-
+
var header = document.createElement('h4');
header.innerHTML = this.name;
form.appendChild(header);
-
+
if (this.description)
{
var desc = document.createElement('p');
desc.innerHTML = this.description;
form.appendChild(desc);
}
-
- if (this.data.length > 1)
+
+ if (this.data.length > 1)
{
var h = document.createElement('hr');
form.appendChild(h);
-
+
var i = 1;
for (var j = 1; j < this.data.length; j++) {
if (this.data[j] instanceof AttributeValue) {
@@ -450,10 +467,10 @@ Component.prototype.createFormHTML = function()
this.data[i].createHTML(form);
}
}
-
+
var hr = document.createElement('hr');
form.appendChild(hr);
-
+
var done = document.createElement('h5');
done.className = 'doneButton';
done.innerHTML = 'Done';
@@ -464,13 +481,13 @@ Component.prototype.createFormHTML = function()
showSkillPage('builder');
});
form.appendChild(done);
-
+
this.form = form;
-
+
target.innerHTML = '';
target.appendChild(form);
activeComponent = this;
-
+
for (var i = 0; i < this.data.length; i++)
{
this.data[i].applyRequireValues();
@@ -496,7 +513,7 @@ Component.prototype.update = function()
Component.prototype.getSaveString = function(spacing)
{
this.createFormHTML();
-
+
var id = '';
var index = saveIndex;
while (index > 0 || id.length == 0)
@@ -506,7 +523,7 @@ Component.prototype.getSaveString = function(spacing)
}
var result = spacing + this.name + '-' + id + ":\n";
saveIndex++;
-
+
result += spacing + " type: '" + this.type + "'\n";
if (this.data.length > 0)
{
@@ -539,11 +556,37 @@ Component.prototype.load = loadSection;
// -- Trigger constructors ----------------------------------------------------- //
+extend('TriggerBlockBreak', 'Component');
+function TriggerBlockBreak() {
+ this.super('Block Break', Type.TRIGGER, true);
+ this.description = 'Applies skill effects when a player breaks a block matching the given details';
+
+ this.data.push(new MultiListValue('Material', 'material', [ 'Any' ].concat(materialList), [ 'Any' ])
+ .setTooltip('The type of block expected to be broken')
+ );
+ this.data.push(new IntValue('Data', 'data', -1)
+ .setTooltip('The expected data value of the block (-1 for any data value)')
+ );
+}
+
+extend('TriggerBlockPlace', 'Component');
+function TriggerBlockPlace() {
+ this.super('Block Place', Type.TRIGGER, true);
+ this.description = 'Applies skill effects when a player places a block matching the given details';
+
+ this.data.push(new MultiListValue('Material', 'material', [ 'Any' ].concat(materialList), [ 'Any' ])
+ .setTooltip('The type of block expected to be placed')
+ );
+ this.data.push(new IntValue('Data', 'data', -1)
+ .setTooltip('The expected data value of the block (-1 for any data value)')
+ );
+}
+
extend('TriggerCast', 'Component');
function TriggerCast()
{
this.super('Cast', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player casts the skill using either the cast command, the skill bar, or click combos.';
}
@@ -551,7 +594,7 @@ extend('TriggerCleanup', 'Component');
function TriggerCleanup()
{
this.super('Cleanup', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when the player disconnects or unlearns the skill. This is always applied with a skill level of 1 just for the sake of math.';
}
@@ -559,9 +602,9 @@ extend('TriggerCrouch', 'Component');
function TriggerCrouch()
{
this.super('Crouch', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player starts or stops crouching using the shift key.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Start Crouching', 'Stop Crouching', 'Both' ], 'Start Crouching')
.setTooltip('Whether or not you want to apply components when crouching or not crouching')
);
@@ -571,7 +614,7 @@ extend('TriggerDeath', 'Component');
function TriggerDeath()
{
this.super('Death', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player dies.';
}
@@ -579,10 +622,12 @@ extend('TriggerEnvironmentDamage', 'Component');
function TriggerEnvironmentDamage()
{
this.super('Environment Damage', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player takes environmental damage.';
-
- this.data.push(new ListValue('Type', 'type', DAMAGE_TYPES, 'FALL'));
+
+ this.data.push(new ListValue('Type', 'type', DAMAGE_TYPES, 'FALL')
+ .setTooltip('The source of damage to apply for')
+ );
}
@@ -590,7 +635,7 @@ extend('TriggerInitialize', 'Component');
function TriggerInitialize()
{
this.super('Initialize', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects immediately. This can be used for passive abilities.';
}
@@ -598,7 +643,7 @@ extend('TriggerKill', 'Component');
function TriggerKill()
{
this.super('Kill', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects upon killing something';
}
@@ -606,9 +651,9 @@ extend('TriggerLand', 'Component');
function TriggerLand()
{
this.super('Land', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player lands on the ground.';
-
+
this.data.push(new DoubleValue('Min Distance', 'min-distance', 0)
.setTooltip('The minimum distance the player should fall before effects activating.')
);
@@ -618,24 +663,32 @@ extend('TriggerLaunch', 'Component');
function TriggerLaunch()
{
this.super('Launch', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player launches a projectile.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Any', 'Arrow', 'Egg', 'Ender Pearl', 'Fireball', 'Fishing Hook', 'Snowball' ], 'Any')
.setTooltip('The type of projectile that should be launched.')
);
}
+extend('TriggerMove', 'Component');
+function TriggerMove()
+{
+ this.super('Move', Type.TRIGGER, true);
+
+ this.description = 'Applies skill effects when a player moves around. This triggers every tick the player is moving, so use this sparingly. Use the "api-moved" value to check/use the distance traveled.';
+}
+
extend('TriggerPhysicalDamage', 'Component');
function TriggerPhysicalDamage()
{
this.super('Physical Damage', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player deals physical (or non-skill) damage. This includes melee attacks and firing a bow.';
-
+
this.data.push(new ListValue('Target Caster', 'target', [ 'True', 'False' ], 'True')
.setTooltip('True makes children target the caster. False makes children target the damaged entity')
- );
+ );
this.data.push(new ListValue('Type', 'type', [ 'Both', 'Melee', 'Projectile' ], 'Both')
.setTooltip('The type of damage dealt')
);
@@ -651,30 +704,33 @@ extend('TriggerSkillDamage', 'Component');
function TriggerSkillDamage()
{
this.super('Skill Damage', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player deals damage with a skill.';
-
+
this.data.push(new ListValue('Target Caster', 'target', [ 'True', 'False' ], 'True')
.setTooltip('True makes children target the caster. False makes children target the damaged entity')
- );
+ );
this.data.push(new DoubleValue("Min Damage", "dmg-min", 0)
.setTooltip('The minimum damage that needs to be dealt')
);
this.data.push(new DoubleValue("Max Damage", "dmg-max", 999)
.setTooltip('The maximum damage that needs to be dealt')
);
+ this.data.push(new StringListValue('Category', 'category', [ 'default' ] )
+ .setTooltip('The type of skill damage to apply for. Leave this empty to apply to all skill damage.')
+ );
}
extend('TriggerTookPhysicalDamage', 'Component');
function TriggerTookPhysicalDamage()
{
this.super('Took Physical Damage', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player takes physical (or non-skill) damage. This includes melee attacks and projectiles not fired by a skill.';
-
+
this.data.push(new ListValue('Target Caster', 'target', [ 'True', 'False' ], 'True')
.setTooltip('True makes children target the caster. False makes children target the attacking entity')
- );
+ );
this.data.push(new ListValue('Type', 'type', [ 'Both', 'Melee', 'Projectile' ], 'Both')
.setTooltip('The type of damage dealt')
);
@@ -690,18 +746,21 @@ extend('TriggerTookSkillDamage', 'Component');
function TriggerTookSkillDamage()
{
this.super('Took Skill Damage', Type.TRIGGER, true);
-
+
this.description = 'Applies skill effects when a player takes damage from a skill other than their own.';
-
+
this.data.push(new ListValue('Target Caster', 'target', [ 'True', 'False' ], 'True')
.setTooltip('True makes children target the caster. False makes children target the attacking entity')
- );
+ );
this.data.push(new DoubleValue("Min Damage", "dmg-min", 0)
.setTooltip('The minimum damage that needs to be dealt')
);
this.data.push(new DoubleValue("Max Damage", "dmg-max", 999)
.setTooltip('The maximum damage that needs to be dealt')
);
+ this.data.push(new StringListValue('Category', 'category', [ 'default' ] )
+ .setTooltip('The type of skill damage to apply for. Leave this empty to apply to all skill damage.')
+ );
}
// -- Target constructors ------------------------------------------------------ //
@@ -710,9 +769,9 @@ extend('TargetArea', 'Component');
function TargetArea()
{
this.super('Area', Type.TARGET, true);
-
+
this.description = 'Targets all units in a radius from the current target (the casting player is the default target).';
-
+
this.data.push(new AttributeValue("Radius", "radius", 3, 0)
.setTooltip('The radius of the area to target in blocks')
);
@@ -734,9 +793,9 @@ extend('TargetCone', 'Component');
function TargetCone()
{
this.super('Cone', Type.TARGET, true);
-
+
this.description = 'Targets all units in a line in front of the current target (the casting player is the default target). If you include the caster, that counts towards the max amount.';
-
+
this.data.push(new AttributeValue("Range", "range", 5, 0)
.setTooltip('The max distance away any target can be in blocks')
);
@@ -761,9 +820,9 @@ extend('TargetLinear', 'Component');
function TargetLinear()
{
this.super('Linear', Type.TARGET, true);
-
+
this.description = 'Targets all units in a line in front of the current target (the casting player is the default target).';
-
+
this.data.push(new AttributeValue("Range", "range", 5, 0)
.setTooltip('The max distance away any target can be in blocks')
);
@@ -788,21 +847,24 @@ extend('TargetLocation', 'Component');
function TargetLocation()
{
this.super('Location', Type.TARGET, true);
-
+
this.description = 'Targets the reticle location of the target or caster. Combine this with another targeting type for ranged area effects.';
-
+
this.data.push(new AttributeValue('Range', 'range', 5, 0)
.setTooltip('The max distance the location can be')
);
+ this.data.push(new ListValue('Ground Only', 'ground', [ 'True', 'False' ], 'True')
+ .setTooltip('Whether or not a player is only allowed to target the ground or other units')
+ );
}
extend('TargetNearest', 'Component');
function TargetNearest()
{
this.super('Nearest', Type.TARGET, true);
-
+
this.description = 'Targets the closest unit(s) in a radius from the current target (the casting player is the default target). If you include the caster, that counts towards the max number.';
-
+
this.data.push(new AttributeValue("Radius", "radius", 3, 0)
.setTooltip('The radius of the area to target in blocks')
);
@@ -824,9 +886,9 @@ extend('TargetOffset', 'Component');
function TargetOffset()
{
this.super('Offset', Type.TARGET, true);
-
+
this.description = 'Targets a location that is the given offset away from each target.';
-
+
this.data.push(new AttributeValue('Forward', 'forward', 0, 0)
.setTooltip('The offset from the target in the direction they are facing. Negative numbers go backwards.')
);
@@ -842,9 +904,9 @@ extend('TargetRemember', 'Component');
function TargetRemember()
{
this.super('Remember', Type.TARGET, true);
-
+
this.description = 'Targets entities stored using the "Remember Targets" mechanic for the matching key. If it was never set, this will fail.';
-
+
this.data.push(new StringValue('Key', 'key', 'target')
.setTooltip('The unique key for the target group that should match that used by the "Remember Targets" skill')
);
@@ -854,7 +916,7 @@ extend('TargetSelf', 'Component');
function TargetSelf()
{
this.super('Self', Type.TARGET, true);
-
+
this.description = 'Returns the current target back to the caster.';
}
@@ -862,9 +924,9 @@ extend('TargetSingle', 'Component');
function TargetSingle()
{
this.super('Single', Type.TARGET, true);
-
+
this.description = 'Targets a single unit in front of the current target (the casting player is the default target).';
-
+
this.data.push(new AttributeValue("Range", "range", 5, 0)
.setTooltip('The max distance away any target can be in blocks')
);
@@ -886,21 +948,21 @@ function ConditionArmor()
{
this.super('Armor', Type.CONDITION, true);
this.description = "Applies child components when the target is wearing an armor item matching the given details.";
-
+
this.data.push(new ListValue('Armor', 'armor', [ 'Helmet', 'Chestplate', 'Leggings', 'Boots', 'Any' ], 'Any')
.setTooltip('The type of armor to check')
);
-
+
addItemOptions(this);
}
extend('ConditionAttribute', 'Component');
-function ConditionAttribute()
+function ConditionAttribute()
{
this.super('Attribute', Type.CONDITION, true);
-
+
this.description = 'Requires the target to have a given number of attributes';
-
+
this.data.push(new StringValue('Attribute', 'attribute', 'Vitality')
.setTooltip('The name of the attribute you are checking the value of')
);
@@ -916,9 +978,9 @@ extend('ConditionBiome', 'Component');
function ConditionBiome()
{
this.super('Biome', Type.CONDITION, true);
-
+
this.description = 'Applies child components when in a specified biome.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'In Biome', 'Not In Biome' ], 'In Biome')
.setTooltip('Whether or not the target should be in the biome. If checking for in the biome, they must be in any one of the checked biomes. If checking for the opposite, they must not be in any of the checked biomes.')
);
@@ -931,24 +993,39 @@ extend('ConditionBlock', 'Component');
function ConditionBlock()
{
this.super('Block', Type.CONDITION, true);
-
+
this.description = 'Applies child components if the target is currently standing on a block of the given type.';
-
+
this.data.push(new ListValue('Type', 'standing', [ 'On Block', 'Not On Block' ], 'On Block')
.setTooltip('Whether or not the target should be in the biome. If checking for in the biome, they must be in any one of the checked biomes. If checking for the opposite, they must not be in any of the checked biomes.')
);
this.data.push(new ListValue('Material', 'material', materialList, 'Dirt')
.setTooltip('The type of the block to require the targets to stand on')
- );
+ );
+}
+
+extend('ConditionCeiling', 'Component');
+function ConditionCeiling()
+{
+ this.super('Ceiling', Type.CONDITION, true);
+
+ this.description = 'Checks the height of the ceiling above each target';
+
+ this.data.push(new AttributeValue('Distance', 'distance', 5, 0)
+ .setTooltip('How high to check for the ceiling')
+ );
+ this.data.push(new ListValue('At least', 'at-least', [ 'True', 'False' ], 'True')
+ .setTooltip('When true, the ceiling must be at least the give number of blocks high. If false, the ceiling must be lower than the given number of blocks')
+ );
}
extend('ConditionChance', 'Component');
function ConditionChance()
{
this.super('Chance', Type.CONDITION, true);
-
+
this.description = 'Rolls a chance to apply child components.';
-
+
this.data.push(new AttributeValue('Chance', 'chance', 25, 0)
.setTooltip('The chance to execute children as a percentage. "25" would be 25%.')
);
@@ -958,9 +1035,9 @@ extend('ConditionClass', 'Component');
function ConditionClass()
{
this.super('Class', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target is the given class or optionally a profession of that class. For example, if you check for "Fighter" which professes into "Warrior", a "Warrior" will pass the check if you do not enable "exact".';
-
+
this.data.push(new StringValue('Class', 'class', 'Fighter')
.setTooltip('The class the player should be')
);
@@ -973,9 +1050,9 @@ extend('ConditionClassLevel', 'Component');
function ConditionClassLevel()
{
this.super('Class Level', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the level of the class with this skill is within the range. This only checks the level of the caster, not the targets.';
-
+
this.data.push(new IntValue('Min Level', 'min-level', 2)
.setTooltip('The minimum class level the player should be. If the player has multiple classes, this will be of their main class')
);
@@ -988,9 +1065,9 @@ extend('ConditionCombat', 'Component');
function ConditionCombat()
{
this.super('Combat', Type.CONDITION, true);
-
+
this.description = 'Applies child components to targets that are in/out of combat, depending on the settings.';
-
+
this.data.push(new ListValue('In Combat', 'combat', [ 'True', 'False' ], 'True')
.setTooltip('Whether or not the target should be in or out of combat')
);
@@ -1003,9 +1080,9 @@ extend('ConditionCrouch', 'Component');
function ConditionCrouch()
{
this.super('Crouch', Type.CONDITION, true);
-
+
this.description = 'Applies child components if the target player(s) are crouching';
-
+
this.data.push(new ListValue('Crouching', 'crouch', [ 'True', 'False' ], 'True')
.setTooltip('Whether or not the player should be crouching')
);
@@ -1015,9 +1092,9 @@ extend('ConditionDirection', 'Component');
function ConditionDirection()
{
this.super('Direction', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target or caster is facing the correct direction relative to the other.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Target', 'Caster' ], 'Target')
.setTooltip('The entity to check the direction of')
);
@@ -1030,9 +1107,9 @@ extend('ConditionElevation', 'Component');
function ConditionElevation()
{
this.super('Elevation', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the elevation of the target matches the settings.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Normal', 'Difference' ], 'Normal')
.setTooltip('The type of comparison to make. Normal is just their Y-coordinate. Difference would be the difference between that the caster\'s Y-coordinate')
);
@@ -1048,7 +1125,7 @@ extend('ConditionElse', 'Component');
function ConditionElse()
{
this.super('Else', Type.CONDITION, true);
-
+
this.description = 'Applies child elements if the previous component failed to execute. This not only applies for conditions not passing, but mechanics failing due to no target or other cases.';
}
@@ -1056,9 +1133,9 @@ extend('ConditionEntityType', 'Component');
function ConditionEntityType()
{
this.super('Entity Type', Type.CONDITION, true);
-
+
this.description = 'Applies child elements if the target matches one of the selected entity types'
-
+
this.data.push(new MultiListValue('Types', 'types', [ 'BAT', 'BLAZE', 'CAVE_SPIDER', 'CHICKEN', 'COW', 'CREEPER', 'DONKEY', 'ELDER_GUARDIAN', 'ENDER_DRAGON', 'ENDERMAN', 'ENDERMITE', 'EVOKER', 'GHAST', 'GIANT', 'GUARDIAN', 'HORSE', 'HUSK', 'IRON_GOLEM', 'LLAMA', 'MAGMA_CUBE', 'MULE', 'MUSHROOM_COW', 'OCELOT', 'PIG', 'PIG_ZOMBIE', 'PLAYER', 'POLAR_BEAR', 'RABBIT', 'SHEEP', 'SHULKER', 'SILVERFISH', 'SKELETON', 'SKELETON_HORSE', 'SLIME', 'SNOWMAN', 'SPIDER', 'SQUID', 'VEX', 'VILLAGER', 'VINDICATOR', 'WITCH', 'WITHER', 'WITHER_SKELETON', 'WOLF', 'ZOMBIE', 'ZOMBIE_HORSE', 'ZOMBIE_VILLAGER' ])
.setTooltip('The entity types to target')
);
@@ -1068,9 +1145,9 @@ extend('ConditionFire', 'Component');
function ConditionFire()
{
this.super('Fire', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target is on fire.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'On Fire', 'Not On Fire' ], 'On Fire')
.setTooltip('Whether or not the target should be on fire')
);
@@ -1080,9 +1157,9 @@ extend('ConditionFlag', 'Component');
function ConditionFlag()
{
this.super('Flag', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target is marked by the appropriate flag.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Set', 'Not Set' ], 'Set')
.setTooltip('Whether or not the flag should be set')
);
@@ -1091,13 +1168,25 @@ function ConditionFlag()
);
}
+extend('ConditionGround', 'Component');
+function ConditionGround()
+{
+ this.super('Ground', Type.CONDITION, true);
+
+ this.description = 'Applies child components when the target is on the ground';
+
+ this.data.push(new ListValue('Type', 'type', [ 'On Ground', 'Not On Ground' ], 'On Ground')
+ .setTooltip('Whether or not the target should be on the ground')
+ );
+}
+
extend('ConditionHealth', 'Component');
function ConditionHealth()
{
this.super('Health', Type.CONDITION, true);
this.description = "Applies child components when the target's health matches the settings.";
-
+
this.data.push(new ListValue('Type', 'type', [ 'Health', 'Percent', 'Difference', 'Difference Percent' ], 'Health')
.setTooltip('The type of measurement to use for the health. Health is their flat health left. Percent is the percentage of health they have left. Difference is the difference between the target\'s flat health and the caster\'s. Difference percent is the difference between the target\'s percentage health left and the caster\s')
);
@@ -1114,7 +1203,7 @@ function ConditionItem()
{
this.super('Item', Type.CONDITION, true);
this.description = "Applies child components when the target is wielding an item matching the given material.";
-
+
addItemOptions(this);
}
@@ -1122,13 +1211,13 @@ extend('ConditionInventory', 'Component');
function ConditionInventory()
{
this.super('Inventory', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target player contains the given item in their inventory. This does not work on mobs.';
-
+
this.data.push(new AttributeValue('Amount', 'amount', 1, 0)
.setTooltip('The amount of the item needed in the player\'s inventory')
);
-
+
addItemOptions(this);
}
@@ -1136,9 +1225,9 @@ extend('ConditionLight', 'Component');
function ConditionLight()
{
this.super('Light', Type.CONDITION, true);
-
+
this.description = "Applies child components when the light level at the target's location matches the settings.";
-
+
this.data.push(new AttributeValue('Min Light', 'min-light', 0, 0)
.setTooltip('The minimum light level needed. 16 is full brightness while 0 is complete darkness')
);
@@ -1153,7 +1242,7 @@ function ConditionMana()
this.super('Mana', Type.CONDITION, true);
this.description = "Applies child components when the target's mana matches the settings.";
-
+
this.data.push(new ListValue('Type', 'type', [ 'Mana', 'Percent', 'Difference', 'Difference Percent' ], 'Mana')
.setTooltip('The type of measurement to use for the mana. Mana is their flat mana left. Percent is the percentage of mana they have left. Difference is the difference between the target\'s flat mana and the caster\'s. Difference percent is the difference between the target\'s percentage mana left and the caster\s')
);
@@ -1169,9 +1258,9 @@ extend('ConditionName', 'Component');
function ConditionName()
{
this.super('Name', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target has a name matching the settings.';
-
+
this.data.push(new ListValue('Contains Text', 'contains', [ 'True', 'False' ], 'True')
.setTooltip('Whether or not the target should have a name containing the text')
);
@@ -1188,7 +1277,7 @@ function ConditionOffhand()
{
this.super('Offhand', Type.CONDITION, true);
this.description = "Applies child components when the target is wielding an item matching the given material as an offhand item. This is for v1.9+ servers only.";
-
+
addItemOptions(this);
}
@@ -1196,9 +1285,9 @@ extend('ConditionPermission', 'Component');
function ConditionPermission()
{
this.super('Permission', Type.CONDITION, true);
-
+
this.description = 'Applies child components if the caster has the required permission';
-
+
this.data.push(new StringValue('Permission', 'perm', 'some.permission')
.setTooltip('The permission the player needs to have')
);
@@ -1208,9 +1297,9 @@ extend('ConditionPotion', 'Component');
function ConditionPotion()
{
this.super('Potion', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target has the potion effect.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Active', 'Not Active' ], 'Active')
.setTooltip('Whether or not the potion should be active')
);
@@ -1229,9 +1318,9 @@ extend('ConditionSkillLevel', 'Component');
function ConditionSkillLevel(skill)
{
this.super('Skill Level', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the skill level is with the range. This checks the skill level of the caster, not the targets.';
-
+
this.data.push(new StringValue('Skill', 'skill', skill)
.setTooltip('The name of the skill to check the level of. If you want to check the current skill, enter the current skill\'s name anyway')
);
@@ -1248,11 +1337,11 @@ function ConditionSlot()
{
this.super('Slot', Type.CONDITION, true);
this.description = "Applies child components when the target player has a matching item in the given slot.";
-
+
this.data.push(new StringListValue('Slots (one per line)', 'slot', [9])
.setTooltip('The slots to look at. Slots 0-8 are the hot bar, 9-35 are the main inventory, 36-39 are armor, and 40 is the offhand slot. Multiple slots will check if any of the slots match.')
);
-
+
addItemOptions(this);
}
@@ -1260,13 +1349,13 @@ extend('ConditionStatus', 'Component');
function ConditionStatus()
{
this.super('Status', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target has the status condition.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Active', 'Not Active' ], 'Active')
.setTooltip('Whether or not the status should be active')
);
- this.data.push(new ListValue('Status', 'status', [ 'Any', 'Curse', 'Disarm', 'Root', 'Silence', 'Stun' ], 'Any')
+ this.data.push(new ListValue('Status', 'status', [ 'Any', 'Absorb', 'Curse', 'Disarm', 'Invincible', 'Root', 'Silence', 'Stun' ], 'Any')
.setTooltip('The status to look for')
);
}
@@ -1275,9 +1364,9 @@ extend('ConditionTime', 'Component');
function ConditionTime()
{
this.super('Time', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the server time matches the settings.';
-
+
this.data.push(new ListValue('Time', 'time', [ 'Day', 'Night' ], 'Day')
.setTooltip('The time to check for in the current world')
);
@@ -1287,9 +1376,9 @@ extend('ConditionTool', 'Component');
function ConditionTool()
{
this.super('Tool', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target is wielding a matching tool.';
-
+
this.data.push(new ListValue('Material', 'material', [ 'Any', 'Wood', 'Stone', 'Iron', 'Gold', 'Diamond' ], 'Any')
.setTooltip('The material the held tool needs to be made out of')
);
@@ -1302,9 +1391,9 @@ extend('ConditionValue', 'Component');
function ConditionValue()
{
this.super('Value', Type.CONDITION, true);
-
+
this.description = 'Applies child components if a stored value is within the given range.';
-
+
this.data.push(new StringValue('Key', 'key', 'value')
.setTooltip('The unique string used for the value set by the Value mechanics.')
);
@@ -1320,23 +1409,35 @@ extend('ConditionWater', 'Component');
function ConditionWater()
{
this.super('Water', Type.CONDITION, true);
-
+
this.description = 'Applies child components when the target is in or out of water, depending on the settings.';
-
+
this.data.push(new ListValue('State', 'state', [ 'In Water', 'Out Of Water' ], 'In Water')
.setTooltip('Whether or not the target needs to be in the water')
);
}
+extend('ConditionWeather', 'Component');
+function ConditionWeather()
+{
+ this.super('Weather', Type.CONDITION, true);
+
+ this.description = 'Applies child components when the target\'s location has the given weather condition';
+
+ this.data.push(new ListValue('Type', 'type', [ 'None', 'Rain', 'Snow', 'Thunder' ], 'Rain')
+ .setTooltip('Whether or not the target needs to be in the water')
+ );
+}
+
// -- Mechanic constructors ---------------------------------------------------- //
extend('MechanicAttribute', 'Component');
function MechanicAttribute()
{
this.super('Attribute', Type.MECHANIC, false);
-
+
this.description = 'Gives a player bonus attributes temporarily.';
-
+
this.data.push(new StringValue('Attribute', 'key', 'Intelligence')
.setTooltip('The name of the attribute to add to')
);
@@ -1346,15 +1447,18 @@ function MechanicAttribute()
this.data.push(new AttributeValue('Seconds', 'seconds', 3, 0)
.setTooltip('How long in seconds to give the attributes to the player')
);
+ this.data.push(new ListValue('Stackable', 'stackable', [ 'True', 'False' ], 'False')
+ .setTooltip('[PREM] Whether or not applying multiple times stacks the effects')
+ );
}
extend('MechanicBlock', 'Component');
-function MechanicBlock()
+function MechanicBlock()
{
this.super('Block', Type.MECHANIC, false);
-
+
this.description = 'Changes blocks to the given type of block for a limited duration.';
-
+
this.data.push(new ListValue('Shape', 'shape', [ 'Sphere', 'Cuboid' ], 'Sphere' )
.setTooltip('The shape of the region to change the blocks for')
);
@@ -1379,12 +1483,12 @@ function MechanicBlock()
this.data.push(new AttributeValue('Right Offset', 'right', 0, 0)
.setTooltip('How far to the right the region should be of the target. A negative value will put it to the left.')
);
-
+
// Sphere options
this.data.push(new AttributeValue('Radius', 'radius', 3, 0).requireValue('shape', [ 'Sphere' ])
.setTooltip('The radius of the sphere region in blocks')
);
-
+
// Cuboid options
this.data.push(new AttributeValue('Width (X)', 'width', 5, 0).requireValue('shape', [ 'Cuboid' ])
.setTooltip('The width of the cuboid in blocks')
@@ -1397,11 +1501,41 @@ function MechanicBlock()
);
}
+extend('MechanicBuff', 'Component');
+function MechanicBuff()
+{
+ this.super('Buff', Type.MECHANIC, false);
+
+ this.description = 'Buffs combat stats of the target';
+
+ this.data.push(new ListValue('Immediate', 'immediate', [ 'True', 'False' ], 'False')
+ .setTooltip('Whether or not to apply the buff to the current damage trigger.')
+ );
+ this.data.push(new ListValue('Type', 'type', [ 'DAMAGE', 'DEFENSE', 'SKILL_DAMAGE', 'SKILL_DEFENSE', 'HEALING' ], 'DAMAGE')
+ .requireValue('immediate', [ 'False' ])
+ .setTooltip('What type of buff to apply. DAMAGE/DEFENSE is for regular attacks, SKILL_DAMAGE/SKILL_DEFENSE are for damage from abilities, and HEALING is for healing from abilities')
+ );
+ this.data.push(new ListValue('Modifier', 'modifier', [ 'Flat', 'Multiplier' ], 'Flat')
+ .setTooltip('The sort of scaling for the buff. Flat will increase/reduce incoming damage by a fixed amount where Multiplier does it by a percentage of the damage. Multipliers above 1 will increase damage taken while multipliers below 1 reduce damage taken.')
+ );
+ this.data.push(new StringValue('Category', 'category', '')
+ .requireValue('type', [ 'SKILL_DAMAGE', 'SKILL_DEFENSE' ])
+ .setTooltip('What kind of skill damage to affect. If left empty, this will affect all skill damage.')
+ );
+ this.data.push(new AttributeValue('Value', 'value', 1, 0)
+ .setTooltip('The amount to increase/decrease incoming damage by')
+ );
+ this.data.push(new AttributeValue('Seconds', 'seconds', 3, 0)
+ .requireValue('immediate', [ 'False' ])
+ .setTooltip('The duration of the buff in seconds')
+ );
+}
+
extend('MechanicCancel', 'Component');
function MechanicCancel()
{
this.super('Cancel', Type.MECHANIC, false);
-
+
this.description = 'Cancels the event that caused the trigger this is under to go off. For example, damage based triggers will stop the damage that was dealt while the Launch trigger would stop the projectile from firing.';
}
@@ -1409,9 +1543,9 @@ extend('MechanicCancelEffect', 'Component');
function MechanicCancelEffect()
{
this.super('Cancel Effect', Type.MECHANIC, false);
-
+
this.description = 'Stops a particle effect prematurely.';
-
+
this.data.push(new StringValue('Effect Key', 'effect-key', 'default')
.setTooltip('The key used when setting up the effect')
);
@@ -1421,9 +1555,9 @@ extend('MechanicChannel', 'Component');
function MechanicChannel()
{
this.super('Channel', Type.MECHANIC, true);
-
+
this.description = 'Applies child effects after a duration which can be interrupted. During the channel, the player cannot move, attack, or use other spells.';
-
+
this.data.push(new ListValue('Still', 'still', [ 'True', 'False' ], 'True')
.setTooltip('Whether or not to hold the player in place while channeling')
);
@@ -1436,9 +1570,9 @@ extend('MechanicCleanse', 'Component');
function MechanicCleanse()
{
this.super('Cleanse', Type.MECHANIC, false);
-
+
this.description = 'Cleanses negative potion or status effects from the targets.';
-
+
this.data.push(new ListValue('Potion', 'potion', [ 'None', 'All', 'Blindness', 'Confusion', 'Hunger', 'Levitation', 'Poison', 'Slow', 'Slow Digging', 'Weakness', 'Wither' ], 'All')
.setTooltip('The type of potion effect to remove from the target')
);
@@ -1451,9 +1585,9 @@ extend('MechanicCommand', 'Component');
function MechanicCommand()
{
this.super('Command', Type.MECHANIC, false);
-
+
this.description ='Executes a command for each of the targets either from them directly by oping them or via the console using their name.';
-
+
this.data.push(new StringValue('Command', 'command', '')
.setTooltip('The command to execute')
);
@@ -1466,9 +1600,9 @@ extend('MechanicCooldown', 'Component');
function MechanicCooldown()
{
this.super('Cooldown', Type.MECHANIC, false);
-
+
this.description = "Lowers the cooldowns of the target's skill(s). If you provide a negative amount, it will increase the cooldown.";
-
+
this.data.push(new StringValue('Skill (or "all")', 'skill', 'all')
.setTooltip('The skill to modify the cooldown for')
);
@@ -1484,9 +1618,9 @@ extend('MechanicDamage', 'Component');
function MechanicDamage()
{
this.super('Damage', Type.MECHANIC, false);
-
+
this.description = 'Inflicts skill damage to each target. Multiplier type would be a percentage of the target health.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Damage', 'Multiplier', 'Percent Left', 'Percent Missing' ], 'Damage')
.setTooltip('The unit to use for the amount of damage. Damage will deal flat damage, Multiplier will deal a percentage of the target\'s max health, Percent Left will deal a percentage of their current health, and Percent Missing will deal a percentage of the difference between their max health and current health')
);
@@ -1496,15 +1630,18 @@ function MechanicDamage()
this.data.push(new ListValue('True Damage', 'true', [ 'True', 'False' ], 'False')
.setTooltip('Whether or not to deal true damage. True damage ignores armor and all plugin checks.')
);
+ this.data.push(new StringValue('Classifier', 'classifier', 'default')
+ .setTooltip('[PREMIUM ONLY] The type of damage to deal. Can act as elemental damage or fake physical damage')
+ );
}
extend('MechanicDamageBuff', 'Component');
function MechanicDamageBuff()
{
this.super('Damage Buff', Type.MECHANIC, false);
-
+
this.description = 'Modifies the physical damage dealt by each target by a multiplier or a flat amount for a limited duration. Negative flat amounts or multipliers less than one will reduce damage dealt while the opposite will increase damage dealt. (e.g. a 5% damage buff would be a multiplier or 1.05)';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Flat', 'Multiplier' ], 'Flat')
.setTooltip('The type of buff to apply. Flat increases damage by a fixed amount while multiplier increases it by a percentage.')
);
@@ -1523,9 +1660,9 @@ extend('MechanicDamageLore', 'Component');
function MechanicDamageLore()
{
this.super('Damage Lore', Type.MECHANIC, false);
-
+
this.description = 'Damages each target based on a value found in the lore of the item held by the caster.';
-
+
this.data.push(new ListValue("Hand", "hand", [ 'Main', 'Offhand' ], 'Main')
.setTooltip('The hand to check for the item. Offhand items are MC 1.9+ only.')
);
@@ -1538,15 +1675,18 @@ function MechanicDamageLore()
this.data.push(new ListValue('True Damage', 'true', [ 'True', 'False' ], 'False')
.setTooltip('Whether or not to deal true damage. True damage ignores armor and all plugin checks.')
);
+ this.data.push(new StringValue('Classifier', 'classifier', 'default')
+ .setTooltip('[PREMIUM ONLY] The type of damage to deal. Can act as elemental damage or fake physical damage')
+ );
}
extend('MechanicDefenseBuff', 'Component');
function MechanicDefenseBuff()
{
this.super('Defense Buff', Type.MECHANIC, false);
-
+
this.description = 'Modifies the physical damage taken by each target by a multiplier or a flat amount for a limited duration. Negative flag amounts or multipliers less than one will reduce damage taken while the opposite will increase damage taken. (e.g. a 5% defense buff would be a multiplier or 0.95, since you would be taking 95% damage)';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Flat', 'Multiplier' ], 'Flat')
.setTooltip('The type of buff to apply. Flat will increase/reduce incoming damage by a fixed amount where Multiplier does it by a percentage of the damage. Multipliers above 1 will increase damage taken while multipliers below 1 reduce damage taken.')
);
@@ -1565,9 +1705,9 @@ extend('MechanicDelay', 'Component');
function MechanicDelay()
{
this.super('Delay', Type.MECHANIC, true);
-
+
this.description = 'Applies child components after a delay.';
-
+
this.data.push(new AttributeValue('Delay', 'delay', 2, 0)
.setTooltip('The amount of time to wait before applying child components in seconds')
);
@@ -1577,16 +1717,16 @@ extend('MechanicDisguise', 'Component');
function MechanicDisguise()
{
this.super('Disguise', Type.MECHANIC, false);
-
+
this.description = 'Disguises each target according to the settings. This mechanic requires the LibsDisguise plugin to be installed on your server.';
-
+
this.data.push(new AttributeValue('Duration', 'duration', -1, 0)
.setTooltip('How long to apply the disguise for in seconds. Use a negative number to permanently disguise the targets.')
);
this.data.push(new ListValue('Type', 'type', [ 'Mob', 'Player', 'Misc' ], 'Mob')
.setTooltip('The type of disguise to use, as defined by the LibsDisguise plugin.')
);
-
+
this.data.push(new ListValue('Mob', 'mob', [ 'Bat', 'Blaze', 'Cave Spider', 'Chicken', 'Cow', 'Creeper', 'Donkey', 'Elder Guardian', 'Ender Dragon', 'Enderman', 'Endermite', 'Ghast', 'Giant', 'Guardian', 'Horse', 'Iron Golem', 'Magma Cube', 'Mule', 'Mushroom Cow', 'Ocelot', 'Pig', 'Pig Zombie', 'Rabbit', 'Sheep', 'Shulker', 'Silverfish', 'Skeleton', 'Slime', 'Snowman', 'Spider', 'Squid', 'Undead Horse', 'Villager', 'Witch', 'Wither', 'Wither Skeleton', 'Wolf', 'Zombie', 'Zombie Villager'], 'Zombie')
.requireValue('type', [ 'Mob' ])
.setTooltip('The type of mob to disguise the target as')
@@ -1595,12 +1735,12 @@ function MechanicDisguise()
.requireValue('type', [ 'Mob' ])
.setTooltip('Whether or not to use the adult variant of the mob')
);
-
+
this.data.push(new StringValue('Player', 'player', 'Eniripsa96')
.requireValue('type', [ 'Player' ])
.setTooltip('The player to disguise the target as')
);
-
+
this.data.push(new ListValue('Misc', 'misc', [ 'Area Effect Cloud', 'Armor Stand', 'Arrow', 'Boat', 'Dragon Fireball', 'Dropped Item', 'Egg', 'Ender Crystal', 'Ender Pearl', 'Ender Signal', 'Experience Orb', 'Falling Block', 'Fireball', 'Firework', 'Fishing Hook', 'Item Frame', 'Leash Hitch', 'Minecart', 'Minecart Chest', 'Minecart Command', 'Minecart Furnace', 'Minecart Hopper', 'Minecart Mob Spawner', 'Minecart TNT', 'Painting', 'Primed TNT', 'Shulker Bullet', 'Snowball', 'Spectral Arrow', 'Splash Potion', 'Tipped Arrow', 'Thrown EXP Bottle', 'Wither Skull' ], 'Painting')
.requireValue('type', [ 'Misc' ])
.setTooltip('The object to disguise the target as')
@@ -1611,13 +1751,28 @@ function MechanicDisguise()
);
}
+extend('MechanicDurability', 'Component');
+function MechanicDurability()
+{
+ this.super('Durability', Type.MECHANIC, false);
+
+ this.description = 'Lowers the durability of a held item';
+
+ this.data.push(new AttributeValue('Amount', 'amount', 1, 0)
+ .setTooltip('Amount to reduce the item\'s durability by')
+ );
+ this.data.push(new ListValue('Offhand', 'offhand', [ 'True', 'False' ], 'False')
+ .setTooltip('Whether or not to apply to the offhand slot')
+ );
+}
+
extend('MechanicExplosion', 'Component');
function MechanicExplosion()
{
this.super('Explosion', Type.MECHANIC, false);
-
+
this.description = 'Causes an explosion at the current target\'s position';
-
+
this.data.push(new AttributeValue('Power', 'power', 3, 0)
.setTooltip('The strength of the explosion')
);
@@ -1633,9 +1788,9 @@ extend('MechanicFire', 'Component');
function MechanicFire()
{
this.super('Fire', Type.MECHANIC, false);
-
+
this.description = 'Sets the target on fire for a duration.';
-
+
this.data.push(new AttributeValue('Seconds', 'seconds', 3, 1)
.setTooltip('The duration of the fire in seconds')
);
@@ -1645,24 +1800,24 @@ extend('MechanicFlag', 'Component');
function MechanicFlag()
{
this.super('Flag', Type.MECHANIC, false);
-
+
this.description = 'Marks the target with a flag for a duration. Flags can be checked by other triggers, spells or the related for interesting synergies and effects.';
-
+
this.data.push(new StringValue('Key', 'key', 'key')
.setTooltip('The unique string for the flag. Use the same key when checking it in a Flag Condition.')
);
this.data.push(new AttributeValue('Seconds', 'seconds', 3, 1)
.setTooltip('The duration the flag should be set for. To set one indefinitely, use Flag Toggle.')
- );
+ );
}
extend('MechanicFlagClear', 'Component');
function MechanicFlagClear()
{
this.super('Flag Clear', Type.MECHANIC, false);
-
+
this.description = 'Clears a flag from the target.';
-
+
this.data.push(new StringValue('Key', 'key', 'key')
.setTooltip('The unique string for the flag. This should match that of the mechanic that set the flag to begin with.')
);
@@ -1672,21 +1827,48 @@ extend('MechanicFlagToggle', 'Component');
function MechanicFlagToggle()
{
this.super('Flag Toggle', Type.MECHANIC, false);
-
+
this.description = 'Toggles a flag on or off for the target. This can be used to make toggle effects.';
-
+
this.data.push(new StringValue('Key', 'key', 'key')
.setTooltip('The unique string for the flag. Use the same key when checking it in a Flag Condition')
);
}
+extend('MechanicFood', 'Component');
+function MechanicFood()
+{
+ this.super('Food', Type.MECHANIC, false);
+
+ this.description = 'Adds or removes to a player\'s hunger and saturation';
+
+ this.data.push(new AttributeValue('Food', 'food', 1, 1)
+ .setTooltip('The amount of food to give. Use a negative number to lower the food meter.')
+ );
+ this.data.push(new AttributeValue('Saturation', 'saturation', 0, 0)
+ .setTooltip('How much saturation to give. Use a negative number to lower saturation. This is the hidden value that determines how long until food starts going down.')
+ );
+}
+
+extend('MechanicForgetTargets', 'Component');
+function MechanicForgetTargets()
+{
+ this.super('Forget Targets', Type.MECHANIC, false);
+
+ this.description = 'Clears targets stored by the "Remember Targets" mechanic';
+
+ this.data.push(new StringValue('Key', 'key', 'key')
+ .setTooltip('The unique key the targets were stored under')
+ );
+}
+
extend('MechanicHeal', 'Component');
function MechanicHeal()
{
this.super('Heal', Type.MECHANIC, false);
-
+
this.description = 'Restores health to each target.';
-
+
this.data.push(new ListValue("Type", "type", [ "Health", "Percent" ], "Health")
.setTooltip('The unit to use for the amount of health to restore. Health restores a flat amount while Percent restores a percentage of their max health.')
);
@@ -1695,13 +1877,25 @@ function MechanicHeal()
);
}
+extend('MechanicHealthSet', 'Component');
+function MechanicHealthSet()
+{
+ this.super('Health Set', Type.MECHANIC, false);
+
+ this.description = 'Sets the target\'s health to the specified amount, ignoring resistances, damage buffs, and so on';
+
+ this.data.push(new AttributeValue("Health", "health", 1, 0)
+ .setTooltip('The health to set to')
+ );
+}
+
extend('MechanicHeldItem', 'Component');
function MechanicHeldItem()
{
this.super('Held Item', Type.MECHANIC, false);
-
+
this.description = 'Sets the held item slot of the target player. This will do nothing if trying to set it to a skill slot.';
-
+
this.data.push(new AttributeValue("Slot", "slot", 0, 0)
.setTooltip('The slot to set it to')
);
@@ -1711,9 +1905,9 @@ extend('MechanicImmunity', 'Component');
function MechanicImmunity()
{
this.super('Immunity', Type.MECHANIC, false);
-
+
this.description = 'Provides damage immunity from one source for a duration.'
-
+
this.data.push(new ListValue('Type', 'type', DAMAGE_TYPES, 'Poison')
.setTooltip('The damage type to give an immunity for')
);
@@ -1729,7 +1923,7 @@ extend('MechanicInterrupt', 'Component');
function MechanicInterrupt()
{
this.super('Interrupt', Type.MECHANIC, false);
-
+
this.description = 'Interrupts any channeling being done by each target if applicable.';
}
@@ -1737,9 +1931,9 @@ extend('MechanicItem', 'Component');
function MechanicItem()
{
this.super('Item', Type.MECHANIC, false);
-
+
this.description = 'Gives each player target the item defined by the settings.';
-
+
this.data.push(new ListValue('Material', 'material', materialList, 'Arrow')
.setTooltip('The type of item to give to the player')
);
@@ -1755,7 +1949,7 @@ function MechanicItem()
this.data.push(new ListValue('Custom', 'custom', [ 'True', 'False' ], 'False')
.setTooltip('Whether or not to apply a custom name/lore to the item')
);
-
+
this.data.push(new StringValue('Name', 'name', 'Name').requireValue('custom', [ 'True' ])
.setTooltip('The name of the item')
);
@@ -1768,17 +1962,17 @@ extend('MechanicItemProjectile', 'Component');
function MechanicItemProjectile()
{
this.super('Item Projectile', Type.MECHANIC, true);
-
+
this.description = 'Launches a projectile using an item as its visual that applies child components upon landing. The target passed on will be the collided target or the location where it landed if it missed.';
-
-
+
+
this.data.push(new ListValue('Item', 'item', materialList, 'Jack O Lantern')
.setTooltip('The item type to use as a projectile')
),
this.data.push(new IntValue('Item Data', 'item-data', 0)
.setTooltip('The durability value for the item to use as a projectile, most notably for dyes or colored items like wool')
),
-
+
addProjectileOptions(this);
addEffectOptions(this, true);
}
@@ -1787,13 +1981,13 @@ extend('MechanicItemRemove', 'Component');
function MechanicItemRemove()
{
this.super('Item Remove', Type.MECHANIC, false);
-
+
this.description = 'Removes an item from a player inventory. This does nothing to mobs.';
-
+
this.data.push(new AttributeValue('Amount', 'amount', 1, 0)
.setTooltip('The amount of the item needed in the player\'s inventory')
);
-
+
addItemOptions(this);
}
@@ -1801,9 +1995,12 @@ extend('MechanicLaunch', 'Component');
function MechanicLaunch()
{
this.super('Launch', Type.MECHANIC, false);
-
+
this.description = 'Launches the target relative to their forward direction. Use negative values to go in the opposite direction (e.g. negative forward makes the target go backwards)';
-
+
+ this.data.push(new ListValue('[PREM] Relative', 'relative', [ 'Target', 'Caster', 'Between'], 'Target')
+ .setTooltip('Determines what is considered "forward". Target uses the direction the target is facing, Caster uses the direction the caster is facing, and Between uses the direction from the caster to the target.')
+ );
this.data.push(new AttributeValue('Forward Speed', 'forward', 0, 0)
.setTooltip('The speed to give the target in the direction they are facing')
);
@@ -1819,9 +2016,12 @@ extend('MechanicLightning', 'Component');
function MechanicLightning()
{
this.super('Lightning', Type.MECHANIC, false);
-
+
this.description = 'Strikes lightning on or near the target. Negative offsets will offset it in the opposite direction (e.g. negative forward offset puts it behind the target).';
-
+
+ this.data.push(new ListValue('Damage', 'damage', ['True', 'False'], 'True')
+ .setTooltip('Whether or not the lightning should deal damage')
+ );
this.data.push(new AttributeValue('Forward Offset', 'forward', 0, 0)
.setTooltip('How far in front of the target in blocks to place the lightning')
);
@@ -1834,9 +2034,9 @@ extend('MechanicMana', 'Component');
function MechanicMana()
{
this.super('Mana', Type.MECHANIC, false);
-
+
this.description = 'Restores or deducts mana from the target.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Mana', 'Percent' ], 'Mana')
.setTooltip('The unit to use for the amount of mana to restore/drain. Mana does a flat amount while Percent does a percentage of their max mana')
);
@@ -1849,9 +2049,9 @@ extend('MechanicMessage', 'Component');
function MechanicMessage()
{
this.super('Message', Type.MECHANIC, false);
-
+
this.description = 'Sends a message to each player target. To include numbers from Value mechanics, use the filters {} where is the key the value is stored under.'
-
+
this.data.push(new StringValue('Message', 'message', 'text')
.setTooltip('The message to display')
);
@@ -1861,11 +2061,11 @@ extend('MechanicParticle', 'Component');
function MechanicParticle()
{
this.super('Particle', Type.MECHANIC, false);
-
+
this.description = 'Plays a particle effect about the target.';
-
+
addParticleOptions(this);
-
+
this.data.push(new DoubleValue('Forward Offset', 'forward', 0)
.setTooltip('How far forward in front of the target in blocks to play the particles. A negative value will go behind.')
);
@@ -1881,9 +2081,9 @@ extend('MechanicParticleAnimation', 'Component');
function MechanicParticleAnimation()
{
this.super('Particle Animation', Type.MECHANIC, false);
-
+
this.description = 'Plays an animated particle effect at the location of each target over time by applying various transformations.';
-
+
this.data.push(new IntValue('Steps', 'steps', 1, 0)
.setTooltip('The number of times to play particles and apply translations each application.')
);
@@ -1911,9 +2111,9 @@ function MechanicParticleAnimation()
this.data.push(new IntValue('V-Cycles', 'v-cycles', 1)
.setTooltip('How many times to move the animation position throughout the animation. Every other cycle moves it back to where it started. For example, two cycles would move it up and then back down.')
);
-
+
addParticleOptions(this);
-
+
this.data.push(new DoubleValue('Forward Offset', 'forward', 0)
.setTooltip('How far forward in front of the target in blocks to play the particles. A negative value will go behind.')
);
@@ -1929,9 +2129,9 @@ extend('MechanicParticleEffect', 'Component');
function MechanicParticleEffect()
{
this.super('Particle Effect', Type.MECHANIC, false);
-
+
this.description = 'Plays a particle effect that follows the current target, using formulas to determine shape, size, and motion';
-
+
addEffectOptions(this, false);
}
@@ -1939,19 +2139,27 @@ extend('MechanicParticleProjectile', 'Component');
function MechanicParticleProjectile()
{
this.super('Particle Projectile', Type.MECHANIC, true);
-
+
this.description = 'Launches a projectile using particles as its visual that applies child components upon landing. The target passed on will be the collided target or the location where it landed if it missed.';
-
+
addProjectileOptions(this);
+
+ this.data.push(new DoubleValue('Gravity', 'gravity', 0)
+ .setTooltip('How much gravity to apply each tick. Negative values make it fall while positive values make it rise')
+ );
+ this.data.push(new ListValue('Pierce', 'pierce', [ 'True', 'False' ], 'False')
+ .setTooltip('Whether or not this projectile should pierce through initial targets and continue hitting those behind them')
+ );
+
addParticleOptions(this);
-
+
this.data.push(new DoubleValue('Frequency', 'frequency', 0.05)
.setTooltip('How often to play a particle effect where the projectile is. It is recommended not to change this value unless there are too many particles playing')
);
this.data.push(new DoubleValue('Lifespan', 'lifespan', 3)
.setTooltip('How long in seconds before the projectile will expire in case it doesn\'t hit anything')
);
-
+
addEffectOptions(this, true);
}
@@ -1959,9 +2167,9 @@ extend('MechanicPassive', 'Component');
function MechanicPassive()
{
this.super('Passive', Type.MECHANIC, true);
-
+
this.description = 'Applies child components continuously every period. The seconds value below is the period or how often it applies.';
-
+
this.data.push(new AttributeValue('Seconds', 'seconds', 1, 0)
.setTooltip('The delay in seconds between each application')
);
@@ -1971,9 +2179,9 @@ extend('MechanicPermission', 'Component');
function MechanicPermission()
{
this.super('Permission', Type.MECHANIC, true);
-
+
this.description = 'Grants each player target a permission for a limited duration. This mechanic requires Vault with an accompanying permissions plugin in order to work.';
-
+
this.data.push(new StringValue('Permission', 'perm', 'plugin.perm.key')
.setTooltip('The permission to give to the player')
);
@@ -1986,9 +2194,9 @@ extend('MechanicPotion', 'Component');
function MechanicPotion()
{
this.super('Potion', Type.MECHANIC, false);
-
+
this.description = 'Applies a potion effect to the target for a duration.';
-
+
this.data.push(new ListValue('Potion', 'potion', [ 'Absorption', 'Blindness', 'Confusion', 'Damage Resistance', 'Fast Digging', 'Fire Resistance', 'Glowing', 'Health Boost', 'Hunger', 'Increase Damage', 'Invisibility', 'Jump', 'Levitation', 'Luck', 'Night Vision', 'Poison', 'Regeneration', 'Saturation', 'Slow', 'Slow Digging', 'Speed', 'Unluck', 'Water Breathing', 'Weakness', 'Wither' ], 'Absorption')
.setTooltip('The type of potion effect to apply')
);
@@ -2007,9 +2215,9 @@ extend('MechanicPotionProjectile', 'Component');
function MechanicPotionProjectile()
{
this.super('Potion Projectile', Type.MECHANIC, true);
-
+
this.description = 'Drops a splash potion from each target that does not apply potion effects by default. This will apply child elements when the potion lands. The targets supplied will be everything hit by the potion. If nothing is hit by the potion, the target will be the location it landed.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Fire Resistance', 'Instant Damage', 'Instant Heal', 'Invisibility', 'Night Vision', 'Poison', 'Regen', 'Slowness', 'Speed', 'Strength', 'Water', 'Water Breathing', 'Weakness' ], 'Fire Resistance')
.setTooltip('The type of the potion to use for the visuals')
);
@@ -2025,9 +2233,9 @@ extend('MechanicProjectile', 'Component');
function MechanicProjectile()
{
this.super('Projectile', Type.MECHANIC, true);
-
+
this.description = 'Launches a projectile that applies child components on hit. The target supplied will be the struck target.';
-
+
this.data.push(new ListValue('Projectile', 'projectile', [ 'Arrow', 'Egg', 'Ghast Fireball', 'Snowball' ], 'Arrow')
.setTooltip('The type of projectile to fire')
);
@@ -2037,18 +2245,18 @@ function MechanicProjectile()
this.data.push(new ListValue('Cost', 'cost', [ 'None', 'All', 'One' ], 'None')
.setTooltip('The cost of the skill of the fired item. All will cost the same number of items as the skill fired.')
);
-
+
addProjectileOptions(this);
addEffectOptions(this, true);
}
extend('MechanicPurge', 'Component');
-function MechanicPurge()
+function MechanicPurge()
{
this.super('Purge', Type.MECHANIC, false);
-
+
this.description = 'Purges the target of positive potion effects or statuses';
-
+
this.data.push(new ListValue('Potion', 'potion', [ 'None', 'All', 'Absorption', 'Damage Resistance', 'Fast Digging', 'Fire Resistance', 'Health Boost', 'Increase Damage', 'Invisibility', 'Jump', 'Night Vision', 'Regeneration', 'Saturation', 'Speed', 'Water Breathing' ], 'All')
.setTooltip('The potion effect to remove from the target, if any')
);
@@ -2061,24 +2269,27 @@ extend('MechanicPush', 'Component');
function MechanicPush()
{
this.super('Push', Type.MECHANIC, false);
-
+
this.description = 'Pushes the target relative to the caster. This will do nothing if used with the caster as the target. Positive numbers apply knockback while negative numbers pull them in.';
-
+
this.data.push(new ListValue('Type', 'type', [ 'Fixed', 'Inverse', 'Scaled' ], 'Fixed')
.setTooltip('How to scale the speed based on relative position. Fixed does the same speed to all targets. Inverse pushes enemies farther away faster. Scaled pushes enemies closer faster.')
);
this.data.push(new AttributeValue('Speed', 'speed', 3, 1)
.setTooltip('How fast to push the target away. Use a negative value to pull them closer.')
);
+ this.data.push(new StringValue('Source', 'source', 'none')
+ .setTooltip('The source to push/pull from. This should be a key used in a Remember Targets mechanic. If no targets are remembered, this will default to the caster.')
+ );
}
extend('MechanicRememberTargets', 'Component');
function MechanicRememberTargets()
{
this.super('Remember Targets', Type.MECHANIC, false);
-
+
this.description = 'Stores the current targets for later use under a specified key';
-
+
this.data.push(new StringValue('Key', 'key', 'target')
.setTooltip('The unique key to store the targets under. The "Remember" target will use this key to apply effects to the targets later on.')
);
@@ -2088,9 +2299,9 @@ extend('MechanicRepeat', 'Component');
function MechanicRepeat()
{
this.super('Repeat', Type.MECHANIC, true);
-
+
this.description = 'Applies child components multiple times. When it applies them is determined by the delay (seconds before the first application) and period (seconds between successive applications).';
-
+
this.data.push(new AttributeValue('Repetitions', 'repetitions', 3, 0)
.setTooltip('How many times to activate child components')
);
@@ -2100,26 +2311,29 @@ function MechanicRepeat()
this.data.push(new DoubleValue('Delay', 'delay', 0)
.setTooltip('The initial delay before starting to apply child components')
);
+ this.data.push(new ListValue('Stop on Fail', 'stop-on-fail', [ 'True', 'False' ], 'False')
+ .setTooltip('Whether or not to stop the repeat task early if the effects fail')
+ );
}
extend('MechanicSound', 'Component');
function MechanicSound()
{
this.super('Sound', Type.MECHANIC, false);
-
+
this.description = "Plays a sound at the target's location.";
-
+
this.data.push(new ListValue('Server Version', 'version', [ '1.9+', 'Pre 1.9' ], '1.9+')
.setTooltip('The version of the server this will be playing for. Servers 1.9 and later have much different sounds available')
);
-
+
this.data.push(new ListValue('Sound', 'newsound', SOUNDS_POST, 'Ambience Cave').requireValue('version', [ '1.9+' ])
.setTooltip('The sound clip to play')
);
this.data.push(new ListValue('Sound', 'sound', SOUNDS_PRE, 'Ambience Cave').requireValue('version', [ 'Pre 1.9' ])
.setTooltip('The sound clip to play')
);
-
+
this.data.push(new AttributeValue('Volume', 'volume', 100, 0)
.setTooltip('The volume of the sound as a percentage. Numbers above 100 will not get any louder, but will be heard from a farther distance')
);
@@ -2132,9 +2346,9 @@ extend('MechanicSpeed', 'Component');
function MechanicSpeed()
{
this.super('Speed', Type.MECHANIC, false);
-
+
this.description = 'Modifies the base speed of a player using a multiplier (stacks with potions)';
-
+
this.data.push(new AttributeValue('Multiplier', 'multiplier', 1.2, 0)
.setTooltip('The multiplier of the player\'s base speed to use')
);
@@ -2147,9 +2361,9 @@ extend('MechanicStatus', 'Component');
function MechanicStatus()
{
this.super('Status', Type.MECHANIC, false);
-
+
this.description = 'Applies a status effect to the target for a duration.';
-
+
this.data.push(new ListValue('Status', 'status', [ 'Absorb', 'Curse', 'Disarm', 'Invincible', 'Root', 'Silence', 'Stun' ], 'Stun')
.setTooltip('The status to apply')
);
@@ -2162,8 +2376,84 @@ extend('MechanicTaunt', 'Component');
function MechanicTaunt()
{
this.super('Taunt', Type.MECHANIC, false);
-
- this.description = 'Draws aggro of targeted creatures. This only works on newer server versions.';
+
+ this.description = 'Draws aggro of targeted creatures. Regular mobs are set to attack the caster. The Spigot/Bukkit API for this was not functional on older versions, so it may not work on older servers. For MythicMobs, this uses their aggro system using the amount chosen below.';
+
+ this.data.push(new AttributeValue('Amount', 'amount', 1, 0)
+ .setTooltip('The amount of aggro to apply if MythicMobs is active. Use negative amounts to reduce aggro')
+ );
+}
+
+extend('MechanicTrigger', 'Component');
+function MechanicTrigger()
+{
+ this.super('Trigger', Type.MECHANIC, true);
+
+ this.description = 'Listens for a trigger on the current targets for a duration.';
+
+ this.data.push(new ListValue('Trigger', 'trigger', [ 'Crouch', 'Death', 'Environment Damage', 'Kill', 'Land', 'Launch', 'Physical Damage', 'Skill Damage', 'Took Physical Damage', 'Took Skill Damage' ], 'Death')
+ .setTooltip('The trigger to listen for')
+ );
+ this.data.push(new AttributeValue('Duration', 'duration', 5, 0)
+ .setTooltip('How long to listen to the trigger for')
+ );
+ this.data.push(new ListValue('Stackable', 'stackable', [ 'True', 'False', ], 'True')
+ .setTooltip('Whether or not different players (or the same player) can listen to the same target at the same time')
+ );
+ this.data.push(new ListValue('Once', 'once', [ 'True', 'False' ], 'True')
+ .setTooltip('Whether or not the trigger should only be used once each cast. When false, the trigger can execute as many times as it happens for the duration.')
+ );
+
+ // CROUCH
+ this.data.push(new ListValue('Type', 'type', [ 'Start Crouching', 'Stop Crouching', 'Both' ], 'Start Crouching')
+ .requireValue('trigger', [ 'Crouch' ])
+ .setTooltip('Whether or not you want to apply components when crouching or not crouching')
+ );
+
+ // ENVIRONMENT_DAMAGE
+ this.data.push(new ListValue('Type', 'type', DAMAGE_TYPES, 'FALL')
+ .requireValue('trigger', [ 'Environment Damage' ])
+ .setTooltip('The source of damage to apply for')
+ );
+
+ // LAND
+ this.data.push(new DoubleValue('Min Distance', 'min-distance', 0)
+ .requireValue('trigger', [ 'Land' ])
+ .setTooltip('The minimum distance the player should fall before effects activating.')
+ );
+
+ // LAUNCH
+ this.data.push(new ListValue('Type', 'type', [ 'Any', 'Arrow', 'Egg', 'Ender Pearl', 'Fireball', 'Fishing Hook', 'Snowball' ], 'Any')
+ .requireValue('trigger', [ 'Launch' ])
+ .setTooltip('The type of projectile that should be launched.')
+ );
+
+ // PHYSICAL
+ this.data.push(new ListValue('Type', 'type', [ 'Both', 'Melee', 'Projectile' ], 'Both')
+ .requireValue('trigger', [ 'Physical Damage', 'Took Physical Damage' ])
+ .setTooltip('The type of damage dealt')
+ );
+
+ // SKILL
+ this.data.push(new StringValue('Category', 'category', '')
+ .requireValue('trigger', [ 'Skill Damage', 'Took Skill Damage' ])
+ .setTooltip('The type of skill damage to apply for. Leave this empty to apply to all skill damage.')
+ );
+
+ // DAMAGE
+ var damageTriggers = [ 'Physical Damage', 'Skill Damage', 'Took Physical Damage', 'Took Skill Damage' ];
+ this.data.push(new ListValue('Target Listen Target', 'target', [ 'True', 'False' ], 'True')
+ .requireValue('trigger', damageTriggers)
+ .setTooltip('True makes children target the target that has been listened to. False makes children target the entity fighting the target entity.')
+ );
+ this.data.push(new DoubleValue("Min Damage", "dmg-min", 0)
+ .requireValue('trigger', damageTriggers)
+ .setTooltip('The minimum damage that needs to be dealt')
+ );
+ this.data.push(new DoubleValue("Max Damage", "dmg-max", 999)
+ .requireValue('trigger', damageTriggers)
+ .setTooltip('The maximum damage that needs to be dealt')
+ );
}
extend('MechanicValueAdd', 'Component');
@@ -2196,6 +2486,36 @@ function MechanicValueAttribute()
);
}
+extend('MechanicValueCopy', 'Component');
+function MechanicValueCopy()
+{
+ this.super('Value Copy', Type.MECHANIC, false);
+
+ this.description = 'Copies a stored value from the caster to the target or vice versa';
+
+ this.data.push(new StringValue('Key', 'key', 'value')
+ .setTooltip('The unique key to store the value under. This key can be used in place of attribute values to use the stored value.')
+ );
+ this.data.push(new StringValue('Destination', 'destination', 'value')
+ .setTooltip('The key to copy the original value to')
+ );
+ this.data.push(new ListValue('To target', 'to-target', [ 'True', 'False' ], 'True')
+ .setTooltip('The amount to add to the value')
+ );
+}
+
+extend('MechanicValueDistance', 'Component');
+function MechanicValueDistance()
+{
+ this.super('Value Distance', Type.MECHANIC, false);
+
+ this.description = 'Stores the distance between the target and the caster into a value';
+
+ this.data.push(new StringValue('Key', 'key', 'attribute')
+ .setTooltip('The unique key to store the value under. This key can be used in place of attribute values to use the stored value.')
+ );
+}
+
extend('MechanicValueHealth', 'Component');
function MechanicValueHealth()
{
@@ -2206,6 +2526,9 @@ function MechanicValueHealth()
this.data.push(new StringValue('Key', 'key', 'value')
.setTooltip('The unique key to store the value under. This key can be used in place of attribute values to use the stored value.')
);
+ this.data.push(new ListValue('Type', 'type', [ 'Current', 'Max', 'Missing', 'Percent' ], 'Current')
+ .setTooltip('Current provides the health the target has, max provides their total health, missing provides how much health they have lost, and percent is the ratio of health to total health.')
+ );
}
extend('MechanicValueLocation', 'Component');
@@ -2272,15 +2595,18 @@ function MechanicValueMana()
this.data.push(new StringValue('Key', 'key', 'value')
.setTooltip('The unique key to store the value under. This key can be used in place of attribute values to use the stored value.')
);
+ this.data.push(new ListValue('Type', 'type', [ 'Current', 'Max', 'Missing', 'Percent' ], 'Current')
+ .setTooltip('Current provides the mana the target has, max provides their total mana, missing provides how much mana they have lost, and percent is the ratio of health to total mana.')
+ );
}
extend('MechanicValueMultiply', 'Component');
function MechanicValueMultiply()
{
this.super('Value Multiply', Type.MECHANIC, false);
-
+
this.description = 'Multiplies a stored value under a unique key for the caster. If the value wasn\'t set before, this will not do anything.';
-
+
this.data.push(new StringValue('Key', 'key', 'value')
.setTooltip('The unique key to store the value under. This key can be used in place of attribute values to use the stored value.')
);
@@ -2289,6 +2615,24 @@ function MechanicValueMultiply()
);
}
+extend('MechanicValuePlaceholder', 'Component');
+function MechanicValuePlaceholder()
+{
+ this.super('Value Placeholder', Type.MECHANIC, false);
+
+ this.description = 'Uses a placeholder string and stores it as a value for the caster';
+
+ this.data.push(new StringValue('Key', 'key', 'value')
+ .setTooltip('The unique key to store the value under. This key can be used in place of attribute values to use the stored value.')
+ );
+ this.data.push(new ListValue("Type", "type", [ 'Number', 'String' ], 'Number')
+ .setTooltip('The type of value to store. Number values require numeric placeholders. String values can be used in messages or commands.')
+ );
+ this.data.push(new StringValue('Placeholder', 'placeholder', '%player_food_level%')
+ .setTooltip('The placeholder string to use. Can contain multiple placeholders if using the String type.')
+ );
+}
+
extend('MechanicValueRandom', 'Component')
function MechanicValueRandom()
{
@@ -2442,6 +2786,9 @@ function MechanicWolf()
this.data.push(new AttributeValue('Damage', 'damage', 3, 0)
.setTooltip('The damage dealt by the wolf each attack')
);
+ this.data.push(new ListValue('Sitting', 'sitting', [ 'True', 'False' ], 'False')
+ .setTooltip('[PREMIUM] whether or not the wolf starts of sitting')
+ );
this.data.push(new AttributeValue('Duration', 'seconds', 10, 0)
.setTooltip('How long to summon the wolf for')
);
@@ -2689,7 +3036,7 @@ function addEffectOptions(component, optional)
component.data.push(opt(new StringValue('Shape Size', '-shape-size', '1')
.setTooltip('Formula for deciding the size of the shape. This can be any sort of formula using the operations defined in the wiki.')
));
- component.data.push(opt(new StringValue('Animation', '-animation', 'circle')
+ component.data.push(opt(new StringValue('Animation', '-animation', 'one-circle')
.setTooltip('Key of a formula for deciding where the particle effect moves relative to the target. View "effects.yml" for a list of defined formulas and their keys.')
));
component.data.push(opt(new ListValue('Animation Direction', '-anim-dir', [ 'XY', 'YZ', 'XZ' ], 'XZ')
@@ -2785,4 +3132,4 @@ function appendOptional(value)
function appendNone(value)
{
return value;
-}
\ No newline at end of file
+}
diff --git a/editor/js/input.js b/editor/js/input.js
index a9ff74e8..150d0a27 100644
--- a/editor/js/input.js
+++ b/editor/js/input.js
@@ -13,6 +13,13 @@ function requireValue(key, values)
return this;
}
+function copyRequirements(source, target) {
+ if (source.requirements) {
+ target.requirements = source.requirements;
+ }
+ return target;
+}
+
/**
* Applies the values required from above
*/
@@ -71,7 +78,8 @@ function checkRequireValue(e)
*/
function setTooltip(text)
{
- this.tooltip = text;
+ if (text.charAt(0) == '[') this.tooltip = text;
+ else this.tooltip = '[' + this.key + '] ' + text;
return this;
}
@@ -200,8 +208,8 @@ IndexListValue.prototype.load = function(value)
*
* @param {string} name - the display name of the value
* @param {string} key - the config key for the value
- * @param {Array} list - the list of available options
- * @param {Number} value - the current selected value
+ * @param {string[]} list - the list of available options
+ * @param {string} value - the current selected value
*
* @constructor
*/
@@ -255,7 +263,7 @@ ListValue.prototype.createHTML = function(target)
option.innerHTML = this.list[i];
this.select.add(option);
- var lower = this.list[i].toLowerCase();
+ var lower = this.list[i].toLowerCase().replace('_', ' ');
if (lower === vLower || (selected == -1 && this.list[i] == 'None'))
{
selected = i;
@@ -1246,4 +1254,4 @@ ByteListValue.prototype.getSaveString = function(spacing)
ByteListValue.prototype.load = function(value)
{
this.value = value;
-}
\ No newline at end of file
+}
diff --git a/editor/js/material.js b/editor/js/material.js
index 22502e6c..5f378dfb 100644
--- a/editor/js/material.js
+++ b/editor/js/material.js
@@ -45,8 +45,12 @@ var materialList = [
'BIRCH_FENCE',
'BIRCH_FENCE_GATE',
'BIRCH_WOOD_STAIRS',
+ 'BLACK_GLAZED_TERRACOTTA',
+ 'BLACK_SHULKER_BOX',
'BLAZE_POWDER',
'BLAZE_ROD',
+ 'BLUE_GLAZED_TERRACOTTA',
+ 'BLUE_SHULKER_BOX',
'BOAT',
'BOAT_ACACIA',
'BOAT_BIRCH',
@@ -54,6 +58,7 @@ var materialList = [
'BOAT_JUNGLE',
'BOAT_SPRUCE',
'BONE',
+ 'BONE_BLOCK',
'BOOK',
'BOOK_AND_QUILL',
'BOOKSHELF',
@@ -64,7 +69,9 @@ var materialList = [
'BREWING_STAND_ITEM',
'BRICK',
'BRICK_STAIRS',
+ 'BROWN_GLAZED_TERRACOTTA',
'BROWN_MUSHROOM',
+ 'BROWN_SHULKER_BOX',
'BUCKET',
'BURNING_FURNACE',
'CACTUS',
@@ -100,6 +107,8 @@ var materialList = [
'COMMAND_MINECART',
'COMMAND_REPEATING',
'COMPASS',
+ 'CONCRETE',
+ 'CONCRETE_POWDER',
'COOKED_BEEF',
'COOKED_CHICKEN',
'COOKED_FISH',
@@ -107,6 +116,8 @@ var materialList = [
'COOKED_RABBIT',
'COOKIE',
'CROPS',
+ 'CYAN_GLAZED_TERRACOTTA',
+ 'CYAN_SHULKER_BOX',
'DARK_OAK_DOOR',
'DARK_OAK_DOOR_ITEM',
'DARK_OAK_FENCE',
@@ -202,7 +213,11 @@ var materialList = [
'GRASS',
'GRASS_PATH',
'GRAVEL',
+ 'GRAY_GLAZED_TERRACOTTA',
+ 'GRAY_SHULKER_BOX',
+ 'GREEN_GLAZED_TERRACOTTA',
'GREEN_RECORD',
+ 'GREEN_SHULKER_BOX',
'GRILLED_PORK',
'HARD_CLAY',
'HAY_BLOCK',
@@ -224,6 +239,7 @@ var materialList = [
'IRON_HOE',
'IRON_INGOT',
'IRON_LEGGINGS',
+ 'IRON_NUGGET',
'IRON_ORE',
'IRON_PICKAXE',
'IRON_PLATE',
@@ -238,6 +254,7 @@ var materialList = [
'JUNGLE_FENCE',
'JUNGLE_FENCE_GATE',
'JUNGLE_WOOD_STAIRS',
+ 'KNOWLEDGE_BOOK',
'LADDER',
'LAPIS_BLOCK',
'LAPIS_ORE',
@@ -252,10 +269,17 @@ var materialList = [
'LEAVES',
'LEAVES_2',
'LEVER',
+ 'LIGHT_BLUE_GLAZED_TERRACOTTA',
+ 'LIGHT_BLUE_SHULKER_BOX',
+ 'LIME_GLAZED_TERRACOTTA',
+ 'LIME_SHULKER_BOX',
'LINGERING_POTION',
'LOG',
'LOG_2',
'LONG_GRASS',
+ 'MAGENTA_GLAZED_TERRACOTTA',
+ 'MAGENTA_SHULKER_BOX',
+ 'MAGMA',
'MAGMA_CREAM',
'MAP',
'MELON',
@@ -278,13 +302,19 @@ var materialList = [
'NETHER_FENCE',
'NETHER_STALK',
'NETHER_STAR',
+ 'NETHER_WART_BLOCK',
'NETHER_WARTS',
'NETHERRACK',
'NOTE_BLOCK',
+ 'OBSERVER',
'OBSIDIAN',
+ 'ORANGE_GLAZED_TERRACOTTA',
+ 'ORANGE_SHULKER_BOX',
'PACKED_ICE',
'PAINTING',
'PAPER',
+ 'PINK_GLAZED_TERRACOTTA',
+ 'PINK_SHULKER_BOX',
'PISTON_BASE',
'PISTON_EXTENSION',
'PISTON_MOVING_PIECE',
@@ -304,6 +334,8 @@ var materialList = [
'PUMPKIN_PIE',
'PUMPKIN_SEEDS',
'PUMPKIN_STEM',
+ 'PURPLE_GLAZED_TERRACOTTA',
+ 'PURPLE_SHULKER_BOX',
'PURPUR_BLOCK',
'PURPUR_DOUBLE_SLAB',
'PURPUR_PILLAR',
@@ -331,10 +363,13 @@ var materialList = [
'RECORD_7',
'RECORD_8',
'RECORD_9',
+ 'RED_GLAZED_TERRACOTTA',
'RED_MUSHROOM',
+ 'RED_NETHER_BRICK',
'RED_ROSE',
'RED_SANDSTONE',
'RED_SANDSTONE_STAIRS',
+ 'RED_SHULKER_BOX',
'REDSTONE',
'REDSTONE_BLOCK',
'REDSTONE_COMPARATOR',
@@ -356,8 +391,11 @@ var materialList = [
'SEEDS',
'SHEARS',
'SHIELD',
+ 'SHULKER_SHELL',
'SIGN',
'SIGN_POST',
+ 'SILVER_GLAZED_TERRACOTTA',
+ 'SILVER_SHULKER_BOX',
'SKULL',
'SKULL_ITEM',
'SLIME_BALL',
@@ -399,6 +437,7 @@ var materialList = [
'STORAGE_MINECART',
'STRING',
'STRUCTURE_BLOCK',
+ 'STRUCTURE_VOID',
'SUGAR',
'SUGAR_CANE',
'SUGAR_CANE_BLOCK',
@@ -407,6 +446,7 @@ var materialList = [
'TIPPED_ARROW',
'TNT',
'TORCH',
+ 'TOTEM',
'TRAP_DOOR',
'TRAPPED_CHEST',
'TRIPWIRE',
@@ -420,6 +460,8 @@ var materialList = [
'WATER_LILY',
'WEB',
'WHEAT',
+ 'WHITE_GLAZED_TERRACOTTA',
+ 'WHITE_SHULKER_BOX',
'WOOD',
'WOOD_AXE',
'WOOD_BUTTON',
@@ -436,7 +478,9 @@ var materialList = [
'WOOL',
'WORKBENCH',
'WRITTEN_BOOK',
- 'YELLOW_FLOWER'
+ 'YELLOW_FLOWER',
+ 'YELLOW_GLAZED_TERRACOTTA',
+ 'YELLOW_SHULKER_BOX'
];
for (var i = 0; i < materialList.length; i++)
diff --git a/editor/js/skill.js b/editor/js/skill.js
index 42571d47..9b1256d5 100644
--- a/editor/js/skill.js
+++ b/editor/js/skill.js
@@ -29,6 +29,7 @@ function Skill(name)
new AttributeValue('Cost', 'cost', 1, 0).setTooltip('The amount of skill points needed to unlock and upgrade this skill'),
new AttributeValue('Cooldown', 'cooldown', 0, 0).setTooltip('The time in seconds before the skill can be cast again (only works with the Cast trigger)'),
new AttributeValue('Mana', 'mana', 0, 0).setTooltip('The amount of mana it takes to cast the skill (only works with the Cast trigger)'),
+ new AttributeValue('Min Spent', 'points-spent-req', 0, 0).setTooltip('The amount of skill points that need to be spent before upgrading this skill'),
new StringValue('Cast Message', 'msg', '&6{player} &2has cast &6{skill}').setTooltip('The message to display to players around the caster when the skill is cast. The radius of the area is in the config.yml options'),
new StringValue('Combo', 'combo', '').setTooltip('The click combo to assign the skill (if enabled). Use L, R, and S for the types of clicks separated by spaces. For example, "L L R R" would work for 4 click combos.'),
new ListValue('Indicator', 'indicator', [ '2D', '3D', 'None' ], '2D').setTooltip('[PREMIUM] What sort of display to use for cast previews. This applies to the "hover bar" in the casting bars setup.'),
@@ -43,7 +44,8 @@ function Skill(name)
'',
'&2Mana: {attr:mana}',
'&2Cooldown: {attr:cooldown}'
- ]).setTooltip('The description shown for the item in skill trees. Include values of mechanics such as damage dealt using their "Icon Key" values')
+ ]).setTooltip('The description shown for the item in skill trees. Include values of mechanics such as damage dealt using their "Icon Key" values'),
+ new StringListValue('Incompatible', 'incompatible', []).setTooltip('List of skill names that must not be upgraded in order to upgrade this skill')
];
}
@@ -74,8 +76,9 @@ Skill.prototype.createFormHTML = function()
header.innerHTML = 'Skill Details';
form.appendChild(header);
- var h = document.createElement('hr');
- form.appendChild(h);
+ form.appendChild(document.createElement('hr'));
+ form.appendChild(this.createEditButton(form));
+ form.appendChild(document.createElement('hr'));
this.data[3].list.splice(1, this.data[3].list.length - 1);
for (var i = 0; i < skills.length; i++)
@@ -93,7 +96,15 @@ Skill.prototype.createFormHTML = function()
var hr = document.createElement('hr');
form.appendChild(hr);
- var done = document.createElement('h5');
+ form.appendChild(this.createEditButton(form));
+
+ var target = document.getElementById('skillForm');
+ target.innerHTML = '';
+ target.appendChild(form);
+}
+
+Skill.prototype.createEditButton = function(form) {
+ var done = document.createElement('h5');
done.className = 'doneButton';
done.innerHTML = 'Edit Effects',
done.skill = this;
@@ -105,11 +116,7 @@ Skill.prototype.createFormHTML = function()
this.form.parentNode.removeChild(this.form);
showSkillPage('builder');
});
- form.appendChild(done);
-
- var target = document.getElementById('skillForm');
- target.innerHTML = '';
- target.appendChild(form);
+ return done;
}
/**
@@ -165,13 +172,13 @@ Skill.prototype.getSaveString = function()
saveString += this.data[0].value + ":\n";
for (var i = 0; i < this.data.length; i++)
{
- if (this.data[i] instanceof AttributeValue) continue;
+ if (isAttribute(this.data[i])) continue;
saveString += this.data[i].getSaveString(' ');
}
saveString += ' attributes:\n';
for (var i = 0; i < this.data.length; i++)
{
- if (this.data[i] instanceof AttributeValue)
+ if (isAttribute(this.data[i]))
{
saveString += this.data[i].getSaveString(' ');
}
@@ -188,6 +195,10 @@ Skill.prototype.getSaveString = function()
return saveString;
}
+function isAttribute(input) {
+ return (input instanceof AttributeValue) || (input.key == 'incompatible');
+}
+
/**
* Loads skill data from the config lines stating at the given index
*
diff --git a/editor/js/sounds.js b/editor/js/sounds.js
index 19ddccd1..99732b47 100644
--- a/editor/js/sounds.js
+++ b/editor/js/sounds.js
@@ -23,9 +23,12 @@ var SOUNDS_POST = [
'BLOCK_DISPENSER_DISPENSE',
'BLOCK_DISPENSER_FAIL',
'BLOCK_DISPENSER_LAUNCH',
- 'BLOCK_END_GATEWAY_SPAWN',
+ 'BLOCK_ENCHANTMENT_TABLE_USE',
'BLOCK_ENDERCHEST_CLOSE',
'BLOCK_ENDERCHEST_OPEN',
+ 'BLOCK_END_GATEWAY_SPAWN',
+ 'BLOCK_END_PORTAL_FRAME_FILL',
+ 'BLOCK_END_PORTAL_SPAWN',
'BLOCK_FENCE_GATE_CLOSE',
'BLOCK_FENCE_GATE_OPEN',
'BLOCK_FIRE_AMBIENT',
@@ -68,10 +71,15 @@ var SOUNDS_POST = [
'BLOCK_METAL_STEP',
'BLOCK_NOTE_BASEDRUM',
'BLOCK_NOTE_BASS',
+ 'BLOCK_NOTE_BELL',
+ 'BLOCK_NOTE_CHIME',
+ 'BLOCK_NOTE_FLUTE',
+ 'BLOCK_NOTE_GUITAR',
'BLOCK_NOTE_HARP',
'BLOCK_NOTE_HAT',
'BLOCK_NOTE_PLING',
'BLOCK_NOTE_SNARE',
+ 'BLOCK_NOTE_XYLOPHONE',
'BLOCK_PISTON_CONTRACT',
'BLOCK_PISTON_EXTEND',
'BLOCK_PORTAL_AMBIENT',
@@ -83,6 +91,8 @@ var SOUNDS_POST = [
'BLOCK_SAND_HIT',
'BLOCK_SAND_PLACE',
'BLOCK_SAND_STEP',
+ 'BLOCK_SHULKER_BOX_CLOSE',
+ 'BLOCK_SHULKER_BOX_OPEN',
'BLOCK_SLIME_BREAK',
'BLOCK_SLIME_FALL',
'BLOCK_SLIME_HIT',
@@ -106,8 +116,12 @@ var SOUNDS_POST = [
'BLOCK_TRIPWIRE_CLICK_OFF',
'BLOCK_TRIPWIRE_CLICK_ON',
'BLOCK_TRIPWIRE_DETACH',
- 'BLOCK_WATER_AMBIENT',
'BLOCK_WATERLILY_PLACE',
+ 'BLOCK_WATER_AMBIENT',
+ 'BLOCK_WOODEN_DOOR_CLOSE',
+ 'BLOCK_WOODEN_DOOR_OPEN',
+ 'BLOCK_WOODEN_TRAPDOOR_CLOSE',
+ 'BLOCK_WOODEN_TRAPDOOR_OPEN',
'BLOCK_WOOD_BREAK',
'BLOCK_WOOD_BUTTON_CLICK_OFF',
'BLOCK_WOOD_BUTTON_CLICK_ON',
@@ -117,10 +131,6 @@ var SOUNDS_POST = [
'BLOCK_WOOD_PRESSUREPLATE_CLICK_OFF',
'BLOCK_WOOD_PRESSUREPLATE_CLICK_ON',
'BLOCK_WOOD_STEP',
- 'BLOCK_WOODEN_DOOR_CLOSE',
- 'BLOCK_WOODEN_DOOR_OPEN',
- 'BLOCK_WOODEN_TRAPDOOR_CLOSE',
- 'BLOCK_WOODEN_TRAPDOOR_OPEN',
'ENCHANT_THORNS_HIT',
'ENTITY_ARMORSTAND_BREAK',
'ENTITY_ARMORSTAND_FALL',
@@ -139,6 +149,9 @@ var SOUNDS_POST = [
'ENTITY_BLAZE_DEATH',
'ENTITY_BLAZE_HURT',
'ENTITY_BLAZE_SHOOT',
+ 'ENTITY_BOAT_PADDLE_LAND',
+ 'ENTITY_BOAT_PADDLE_WATER',
+ 'ENTITY_BOBBER_RETRIEVE',
'ENTITY_BOBBER_SPLASH',
'ENTITY_BOBBER_THROW',
'ENTITY_CAT_AMBIENT',
@@ -171,6 +184,7 @@ var SOUNDS_POST = [
'ENTITY_ELDER_GUARDIAN_CURSE',
'ENTITY_ELDER_GUARDIAN_DEATH',
'ENTITY_ELDER_GUARDIAN_DEATH_LAND',
+ 'ENTITY_ELDER_GUARDIAN_FLOP',
'ENTITY_ELDER_GUARDIAN_HURT',
'ENTITY_ELDER_GUARDIAN_HURT_LAND',
'ENTITY_ENDERDRAGON_AMBIENT',
@@ -180,6 +194,7 @@ var SOUNDS_POST = [
'ENTITY_ENDERDRAGON_GROWL',
'ENTITY_ENDERDRAGON_HURT',
'ENTITY_ENDERDRAGON_SHOOT',
+ 'ENTITY_ENDEREYE_DEATH',
'ENTITY_ENDEREYE_LAUNCH',
'ENTITY_ENDERMEN_AMBIENT',
'ENTITY_ENDERMEN_DEATH',
@@ -192,9 +207,16 @@ var SOUNDS_POST = [
'ENTITY_ENDERMITE_HURT',
'ENTITY_ENDERMITE_STEP',
'ENTITY_ENDERPEARL_THROW',
+ 'ENTITY_EVOCATION_FANGS_ATTACK',
+ 'ENTITY_EVOCATION_ILLAGER_AMBIENT',
+ 'ENTITY_EVOCATION_ILLAGER_CAST_SPELL',
+ 'ENTITY_EVOCATION_ILLAGER_DEATH',
+ 'ENTITY_EVOCATION_ILLAGER_HURT',
+ 'ENTITY_EVOCATION_ILLAGER_PREPARE_ATTACK',
+ 'ENTITY_EVOCATION_ILLAGER_PREPARE_SUMMON',
+ 'ENTITY_EVOCATION_ILLAGER_PREPARE_WOLOLO',
'ENTITY_EXPERIENCE_BOTTLE_THROW',
'ENTITY_EXPERIENCE_ORB_PICKUP',
- 'ENTITY_EXPERIENCE_ORB_TOUCH',
'ENTITY_FIREWORK_BLAST',
'ENTITY_FIREWORK_BLAST_FAR',
'ENTITY_FIREWORK_LARGE_BLAST',
@@ -247,22 +269,42 @@ var SOUNDS_POST = [
'ENTITY_HOSTILE_SMALL_FALL',
'ENTITY_HOSTILE_SPLASH',
'ENTITY_HOSTILE_SWIM',
+ 'ENTITY_HUSK_AMBIENT',
+ 'ENTITY_HUSK_DEATH',
+ 'ENTITY_HUSK_HURT',
+ 'ENTITY_HUSK_STEP',
+ 'ENTITY_ILLUSION_ILLAGER_AMBIENT',
+ 'ENTITY_ILLUSION_ILLAGER_CAST_SPELL',
+ 'ENTITY_ILLUSION_ILLAGER_DEATH',
+ 'ENTITY_ILLUSION_ILLAGER_HURT',
+ 'ENTITY_ILLUSION_ILLAGER_MIRROR_MOVE',
+ 'ENTITY_ILLUSION_ILLAGER_PREPARE_BLINDNESS',
+ 'ENTITY_ILLUSION_ILLAGER_PREPARE_MIRROR',
'ENTITY_IRONGOLEM_ATTACK',
'ENTITY_IRONGOLEM_DEATH',
'ENTITY_IRONGOLEM_HURT',
'ENTITY_IRONGOLEM_STEP',
- 'ENTITY_ITEM_BREAK',
- 'ENTITY_ITEM_PICKUP',
'ENTITY_ITEMFRAME_ADD_ITEM',
'ENTITY_ITEMFRAME_BREAK',
'ENTITY_ITEMFRAME_PLACE',
'ENTITY_ITEMFRAME_REMOVE_ITEM',
'ENTITY_ITEMFRAME_ROTATE_ITEM',
+ 'ENTITY_ITEM_BREAK',
+ 'ENTITY_ITEM_PICKUP',
'ENTITY_LEASHKNOT_BREAK',
'ENTITY_LEASHKNOT_PLACE',
'ENTITY_LIGHTNING_IMPACT',
'ENTITY_LIGHTNING_THUNDER',
'ENTITY_LINGERINGPOTION_THROW',
+ 'ENTITY_LLAMA_AMBIENT',
+ 'ENTITY_LLAMA_ANGRY',
+ 'ENTITY_LLAMA_CHEST',
+ 'ENTITY_LLAMA_DEATH',
+ 'ENTITY_LLAMA_EAT',
+ 'ENTITY_LLAMA_HURT',
+ 'ENTITY_LLAMA_SPIT',
+ 'ENTITY_LLAMA_STEP',
+ 'ENTITY_LLAMA_SWAG',
'ENTITY_MAGMACUBE_DEATH',
'ENTITY_MAGMACUBE_HURT',
'ENTITY_MAGMACUBE_JUMP',
@@ -271,10 +313,44 @@ var SOUNDS_POST = [
'ENTITY_MINECART_RIDING',
'ENTITY_MOOSHROOM_SHEAR',
'ENTITY_MULE_AMBIENT',
+ 'ENTITY_MULE_CHEST',
'ENTITY_MULE_DEATH',
'ENTITY_MULE_HURT',
'ENTITY_PAINTING_BREAK',
'ENTITY_PAINTING_PLACE',
+ 'ENTITY_PARROT_AMBIENT',
+ 'ENTITY_PARROT_DEATH',
+ 'ENTITY_PARROT_EAT',
+ 'ENTITY_PARROT_FLY',
+ 'ENTITY_PARROT_HURT',
+ 'ENTITY_PARROT_IMITATE_BLAZE',
+ 'ENTITY_PARROT_IMITATE_CREEPER',
+ 'ENTITY_PARROT_IMITATE_ELDER_GUARDIAN',
+ 'ENTITY_PARROT_IMITATE_ENDERDRAGON',
+ 'ENTITY_PARROT_IMITATE_ENDERMAN',
+ 'ENTITY_PARROT_IMITATE_ENDERMITE',
+ 'ENTITY_PARROT_IMITATE_EVOCATION_ILLAGER',
+ 'ENTITY_PARROT_IMITATE_GHAST',
+ 'ENTITY_PARROT_IMITATE_HUSK',
+ 'ENTITY_PARROT_IMITATE_ILLUSION_ILLAGER',
+ 'ENTITY_PARROT_IMITATE_MAGMACUBE',
+ 'ENTITY_PARROT_IMITATE_POLAR_BEAR',
+ 'ENTITY_PARROT_IMITATE_SHULKER',
+ 'ENTITY_PARROT_IMITATE_SILVERFISH',
+ 'ENTITY_PARROT_IMITATE_SKELETON',
+ 'ENTITY_PARROT_IMITATE_SLIME',
+ 'ENTITY_PARROT_IMITATE_SPIDER',
+ 'ENTITY_PARROT_IMITATE_STRAY',
+ 'ENTITY_PARROT_IMITATE_VEX',
+ 'ENTITY_PARROT_IMITATE_VINDICATION_ILLAGER',
+ 'ENTITY_PARROT_IMITATE_WITCH',
+ 'ENTITY_PARROT_IMITATE_WITHER',
+ 'ENTITY_PARROT_IMITATE_WITHER_SKELETON',
+ 'ENTITY_PARROT_IMITATE_WOLF',
+ 'ENTITY_PARROT_IMITATE_ZOMBIE',
+ 'ENTITY_PARROT_IMITATE_ZOMBIE_PIGMAN',
+ 'ENTITY_PARROT_IMITATE_ZOMBIE_VILLAGER',
+ 'ENTITY_PARROT_STEP',
'ENTITY_PIG_AMBIENT',
'ENTITY_PIG_DEATH',
'ENTITY_PIG_HURT',
@@ -291,10 +367,18 @@ var SOUNDS_POST = [
'ENTITY_PLAYER_BURP',
'ENTITY_PLAYER_DEATH',
'ENTITY_PLAYER_HURT',
+ 'ENTITY_PLAYER_HURT_DROWN',
+ 'ENTITY_PLAYER_HURT_ON_FIRE',
'ENTITY_PLAYER_LEVELUP',
'ENTITY_PLAYER_SMALL_FALL',
'ENTITY_PLAYER_SPLASH',
'ENTITY_PLAYER_SWIM',
+ 'ENTITY_POLAR_BEAR_AMBIENT',
+ 'ENTITY_POLAR_BEAR_BABY_AMBIENT',
+ 'ENTITY_POLAR_BEAR_DEATH',
+ 'ENTITY_POLAR_BEAR_HURT',
+ 'ENTITY_POLAR_BEAR_STEP',
+ 'ENTITY_POLAR_BEAR_WARNING',
'ENTITY_RABBIT_AMBIENT',
'ENTITY_RABBIT_ATTACK',
'ENTITY_RABBIT_DEATH',
@@ -353,13 +437,24 @@ var SOUNDS_POST = [
'ENTITY_SQUID_AMBIENT',
'ENTITY_SQUID_DEATH',
'ENTITY_SQUID_HURT',
+ 'ENTITY_STRAY_AMBIENT',
+ 'ENTITY_STRAY_DEATH',
+ 'ENTITY_STRAY_HURT',
+ 'ENTITY_STRAY_STEP',
'ENTITY_TNT_PRIMED',
+ 'ENTITY_VEX_AMBIENT',
+ 'ENTITY_VEX_CHARGE',
+ 'ENTITY_VEX_DEATH',
+ 'ENTITY_VEX_HURT',
'ENTITY_VILLAGER_AMBIENT',
'ENTITY_VILLAGER_DEATH',
'ENTITY_VILLAGER_HURT',
'ENTITY_VILLAGER_NO',
'ENTITY_VILLAGER_TRADING',
'ENTITY_VILLAGER_YES',
+ 'ENTITY_VINDICATION_ILLAGER_AMBIENT',
+ 'ENTITY_VINDICATION_ILLAGER_DEATH',
+ 'ENTITY_VINDICATION_ILLAGER_HURT',
'ENTITY_WITCH_AMBIENT',
'ENTITY_WITCH_DEATH',
'ENTITY_WITCH_DRINK',
@@ -370,6 +465,10 @@ var SOUNDS_POST = [
'ENTITY_WITHER_DEATH',
'ENTITY_WITHER_HURT',
'ENTITY_WITHER_SHOOT',
+ 'ENTITY_WITHER_SKELETON_AMBIENT',
+ 'ENTITY_WITHER_SKELETON_DEATH',
+ 'ENTITY_WITHER_SKELETON_HURT',
+ 'ENTITY_WITHER_SKELETON_STEP',
'ENTITY_WITHER_SPAWN',
'ENTITY_WOLF_AMBIENT',
'ENTITY_WOLF_DEATH',
@@ -403,10 +502,12 @@ var SOUNDS_POST = [
'ENTITY_ZOMBIE_VILLAGER_STEP',
'ITEM_ARMOR_EQUIP_CHAIN',
'ITEM_ARMOR_EQUIP_DIAMOND',
+ 'ITEM_ARMOR_EQUIP_ELYTRA',
'ITEM_ARMOR_EQUIP_GENERIC',
'ITEM_ARMOR_EQUIP_GOLD',
'ITEM_ARMOR_EQUIP_IRON',
'ITEM_ARMOR_EQUIP_LEATHER',
+ 'ITEM_BOTTLE_EMPTY',
'ITEM_BOTTLE_FILL',
'ITEM_BOTTLE_FILL_DRAGONBREATH',
'ITEM_BUCKET_EMPTY',
@@ -414,12 +515,14 @@ var SOUNDS_POST = [
'ITEM_BUCKET_FILL',
'ITEM_BUCKET_FILL_LAVA',
'ITEM_CHORUS_FRUIT_TELEPORT',
+ 'ITEM_ELYTRA_FLYING',
'ITEM_FIRECHARGE_USE',
'ITEM_FLINTANDSTEEL_USE',
'ITEM_HOE_TILL',
'ITEM_SHIELD_BLOCK',
'ITEM_SHIELD_BREAK',
'ITEM_SHOVEL_FLATTEN',
+ 'ITEM_TOTEM_USE',
'MUSIC_CREATIVE',
'MUSIC_CREDITS',
'MUSIC_DRAGON',
@@ -440,6 +543,9 @@ var SOUNDS_POST = [
'RECORD_WAIT',
'RECORD_WARD',
'UI_BUTTON_CLICK',
+ 'UI_TOAST_CHALLENGE_COMPLETE',
+ 'UI_TOAST_IN',
+ 'UI_TOAST_OUT',
'WEATHER_RAIN',
'WEATHER_RAIN_ABOVE'
];
@@ -655,4 +761,4 @@ function formatSound(name) {
result += words[i].charAt(0) + words[i].substr(1).toLowerCase();
}
return result;
-}
\ No newline at end of file
+}
diff --git a/editor/style.css b/editor/style.css
index 2b5355fa..86b962ce 100644
--- a/editor/style.css
+++ b/editor/style.css
@@ -50,6 +50,12 @@ html, body {
background-color: black;
}
+#attribute-label {
+ width: 90% !important;
+ text-align: center !important;
+ color: #888;
+}
+
#badBrowser p {
text-align: center;
margin-top: 40%;
@@ -69,12 +75,10 @@ html, body {
#skills, #classes {
float: left;
- width: calc(100% - 16px);
- margin-left: 5px;
- height: calc(100% - 55px);
- border: 3px solid white;
+ width: 100%;
+ height: calc(100% - 45px);
background-color: black;
- border-radius: 20px;
+ border-radius: 0;
overflow: hidden;
}
@@ -112,11 +116,12 @@ html, body {
float: left;
width: 200px;
font: 18px Sertig-Web;
- background-color: #000;
+ background-color: #181818;
color: white;
font-weight: bold;
height: 100%;
padding: 5px;
+ border: none;
}
#skillList option, #classList option {
@@ -158,11 +163,11 @@ h5 {
float: left;
width: 225px;
padding: 10px 5px;
- background-color: #111;
+ background-color: #181818;
margin-bottom: 10px;
margin-left: 10px;
- border-radius: 10px;
- border: 2px solid #ccc;
+ border-radius: 5px;
+ border: 2px solid #333;
text-align: center;
font: 24px Sertig-Web;
font-weight: bold;
@@ -171,7 +176,7 @@ h5 {
}
h5:hover {
- background-color: #666;
+ background-color: #777;
cursor: pointer;
}
@@ -180,12 +185,11 @@ h6 {
display: inline-block;
width: calc(25% - 26px);
padding: 5px 5px;
- background-color: #111;
- margin: 0 3px;
+ background-color: #043;
+ margin-left: 3px;
margin-top: 10px;
margin-bottom: 5px;
- border-radius: 10px;
- border: 2px solid #ccc;
+ border-radius: 5px;
text-align: center;
font: 24px Sertig-Web;
font-weight: bold;
@@ -263,24 +267,41 @@ input, select, textarea {
}
.doneButton {
- background-color: blue;
+ background-color: #008966;
+ border: 2px solid #004433;
color: white;
- transition: background-color: 600ms, color 600ms;
+ transition: background-color 600ms, color 600ms;
}
.doneButton:hover {
- background-color: white
- color: red;
+ background-color: #004433;
+ border: 2px solid #002211;
+}
+
+hr {
+ display: block;
+ background-color: #888;
+ height: 1px;
+ width: 100%;
+ clear: both;
+}
+
+#saveSkill {
+ background-color: #375a7f;
+}
+
+#saveSkill:hover {
+ background-color: #6af;
}
.ioButton {
height: 30px;
margin: 5px 10px;
width: calc(100% - 20px);
- background-color: #333;
+ background-color: #375a7f;
color: white;
- border: 2px solid white;
- border-radius: 10px;
+ border: none;
+ border-radius: 5px;
font: 20px Sertig-Web;
font-weight: bold;
cursor: pointer;
@@ -288,7 +309,7 @@ input, select, textarea {
}
.ioButton:hover {
- background-color: #888;
+ background-color: #6af;
}
.ioText {
@@ -298,7 +319,7 @@ input, select, textarea {
}
.premium {
- background-color: #066;
+ background-color: #033;
}
.premium:hover {
@@ -311,7 +332,6 @@ input, select, textarea {
width: calc(45% - 36px);
margin-left: 5px;
background-color: black;
- border: 3px solid #fff;
border-bottom: none;
margin: 5px 5px 0;
color: white;
@@ -325,6 +345,7 @@ input, select, textarea {
.tab {
cursor: pointer;
+ background: #008966;
}
.tab:hover {
@@ -341,8 +362,8 @@ input, select, textarea {
left: -1px;
top: -1px;
content: '';
- border-top: 15px solid #fff;
- border-right: 15px solid transparent;
+ border-top: 20px solid #333;
+ border-right: 20px solid transparent;
}
.tabLeft:after {
@@ -350,8 +371,8 @@ input, select, textarea {
left: -3px;
top: -3px;
content: '';
- border-top: 15px solid #333;
- border-right: 15px solid transparent;
+ border-top: 20px solid #333;
+ border-right: 20px solid transparent;
}
.tabRight:before {
@@ -359,8 +380,8 @@ input, select, textarea {
right: -1px;
top: -1px;
content: '';
- border-top: 15px solid #fff;
- border-left: 15px solid transparent;
+ border-top: 20px solid #333;
+ border-left: 20px solid transparent;
}
.tabRight:after {
@@ -368,8 +389,8 @@ input, select, textarea {
right: -3px;
top: -3px;
content: '';
- border-top: 15px solid #333;
- border-left: 15px solid transparent;
+ border-top: 20px solid #333;
+ border-left: 20px solid transparent;
}
#io {
@@ -385,16 +406,20 @@ input, select, textarea {
font: 24px Sertig-Web;
font-weight: bold;
padding-top: 10px;
+ clear: both;
}
#skillForm input, #skillForm select, #classForm input, #classForm select, #skillForm .byteList, #classForm .byteList {
font: 20px Sertig-Web;
font-weight: bold;
- background-color: #333;
- border: 2px solid white;
- border-radius: 10px;
+ background-color: #181818;
+ border: 1px solid #888;
+ border-top: none;
+ border-right: none;
+ border-radius: 5px;
color: white;
padding: 5px 10px;
+ padding-right: 0;
margin: 2px 5px;
width: 40%;
float: left;
@@ -428,9 +453,11 @@ input, select, textarea {
#skillForm textarea, #classForm textArea {
font: 20px Sertig-Web;
font-weight: bold;
- background-color: #333;
- border: 2px solid white;
- border-radius: 10px;
+ background-color: #181818;
+ border: 1px solid #888;
+ border-top: none;
+ border-right: none;
+ border-radius: 5px;
color: white;
padding: 5px 10px;
margin: 2px 5px;
@@ -439,6 +466,10 @@ input, select, textarea {
height: 200px;
}
+textArea {
+ resize: vertical;
+}
+
#skillForm p, #classForm p {
text-align: center;
font: 20px Sertig-Web;
@@ -454,6 +485,7 @@ input, select, textarea {
margin: 0;
padding: 0;
padding-top: 10px;
+ clear: none;
}
#skillForm .base, #classForm .base {
@@ -475,7 +507,7 @@ input, select, textarea {
::-webkit-scrollbar-track {
border-radius: 10px;
- border: 2px solid #aaa;
+ border: 1px solid #aaa;
}
::-webkit-scrollbar-thumb {
@@ -483,7 +515,7 @@ input, select, textarea {
background-color: #aaa;
}
-@media screen and (max-width: 459px) {
+@media screen and (max-width: 599px) {
#main {
display: none;
diff --git a/editor/tooltips.css b/editor/tooltips.css
index f684d92d..a682e078 100644
--- a/editor/tooltips.css
+++ b/editor/tooltips.css
@@ -69,8 +69,8 @@
padding: 8px;
width: 100%;
background-color: #222;
- border: 2px solid white;
- border-radius: 15px;
+ border-radius: 5px;
+ border: 1px solid white;
color: #fff;
content: attr(data-tooltip);
font-size: 18px;
diff --git a/img/back0.png b/img/back0.png
deleted file mode 100644
index aff4a59e..00000000
Binary files a/img/back0.png and /dev/null differ
diff --git a/img/back1.png b/img/back1.png
deleted file mode 100644
index e57b373e..00000000
Binary files a/img/back1.png and /dev/null differ
diff --git a/img/background.png b/img/background.png
deleted file mode 100644
index 360ec07e..00000000
Binary files a/img/background.png and /dev/null differ
diff --git a/img/down0.png b/img/down0.png
deleted file mode 100644
index 0e888e82..00000000
Binary files a/img/down0.png and /dev/null differ
diff --git a/img/down1.png b/img/down1.png
deleted file mode 100644
index 207eadfd..00000000
Binary files a/img/down1.png and /dev/null differ
diff --git a/img/more0.png b/img/more0.png
deleted file mode 100644
index c2d18f72..00000000
Binary files a/img/more0.png and /dev/null differ
diff --git a/img/more1.png b/img/more1.png
deleted file mode 100644
index 261da847..00000000
Binary files a/img/more1.png and /dev/null differ
diff --git a/img/nameplate.png b/img/nameplate.png
deleted file mode 100644
index cbb0d4bb..00000000
Binary files a/img/nameplate.png and /dev/null differ
diff --git a/img/selector.png b/img/selector.png
deleted file mode 100644
index b6faeb34..00000000
Binary files a/img/selector.png and /dev/null differ
diff --git a/img/title.png b/img/title.png
deleted file mode 100644
index e95defa1..00000000
Binary files a/img/title.png and /dev/null differ
diff --git a/img/up0.png b/img/up0.png
deleted file mode 100644
index eb14b15b..00000000
Binary files a/img/up0.png and /dev/null differ
diff --git a/img/up1.png b/img/up1.png
deleted file mode 100644
index 8f97d463..00000000
Binary files a/img/up1.png and /dev/null differ
diff --git a/index.html b/index.html
index e76ead47..3c75dc91 100644
--- a/index.html
+++ b/index.html
@@ -59,7 +59,7 @@
Dynamic Editor
Details
Triggers
-
Save
+
Save
Delete
diff --git a/modules/BungeeCord.jar b/modules/BungeeCord.jar
new file mode 100644
index 00000000..c3b73809
Binary files /dev/null and b/modules/BungeeCord.jar differ
diff --git a/modules/MCCore.jar b/modules/MCCore.jar
index ddc092f7..2971494b 100644
Binary files a/modules/MCCore.jar and b/modules/MCCore.jar differ
diff --git a/modules/MythicMobs-4.2.0.jar b/modules/MythicMobs-4.2.0.jar
new file mode 100644
index 00000000..70121bc6
Binary files /dev/null and b/modules/MythicMobs-4.2.0.jar differ
diff --git a/modules/Parties.jar b/modules/Parties.jar
new file mode 100644
index 00000000..ef5dd952
Binary files /dev/null and b/modules/Parties.jar differ
diff --git a/modules/PlaceholderAPI-2.8.2.jar b/modules/PlaceholderAPI-2.8.2.jar
new file mode 100644
index 00000000..8f727228
Binary files /dev/null and b/modules/PlaceholderAPI-2.8.2.jar differ
diff --git a/modules/RPG Parties.jar b/modules/RPG Parties.jar
new file mode 100644
index 00000000..326d7024
Binary files /dev/null and b/modules/RPG Parties.jar differ
diff --git a/modules/RPGInventory.jar b/modules/RPGInventory.jar
new file mode 100644
index 00000000..cac272e9
Binary files /dev/null and b/modules/RPGInventory.jar differ
diff --git a/modules/SkillAPIModule.jar b/modules/SkillAPIModule.jar
new file mode 100644
index 00000000..06ea641f
Binary files /dev/null and b/modules/SkillAPIModule.jar differ
diff --git a/modules/SkillAPIPlaceholders.jar b/modules/SkillAPIPlaceholders.jar
new file mode 100644
index 00000000..cdbf13a5
Binary files /dev/null and b/modules/SkillAPIPlaceholders.jar differ
diff --git a/modules/WorldEdit.jar b/modules/WorldEdit.jar
new file mode 100644
index 00000000..101f5336
Binary files /dev/null and b/modules/WorldEdit.jar differ
diff --git a/modules/WorldGuard.jar b/modules/WorldGuard.jar
new file mode 100644
index 00000000..e4821f00
Binary files /dev/null and b/modules/WorldGuard.jar differ
diff --git a/modules/craftbukkit-1.13.jar b/modules/craftbukkit-1.13.jar
new file mode 100644
index 00000000..96ef215c
Binary files /dev/null and b/modules/craftbukkit-1.13.jar differ
diff --git a/modules/hamcrest-core-1.3.jar b/modules/hamcrest-core-1.3.jar
new file mode 100644
index 00000000..9d5fe16e
Binary files /dev/null and b/modules/hamcrest-core-1.3.jar differ
diff --git a/modules/junit-4.12.jar b/modules/junit-4.12.jar
new file mode 100644
index 00000000..3a7fc266
Binary files /dev/null and b/modules/junit-4.12.jar differ
diff --git a/modules/mockito-core-1.10.19.jar b/modules/mockito-core-1.10.19.jar
new file mode 100644
index 00000000..d94e289d
Binary files /dev/null and b/modules/mockito-core-1.10.19.jar differ
diff --git a/modules/objenesis-2.4.jar b/modules/objenesis-2.4.jar
new file mode 100644
index 00000000..f76ea51f
Binary files /dev/null and b/modules/objenesis-2.4.jar differ
diff --git a/modules/spigot-1.9.jar b/modules/spigot-1.9.jar
deleted file mode 100644
index c7716ac6..00000000
Binary files a/modules/spigot-1.9.jar and /dev/null differ
diff --git a/src/SkillAPIModule.jar b/src/SkillAPIModule.jar
new file mode 100644
index 00000000..06ea641f
Binary files /dev/null and b/src/SkillAPIModule.jar differ
diff --git a/src/SkillAPIPlaceholders.jar b/src/SkillAPIPlaceholders.jar
new file mode 100644
index 00000000..cdbf13a5
Binary files /dev/null and b/src/SkillAPIPlaceholders.jar differ
diff --git a/src/attributes.yml b/src/attributes.yml
new file mode 100644
index 00000000..3d0ddc23
--- /dev/null
+++ b/src/attributes.yml
@@ -0,0 +1,115 @@
+# Attributes.yml
+#
+# For full details, visit
+# http://dev.bukkit.org/bukkit-plugins/skillapi/pages/attributes/
+#
+# List of available stats to modify:
+# armor | [PREM, 1.9+] Vanilla damage mitigation
+# armor-toughness | [PREM, 1.9+] Secondary vanilla damage mitigation
+# attack-speed | [PREM, 1.9+] Weapon recharge time
+# cooldown | [PREM] Modifies skill cooldowns
+# defense- | [PREM] Reduces damage taken from various damage sources.
+# | See the DamageCause docs to see supported types.
+# | Use lower-case versions of it, such as "defense-block_explosion".
+# exp | [PREM] increases all class experience gained
+# health | The max health of the player
+# hunger | [PREM] Increases how long hunger lasts. This attribute is always based off of a base value of 1. A resulting value of 2 would double how long the hunger bar lasts, for example.
+# hunger-heal | [PREM] Increases how much you heal while satiated
+# knockback-resist | [PREM, 1.9+] Probability of resisting knockback as a decimal (1.0 is 100% change to resist)
+# luck | [PREM, 1.9+] loot table chances
+# mana | The max mana of the player
+# mana-regen | The amount of mana regeneration the player has
+# move-speed | The movement speed of the player
+# physical-damage | The amount of damage done by physical (basic or projectile) attacks
+# physical-defense | The amount of damage taken by physical (basic or projectile) attacks
+# skill-damage | The amount of damage done by skills
+# skill-defense | The amount of damage taken by skills
+
+# skill-damage- | [PREM] The amount of damage done by skills with the specified classification
+# skill-defense- | [PREM] The amount of damage taken by skills with the specified classification
+vitality:
+ display: 'Vitality'
+ max: 999
+ icon: 'ink sack'
+ icon-data: 1
+ icon-lore:
+ - '&6Vitality &7(&2{amount}&7)'
+ - ''
+ - '&7Grants 1 health per'
+ - '&7point invested.'
+ global:
+ condition: {}
+ mechanic: {}
+ target: {}
+ stats:
+ health: 'a+v'
+spirit:
+ display: 'Spirit'
+ max: 999
+ icon: 'ink sack'
+ icon-data: 6
+ icon-lore:
+ - '&6Spirit &7(&2{amount}&7)'
+ - ''
+ - '&7Grants 1 mana and 2.5%'
+ - '&7mana regeneration per'
+ - '&7point invested.'
+ global:
+ condition: {}
+ mechanic: {}
+ target: {}
+ stats:
+ mana: 'a+v'
+ mana-regen: 'a*0.025+1*v'
+intelligence:
+ display: 'Intelligence'
+ max: 999
+ icon: 'ink sack'
+ icon-data: 5
+ icon-lore:
+ - '&6Intelligence &7(&2{amount}&7)'
+ - ''
+ - '&7Grants 2.5% increased'
+ - '&7skill damage per point'
+ - '&7invested.'
+ global:
+ condition: {}
+ mechanic:
+ Damage-value: 'a*0.025+1*v'
+ target: {}
+dexterity:
+ display: 'Dexterity'
+ max: 999
+ icon: 'ink sack'
+ icon-data: 10
+ icon-lore:
+ - '&6Dexterity &7(&2{amount}&7)'
+ - ''
+ - '&7Grants 2.5% increased'
+ - '&7range per point invested.'
+ global:
+ condition: {}
+ mechanic: {}
+ target:
+ Cone-range: 'a*0.025+1*v'
+ Linear-range: 'a*0.025+1*v'
+ Location-range: 'a*0.025+1*v'
+ Nearest-radius: 'a*0.025+1*v'
+ Single-range: 'a*0.025+1*v'
+strength:
+ display: 'Strength'
+ max: 999
+ icon: 'ink sack'
+ icon-data: 14
+ icon-lore:
+ - '&6Strength &7(&2{amount}&7)'
+ - ''
+ - '&7Grants 2.5% increased'
+ - '&7non-skill damage per'
+ - '&7point invested.'
+ global:
+ condition: {}
+ mechanic: {}
+ target: {}
+ stats:
+ physical-damage: 'a*0.025+1*v'
\ No newline at end of file
diff --git a/src/com/sucy/skill/SkillAPI.java b/src/com/sucy/skill/SkillAPI.java
index 6551873a..beb516a6 100644
--- a/src/com/sucy/skill/SkillAPI.java
+++ b/src/com/sucy/skill/SkillAPI.java
@@ -24,10 +24,13 @@
package com.sucy.skill;
+import com.rit.sucy.config.CommentedConfig;
import com.rit.sucy.config.CommentedLanguageConfig;
import com.rit.sucy.version.VersionManager;
import com.rit.sucy.version.VersionPlayer;
import com.sucy.skill.api.classes.RPGClass;
+import com.sucy.skill.api.particle.EffectManager;
+import com.sucy.skill.api.particle.Particle;
import com.sucy.skill.api.player.PlayerAccounts;
import com.sucy.skill.api.player.PlayerClass;
import com.sucy.skill.api.player.PlayerData;
@@ -40,25 +43,27 @@
import com.sucy.skill.data.io.SQLIO;
import com.sucy.skill.dynamic.DynamicClass;
import com.sucy.skill.dynamic.DynamicSkill;
-import com.sucy.skill.dynamic.mechanic.BlockMechanic;
-import com.sucy.skill.dynamic.mechanic.PassiveMechanic;
-import com.sucy.skill.dynamic.mechanic.RepeatMechanic;
-import com.sucy.skill.dynamic.mechanic.WolfMechanic;
-import com.sucy.skill.gui.Menu;
+import com.sucy.skill.gui.tool.GUITool;
+import com.sucy.skill.hook.BungeeHook;
import com.sucy.skill.hook.PluginChecker;
import com.sucy.skill.listener.*;
import com.sucy.skill.manager.*;
-import com.sucy.skill.task.*;
+import com.sucy.skill.packet.PacketInjector;
+import com.sucy.skill.task.CooldownTask;
+import com.sucy.skill.task.GUITask;
+import com.sucy.skill.task.ManaTask;
+import com.sucy.skill.task.SaveTask;
+import com.sucy.skill.thread.MainThread;
import org.bukkit.Bukkit;
-import org.bukkit.GameMode;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
import org.bukkit.metadata.FixedMetadataValue;
+import org.bukkit.metadata.MetadataValue;
import org.bukkit.metadata.Metadatable;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
import java.util.ArrayList;
import java.util.HashMap;
@@ -68,14 +73,15 @@
*
The main class of the plugin which has the accessor methods into most of the API.
*
You can retrieve a reference to this through Bukkit the same way as any other plugin.
*/
-public class SkillAPI extends JavaPlugin
-{
+public class SkillAPI extends JavaPlugin {
private static SkillAPI singleton;
- private final HashMap skills = new HashMap();
- private final HashMap classes = new HashMap();
- private final HashMap players = new HashMap();
- private final ArrayList groups = new ArrayList();
+ private final HashMap skills = new HashMap<>();
+ private final HashMap classes = new HashMap<>();
+ private final HashMap players = new HashMap<>();
+ private final ArrayList groups = new ArrayList<>();
+
+ private final List listeners = new ArrayList<>();
private CommentedLanguageConfig language;
private Settings settings;
@@ -86,26 +92,26 @@ public class SkillAPI extends JavaPlugin
private RegistrationManager registrationManager;
private AttributeManager attributeManager;
- private ManaTask manaTask;
- private CooldownTask cdTask;
- private InventoryTask invTask;
- private SaveTask saveTask;
- private GUITask guiTask;
+ private MainThread mainThread;
+ private BukkitTask manaTask;
private boolean loaded = false;
+ private boolean disabling = false;
/**
*
Enables SkillAPI, setting up listeners, managers, and loading data. This
* should not be called by other plugins.
*/
@Override
- public void onEnable()
- {
+ public void onEnable() {
// Set up the singleton
- if (singleton != null)
- throw new IllegalStateException("Cannot enable SkillAPI twice!");
+ if (singleton != null) { throw new IllegalStateException("Cannot enable SkillAPI twice!"); }
singleton = this;
+ mainThread = new MainThread();
+ Particle.init();
+ EffectManager.init();
+
// Load settings
settings = new Settings(this);
language = new CommentedLanguageConfig(this, "language");
@@ -114,7 +120,7 @@ public void onEnable()
language.save();
// Hook plugins
- PluginChecker.isVaultActive();
+ if (PluginChecker.isBungeeActive()) { BungeeHook.init(this); }
// Set up managers
comboManager = new ComboManager();
@@ -123,9 +129,7 @@ public void onEnable()
io = settings.isUseSql() ? new SQLIO(this) : new ConfigIO(this);
PlayerStats.init();
ClassBoardManager.registerText();
- ResourceManager.copyQuestsModule();
- if (settings.isAttributesEnabled())
- attributeManager = new AttributeManager(this);
+ if (settings.isAttributesEnabled()) { attributeManager = new AttributeManager(this); }
// Load classes and skills
registrationManager.initialize();
@@ -134,47 +138,73 @@ public void onEnable()
settings.loadGroupSettings();
// Set up listeners
- listen(new CastListener(), true);
+ listen(new BindListener(), true);
+ listen(new BuffListener(), true);
listen(new MainListener(), true);
listen(new MechanicListener(), true);
listen(new StatusListener(), true);
+ listen(new ToolListener(), true);
listen(new KillListener(), true);
- listen(new TreeListener(), !settings.isMapTreeEnabled());
+ listen(new AddonListener(), true);
listen(new ItemListener(), settings.isCheckLore());
listen(new BarListener(), settings.isSkillBarEnabled());
- listen(new ClickListener(), settings.isCombosEnabled());
+ if (VersionManager.isVersionAtLeast(VersionManager.V1_8_0)) {
+ final PacketInjector injector = new PacketInjector(this);
+ listen(new PacketListener(injector), true);
+ listen(new ClickListener(), settings.isCombosEnabled());
+ }
+ listen(new ComboListener(), settings.isCombosEnabled());
listen(new AttributeListener(), settings.isAttributesEnabled());
+ listen(new CastListener(), settings.isUsingBars());
+ listen(
+ new CastOffhandListener(),
+ settings.isCastEnabled() && VersionManager.isVersionAtLeast(VersionManager.V1_9_0));
+ listen(new CastItemListener(), settings.isUsingWand());
+ listen(new CastCombatListener(), settings.isUsingCombat());
listen(new DeathListener(), !VersionManager.isVersionAtLeast(11000));
-
- if (settings.isMapTreeAvailable())
- Menu.initialize(this);
+ listen(new LingeringPotionListener(), VersionManager.isVersionAtLeast(VersionManager.V1_9_0));
+ listen(new ExperienceListener(), settings.yieldsEnabled());
// Set up tasks
- if (settings.isManaEnabled())
- manaTask = new ManaTask(this);
- if (settings.isSkillBarCooldowns())
- cdTask = new CooldownTask(this);
- if (settings.isCheckLore())
- invTask = new InventoryTask(this, settings.getPlayersPerCheck());
- if (settings.isAutoSave())
- saveTask = new SaveTask(this);
- guiTask = new GUITask(this);
+ if (settings.isManaEnabled()) {
+ if (VersionManager.isVersionAtLeast(11400)) {
+ manaTask = Bukkit.getScheduler().runTaskTimer(
+ this,
+ new ManaTask(),
+ SkillAPI.getSettings().getGainFreq(),
+ SkillAPI.getSettings().getGainFreq()
+ );
+ } else {
+ MainThread.register(new ManaTask());
+ }
+ }
+ if (settings.isSkillBarCooldowns()) { MainThread.register(new CooldownTask()); }
+ if (settings.isAutoSave()) { MainThread.register(new SaveTask(this)); }
+ MainThread.register(new GUITask(this));
+
+ GUITool.init();
// Load player data
- for (Player player : VersionManager.getOnlinePlayers())
- {
- PlayerData data = loadPlayerData(player).getActiveData();
- data.init(player);
+ players.putAll(io.loadAll());
+ for (PlayerAccounts accounts : players.values()) { accounts.getActiveData().init(accounts.getPlayer()); }
+
+ // Must initialize listeners AFTER player data is loaded since the
+ // player objects would otherwise change and mess a lot of things up.
+ for (SkillAPIListener listener : listeners) {
+ listener.init();
}
- if (settings.isUseSql()) ((SQLIO) io).cleanup();
+
+ ResourceManager.copyQuestsModule();
+ ResourceManager.copyPlaceholdersModule();
loaded = true;
}
- private void listen(Listener listener, boolean enabled)
- {
- if (enabled)
+ private void listen(SkillAPIListener listener, boolean enabled) {
+ if (enabled) {
Bukkit.getPluginManager().registerEvents(listener, this);
+ listeners.add(listener);
+ }
}
/**
@@ -182,56 +212,32 @@ private void listen(Listener listener, boolean enabled)
* listeners. This should not be called by other plugins.
Represents a set of settings that store configurable data for an object.
*/
-public class Settings
-{
+public class Settings {
private static final String BASE = "-base";
private static final String SCALE = "-scale";
- private final HashMap settings = new HashMap();
+ private final HashMap settings;
+
+ public Settings() {
+ this.settings = new LinkedHashMap<>();
+ }
+
+ public Settings(final Settings settings) {
+ this.settings = new HashMap<>(settings.settings);
+ }
/**
* Sets the value for a setting. You should only provide a
@@ -52,8 +61,7 @@ public class Settings
* @param key setting key
* @param value setting value
*/
- public void set(String key, Object value)
- {
+ public void set(String key, Object value) {
settings.put(key, value);
}
@@ -68,8 +76,7 @@ public void set(String key, Object value)
* @param base base value
* @param scale value scale
*/
- public void set(String key, double base, double scale)
- {
+ public void set(String key, double base, double scale) {
settings.put(key + BASE, base);
settings.put(key + SCALE, scale);
}
@@ -85,10 +92,8 @@ public void set(String key, double base, double scale)
* @param key scaling setting name
* @param value new base value
*/
- public void setBase(String key, double value)
- {
- if (!settings.containsKey(key + SCALE))
- {
+ public void setBase(String key, double value) {
+ if (!settings.containsKey(key + SCALE)) {
settings.put(key + SCALE, 0.0);
}
settings.put(key + BASE, value);
@@ -105,10 +110,8 @@ public void setBase(String key, double value)
* @param key scaling setting name
* @param value new scale value
*/
- public void setScale(String key, double value)
- {
- if (!settings.containsKey(key + BASE))
- {
+ public void setScale(String key, double value) {
+ if (!settings.containsKey(key + BASE)) {
settings.put(key + BASE, 0.0);
}
settings.put(key + SCALE, value);
@@ -122,8 +125,7 @@ public void setScale(String key, double value)
*
* @return double setting value
*/
- public double getDouble(String key)
- {
+ public double getDouble(String key) {
return getDouble(key, 0);
}
@@ -136,14 +138,10 @@ public double getDouble(String key)
*
* @return double setting value
*/
- public double getDouble(String key, double defaultValue)
- {
- if (settings.containsKey(key))
- {
+ public double getDouble(String key, double defaultValue) {
+ if (settings.containsKey(key)) {
return NumberParser.parseDouble(settings.get(key).toString());
- }
- else
- {
+ } else {
set(key, defaultValue);
return defaultValue;
}
@@ -157,8 +155,7 @@ public double getDouble(String key, double defaultValue)
*
* @return integer setting value
*/
- public int getInt(String key)
- {
+ public int getInt(String key) {
return getInt(key, 0);
}
@@ -171,14 +168,10 @@ public int getInt(String key)
*
* @return integer setting value
*/
- public int getInt(String key, int defaultValue)
- {
- if (settings.containsKey(key))
- {
+ public int getInt(String key, int defaultValue) {
+ if (settings.containsKey(key)) {
return Integer.parseInt(settings.get(key).toString());
- }
- else
- {
+ } else {
set(key, defaultValue);
return defaultValue;
}
@@ -192,8 +185,7 @@ public int getInt(String key, int defaultValue)
*
* @return boolean setting value
*/
- public boolean getBool(String key)
- {
+ public boolean getBool(String key) {
return settings.containsKey(key) && Boolean.parseBoolean(settings.get(key).toString());
}
@@ -206,14 +198,10 @@ public boolean getBool(String key)
*
* @return boolean setting value
*/
- public boolean getBool(String key, boolean defaultValue)
- {
- if (settings.containsKey(key))
- {
+ public boolean getBool(String key, boolean defaultValue) {
+ if (settings.containsKey(key)) {
return Boolean.parseBoolean(settings.get(key).toString());
- }
- else
- {
+ } else {
set(key, defaultValue);
return defaultValue;
}
@@ -227,8 +215,7 @@ public boolean getBool(String key, boolean defaultValue)
*
* @return String setting value
*/
- public String getString(String key)
- {
+ public String getString(String key) {
return getString(key, null);
}
@@ -241,14 +228,10 @@ public String getString(String key)
*
* @return String setting value
*/
- public String getString(String key, String defaultValue)
- {
- if (settings.containsKey(key) && settings.get(key) != null)
- {
+ public String getString(String key, String defaultValue) {
+ if (settings.containsKey(key) && settings.get(key) != null) {
return settings.get(key).toString();
- }
- else
- {
+ } else {
set(key, defaultValue);
return defaultValue;
}
@@ -262,15 +245,16 @@ public String getString(String key, String defaultValue)
* @return string list or empty list if not found
*/
@SuppressWarnings("unchecked")
- public List getStringList(String key)
- {
- if (settings.containsKey(key) && settings.get(key) instanceof List>)
- {
- return (List) settings.get(key);
- }
- else
- {
- return new ArrayList();
+ public List getStringList(String key) {
+ if (settings.containsKey(key)) {
+ final Object value = settings.get(key);
+ if (value instanceof List>) {
+ return (List) settings.get(key);
+ } else {
+ return ImmutableList.of(value.toString());
+ }
+ } else {
+ return new ArrayList<>();
}
}
@@ -283,8 +267,7 @@ public List getStringList(String key)
*
* @return scaled setting value
*/
- public double getAttr(String key, int level)
- {
+ public double getAttr(String key, int level) {
return getAttr(key, level, 0);
}
@@ -299,10 +282,8 @@ public double getAttr(String key, int level)
*
* @return scaled setting value
*/
- public double getAttr(String key, int level, double defaultValue)
- {
- if (!has(key))
- {
+ public double getAttr(String key, int level, double defaultValue) {
+ if (!has(key)) {
set(key, defaultValue, 0);
return defaultValue;
}
@@ -317,14 +298,10 @@ public double getAttr(String key, int level, double defaultValue)
*
* @return base value
*/
- public double getBase(String key)
- {
- if (!settings.containsKey(key + BASE))
- {
+ public double getBase(String key) {
+ if (!settings.containsKey(key + BASE)) {
return 0;
- }
- else
- {
+ } else {
return NumberParser.parseDouble(settings.get(key + BASE).toString());
}
}
@@ -337,14 +314,10 @@ public double getBase(String key)
*
* @return change in value per level
*/
- public double getScale(String key)
- {
- if (!settings.containsKey(key + SCALE))
- {
+ public double getScale(String key) {
+ if (!settings.containsKey(key + SCALE)) {
return 0;
- }
- else
- {
+ } else {
return NumberParser.parseDouble(settings.get(key + SCALE).toString());
}
}
@@ -358,18 +331,12 @@ public double getScale(String key)
*
* @return attribute value or 0 if not found
*/
- public Object getObj(String key, int level)
- {
- if (settings.containsKey(key))
- {
+ public Object getObj(String key, int level) {
+ if (settings.containsKey(key)) {
return settings.get(key);
- }
- else if (settings.containsKey(key + BASE))
- {
+ } else if (settings.containsKey(key + BASE)) {
return getAttr(key, level);
- }
- else
- {
+ } else {
return 0;
}
}
@@ -383,8 +350,7 @@ else if (settings.containsKey(key + BASE))
*
* @return true if defined, false otherwise
*/
- public boolean has(String key)
- {
+ public boolean has(String key) {
return settings.containsKey(key) || settings.containsKey(key + BASE);
}
@@ -394,8 +360,7 @@ public boolean has(String key)
*
* @param key name of the attribute
*/
- public void remove(String key)
- {
+ public void remove(String key) {
settings.remove(key);
settings.remove(key + BASE);
settings.remove(key + SCALE);
@@ -411,10 +376,8 @@ public void remove(String key)
* @param defaultBase default base value
* @param defaultScale default scale value
*/
- public void checkDefault(String key, double defaultBase, double defaultScale)
- {
- if (!has(key))
- {
+ public void checkDefault(String key, double defaultBase, double defaultScale) {
+ if (!has(key)) {
set(key, defaultBase, defaultScale);
}
}
@@ -425,14 +388,11 @@ public void checkDefault(String key, double defaultBase, double defaultScale)
*
* @param config configuration section to save to
*/
- public void save(DataSection config)
- {
- if (config == null)
- {
+ public void save(DataSection config) {
+ if (config == null) {
return;
}
- for (String key : settings.keySet())
- {
+ for (String key : settings.keySet()) {
config.set(key, settings.get(key));
}
}
@@ -448,15 +408,12 @@ public void save(DataSection config)
*
* @param config configuration section to load from
*/
- public void load(DataSection config)
- {
- if (config == null)
- {
+ public void load(DataSection config) {
+ if (config == null) {
return;
}
- for (String key : config.keys())
- {
+ for (String key : config.keys()) {
settings.put(key, config.get(key));
}
}
@@ -464,11 +421,9 @@ public void load(DataSection config)
/**
* Dumps the settings to the console for debugging purposes
*/
- public void dumpToConsole()
- {
+ public void dumpToConsole() {
Logger.log("Settings:");
- for (String key : settings.keySet())
- {
+ for (String key : settings.keySet()) {
Logger.log("- " + key + ": " + settings.get(key).toString());
}
}
diff --git a/src/com/sucy/skill/api/SkillPlugin.java b/src/com/sucy/skill/api/SkillPlugin.java
index 535caabd..d3a7fc5f 100644
--- a/src/com/sucy/skill/api/SkillPlugin.java
+++ b/src/com/sucy/skill/api/SkillPlugin.java
@@ -26,7 +26,12 @@
*/
package com.sucy.skill.api;
+import com.google.common.collect.ImmutableList;
import com.sucy.skill.SkillAPI;
+import com.sucy.skill.dynamic.custom.CustomEffectComponent;
+import com.sucy.skill.dynamic.trigger.Trigger;
+
+import java.util.List;
/**
*
Interface for plugins that define new classes and skills
@@ -34,8 +39,7 @@
* (e.g. adding classes in the registerClasses method and skills
* in the registerSkills method). It keeps the API working nicely!
*/
-public interface SkillPlugin
-{
+public interface SkillPlugin {
/**
*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.sucy.skill.api.particle;
+
+import com.sucy.skill.api.Settings;
+import com.sucy.skill.api.particle.direction.Directions;
+import com.sucy.skill.api.particle.target.EffectTarget;
+import com.sucy.skill.log.Logger;
+import org.bukkit.Material;
+
+/**
+ * Handles playing effects based on configuration settings
+ */
+public class EffectPlayer
+{
+ public static final String SHAPE = "-shape";
+ public static final String SHAPE_DIR = "-shape-dir";
+ public static final String SHAPE_SIZE = "-shape-size";
+ public static final String ANIMATION = "-animation";
+ public static final String ANIM_DIR = "-anim-dir";
+ public static final String ANIM_SIZE = "-anim-size";
+ public static final String INTERVAL = "-interval";
+ public static final String VIEW_RANGE = "-view-range";
+
+ public static final String P_TYPE = "-particle-type";
+ public static final String MAT = "-particle-material";
+ public static final String DATA = "-particle-data";
+ public static final String AMOUNT = "-particle-amount";
+ public static final String DX = "-particle-dx";
+ public static final String DY = "-particle-dy";
+ public static final String DZ = "-particle-dz";
+ public static final String SPEED = "-particle-speed";
+
+ private Settings settings;
+
+ /**
+ * Sets up an effect player that applies effects based of the values in the provided settings.
+ * All of the available settings are provided as static values in this class.
+ *
+ * @param settings settings to read from
+ */
+ public EffectPlayer(Settings settings)
+ {
+ this.settings = settings;
+ }
+
+ /**
+ * Plays a particle effect, grabbing values from the settings data
+ *
+ * @param target target to play for
+ * @param key effect key to use
+ * @param ticks duration of effect in ticks
+ * @param level level of the effect
+ */
+ public void start(EffectTarget target, String key, int ticks, int level)
+ {
+ start(target, key, ticks, level, false);
+ }
+
+ /**
+ * Plays a particle effect, grabbing values from the settings data
+ *
+ * @param target target to play for
+ * @param key effect key to use
+ * @param ticks duration of effect in ticks
+ * @param level level of the effect
+ * @param noPrefix exclude prefix when grabbing settings
+ */
+ public void start(EffectTarget target, String key, int ticks, int level, boolean noPrefix)
+ {
+ // If the effect is already running, just refresh it
+ EffectInstance instance = EffectManager.getEffect(target, key);
+ if (instance != null)
+ {
+ instance.extend(ticks);
+ return;
+ }
+
+ // If the effect is not registered, make it
+ if (EffectManager.getEffect(key) == null)
+ makeEffect(key, noPrefix);
+
+ // Play the effect
+ EffectManager.runEffect(EffectManager.getEffect(key), target, ticks, level);
+ }
+
+ /**
+ * Creates and registers an effect
+ *
+ * @param key effect key
+ * @param noPrefix exclude prefix when grabbing settings
+ */
+ private void makeEffect(String key, boolean noPrefix)
+ {
+ String keyMod = noPrefix ? "" : key;
+
+ // Grab the particle type
+ ParticleType particleType = ParticleLookup.find(settings.getString(keyMod + P_TYPE, "SPELL"));
+ ParticleSettings particle;
+
+ // Block Crack and the related use materials
+ if (particleType.usesMat())
+ {
+ try
+ {
+ particle = new ParticleSettings(
+ particleType,
+ (float) settings.getDouble(keyMod + DX),
+ (float) settings.getDouble(keyMod + DY),
+ (float) settings.getDouble(keyMod + DZ),
+ (float) settings.getDouble(keyMod + SPEED, 1),
+ settings.getInt(keyMod + AMOUNT, 1),
+ Material.matchMaterial(settings.getString(keyMod + MAT, "DIRT")),
+ settings.getInt(keyMod + DATA)
+ );
+ }
+ catch (Exception ex)
+ {
+ Logger.invalid("Bad material for particle effect - " + settings.getString(keyMod + MAT));
+ return;
+ }
+ }
+
+ // Others just use basic data
+ else
+ particle = new ParticleSettings(
+ particleType,
+ (float) settings.getDouble(keyMod + DX),
+ (float) settings.getDouble(keyMod + DY),
+ (float) settings.getDouble(keyMod + DZ),
+ (float) settings.getDouble(keyMod + SPEED, 1),
+ settings.getInt(keyMod + AMOUNT, 1)
+ );
+
+ // Make the effect
+ ParticleEffect effect = new ParticleEffect(
+ key,
+ EffectManager.getFormula(settings.getString(keyMod + SHAPE, "single")),
+ EffectManager.getFormula(settings.getString(keyMod + ANIMATION, "single")),
+ particle,
+ Directions.byName(settings.getString(keyMod + SHAPE_DIR, "XZ")),
+ Directions.byName(settings.getString(keyMod + ANIM_DIR, "XZ")),
+ settings.getString(keyMod + SHAPE_SIZE, "1"),
+ settings.getString(keyMod + ANIM_SIZE, "1"),
+ settings.getInt(keyMod + INTERVAL, 1),
+ settings.getInt(keyMod + VIEW_RANGE, 25)
+ );
+
+ // Register the effect
+ EffectManager.register(effect);
+ }
+}
diff --git a/src/com/sucy/skill/api/particle/Particle.java b/src/com/sucy/skill/api/particle/Particle.java
new file mode 100644
index 00000000..ceb0cffb
--- /dev/null
+++ b/src/com/sucy/skill/api/particle/Particle.java
@@ -0,0 +1,300 @@
+/**
+ * SkillAPI
+ * com.sucy.skill.api.particle.Particle
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Steven Sucy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.sucy.skill.api.particle;
+
+import com.rit.sucy.version.VersionManager;
+import org.bukkit.Bukkit;
+import org.bukkit.Color;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Simplified particle utility compared to MCCore's
+ */
+public class Particle {
+ private static Constructor> packet;
+
+ private static Method toNms;
+ private static Method getHandle;
+ private static Method sendPacket;
+
+ private static Field connection;
+
+ private static HashMap particleTypes = new HashMap<>();
+
+ /**
+ * Initializes the SkillAPI particle utility
+ */
+ public static void init() {
+ try {
+ String version = Bukkit.getServer().getClass().getPackage().getName().substring(23);
+ String nms = "net.minecraft.server." + version + '.';
+ String craft = "org.bukkit.craftbukkit." + version + '.';
+ getHandle = Class.forName(craft + "entity.CraftPlayer").getMethod("getHandle");
+ connection = Class.forName(nms + "EntityPlayer").getDeclaredField("playerConnection");
+ sendPacket = Class.forName(nms + "PlayerConnection")
+ .getDeclaredMethod("sendPacket", Class.forName(nms + "Packet"));
+
+ Class> packetClass;
+ // 1.13+ Servers
+ Class> particleEnum;
+ if (VersionManager.isVersionAtLeast(11300)) {
+ Class> craftParticle = Class.forName(craft + "CraftParticle");
+ toNms = craftParticle.getDeclaredMethod("toNMS", org.bukkit.Particle.class, Object.class);
+ particleEnum = Class.forName(nms + "ParticleParam");
+ packetClass = Class.forName(nms + "PacketPlayOutWorldParticles");
+ packet = packetClass.getConstructor(
+ particleEnum,
+ boolean.class,
+ float.class,
+ float.class,
+ float.class,
+ float.class,
+ float.class,
+ float.class,
+ float.class,
+ int.class);
+ }
+
+ // 1.8+ servers
+ else if (VersionManager.isVersionAtLeast(VersionManager.V1_8_0)) {
+ particleEnum = Class.forName(nms + "EnumParticle");
+ for (Object value : particleEnum.getEnumConstants()) { particleTypes.put(value.toString(), value); }
+ packetClass = Class.forName(nms + "PacketPlayOutWorldParticles");
+ packet = packetClass.getConstructor(
+ particleEnum,
+ Boolean.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Integer.TYPE,
+ int[].class);
+ }
+
+ // 1.7.x servers
+ else {
+ packetClass = Class.forName(nms + "PacketPlayOutWorldParticles");
+ packet = packetClass.getConstructor(
+ String.class,
+ Boolean.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Float.TYPE,
+ Integer.TYPE);
+ }
+ } catch (Exception ex) {
+ System.out.println("Failed to set up particles, are you using Cauldron?");
+ }
+ }
+
+ /**
+ * Sends a list of packets to a player
+ *
+ * @param player player to send to
+ * @param packets packets to send
+ *
+ * @throws Exception
+ */
+ public static void send(Player player, List
*/
-public final class PlayerClass
+public class PlayerClass
{
private PlayerData player;
private RPGClass classData;
@@ -307,7 +308,22 @@ public void setPoints(int amount)
* @param amount amount of experience to give
* @param source type of the source of the experience
*/
- public void giveExp(double amount, ExpSource source)
+ public void giveExp(double amount, ExpSource source) {
+ giveExp(amount, source, true);
+ }
+
+ /**
+ *
Gives experience to the class under the context of the experience source.
+ *
This will also check for leveling up after the experience is added.
+ *
If the class does not normally receive experience from the source,
+ * it will still launch an experience event, just it will start off as
+ * cancelled in case it should still be given in select circumstances.
+ *
+ * @param amount amount of experience to give
+ * @param source type of the source of the experience
+ * @param showMessage whether or not to show the configured message if enabled
+ */
+ public void giveExp(double amount, ExpSource source, boolean showMessage)
{
// Cannot give a non-positive amount of exp
if (amount <= 0 || level >= classData.getMaxLevel())
@@ -320,22 +336,24 @@ public void giveExp(double amount, ExpSource source)
event.setCancelled(!classData.receivesExp(source));
Bukkit.getPluginManager().callEvent(event);
+ int rounded = (int)Math.ceil(event.getExp());
+
// Add experience if not cancelled
- if (!event.isCancelled() && event.getExp() > 0)
+ if (!event.isCancelled() && rounded > 0)
{
- if (SkillAPI.getSettings().isShowExpMessages() && player.getPlayer() != null)
+ if (showMessage && SkillAPI.getSettings().isShowExpMessages() && player.getPlayer() != null)
{
TitleManager.show(
player.getPlayer(),
TitleType.EXP_GAINED,
NotificationNodes.EXP,
- RPGFilter.EXP.setReplacement(amount + ""),
+ RPGFilter.EXP.setReplacement(rounded + ""),
RPGFilter.CLASS.setReplacement(classData.getName()),
- Filter.AMOUNT.setReplacement(amount + "")
+ Filter.AMOUNT.setReplacement(rounded + "")
);
}
- exp += amount;
+ exp += rounded;
checkLevelUp();
}
}
@@ -396,12 +414,7 @@ private void checkLevelUp()
{
giveLevels(levels);
- // Level up effect
- if (SkillAPI.getSettings().hasLevelUpEffect())
- {
- DynamicSkill skill = SkillAPI.getSettings().getLevelUpSkill();
- skill.cast(player.getPlayer(), level);
- }
+ // Level up message
if (SkillAPI.getSettings().isShowLevelMessages())
{
TitleManager.show(
@@ -442,12 +455,23 @@ public void giveLevels(int amount)
getPlayerData().giveAttribPoints(classData.getGroupSettings().getAttribsForLevels(level, level - amount));
// Update health/mana
- getPlayerData().updateHealthAndMana(getPlayerData().getPlayer());
+ final Player player = getPlayerData().getPlayer();
+ if (player != null) {
+ getPlayerData().updateHealthAndMana(getPlayerData().getPlayer());
+ getPlayerData().getEquips().update(getPlayerData().getPlayer());
+ }
getPlayerData().autoLevel();
// Call the event
PlayerLevelUpEvent event = new PlayerLevelUpEvent(this, amount);
Bukkit.getPluginManager().callEvent(event);
+
+ // Apply the effect
+ if (SkillAPI.getSettings().hasLevelUpEffect())
+ {
+ DynamicSkill skill = SkillAPI.getSettings().getLevelUpSkill();
+ skill.cast(player, level);
+ }
}
/**
diff --git a/src/com/sucy/skill/api/player/PlayerCombos.java b/src/com/sucy/skill/api/player/PlayerCombos.java
index 1a1f0e7c..8f4bf89d 100644
--- a/src/com/sucy/skill/api/player/PlayerCombos.java
+++ b/src/com/sucy/skill/api/player/PlayerCombos.java
@@ -42,10 +42,9 @@
* Represents the click combos available for a player to use along
* with their current click pattern
*/
-public class PlayerCombos
-{
- private HashMap skills = new HashMap();
- private HashMap reverse = new HashMap();
+public class PlayerCombos {
+ private HashMap skills = new HashMap<>();
+ private HashMap reverse = new HashMap<>();
private PlayerData player;
private Click[] clicks;
@@ -57,8 +56,7 @@ public class PlayerCombos
*
* @param data owning player's data
*/
- public PlayerCombos(PlayerData data)
- {
+ public PlayerCombos(PlayerData data) {
this.player = data;
this.clickIndex = 0;
this.clicks = new Click[SkillAPI.getComboManager().getComboSize()];
@@ -72,8 +70,7 @@ public PlayerCombos(PlayerData data)
*
* @return current number of clicks in the active combo
*/
- public int getComboCount()
- {
+ public int getComboCount() {
return clickIndex;
}
@@ -82,8 +79,7 @@ public int getComboCount()
*
* @return map of combo IDs to skills
*/
- public HashMap getSkillMap()
- {
+ public HashMap getSkillMap() {
return skills;
}
@@ -92,8 +88,7 @@ public HashMap getSkillMap()
*
* @return owning player's data
*/
- public PlayerData getPlayerData()
- {
+ public PlayerData getPlayerData() {
return player;
}
@@ -105,18 +100,15 @@ public PlayerData getPlayerData()
*
* @return skill name bound to the ID or null if none
*/
- public String getSkillName(int id)
- {
+ public String getSkillName(int id) {
return skills.get(id);
}
-
/**
* Clears the player's current click combo, causing them
* to not count their recent clicks towards a combo
*/
- public void clearCombo()
- {
+ public void clearCombo() {
clickIndex = 0;
}
@@ -126,10 +118,9 @@ public void clearCombo()
*
* @param click click to apply for the player
*/
- public void applyClick(Click click)
- {
+ public void applyClick(Click click) {
// Don't count disabled clicks
- if (!SkillAPI.getComboManager().isClickEnabled(click.getId())) return;
+ if (!SkillAPI.getComboManager().isClickEnabled(click.getId())) { return; }
checkExpired();
@@ -139,13 +130,11 @@ public void applyClick(Click click)
// Cast skill when combo is completed
int id = SkillAPI.getComboManager().convertCombo(clicks, clickIndex);
- if (clickIndex == clicks.length || skills.containsKey(id))
- {
+ if (clickIndex == clicks.length || skills.containsKey(id)) {
PlayerComboFinishEvent event = new PlayerComboFinishEvent(player, id, skills.get(id));
Bukkit.getPluginManager().callEvent(event);
- if (skills.containsKey(id) && !event.isCancelled())
- {
+ if (skills.containsKey(id) && !event.isCancelled()) {
player.cast(skills.get(id));
}
}
@@ -154,12 +143,10 @@ public void applyClick(Click click)
/**
* Checks for when the combo times out
*/
- private void checkExpired()
- {
+ private void checkExpired() {
// Reset combo if too much time passed
if (clickIndex == clicks.length
- || System.currentTimeMillis() - clickTime > SkillAPI.getSettings().getClickTime())
- {
+ || System.currentTimeMillis() - clickTime > SkillAPI.getSettings().getClickTime()) {
clearCombo();
}
}
@@ -169,24 +156,18 @@ private void checkExpired()
*
* @return current combo string
*/
- public String getCurrentComboString()
- {
- if (clickIndex == 0) return "";
- else if (clickIndex == clicks.length)
- {
- int id = SkillAPI.getComboManager().convertCombo(clicks);
- if (skills.containsKey(id))
- {
- return skills.get(id);
- }
- else return "";
+ public String getCurrentComboString() {
+ if (clickIndex == 0) { return ""; } else if (clickIndex == clicks.length) {
+ final int id = SkillAPI.getComboManager().convertCombo(clicks);
+ if (skills.containsKey(id)) {
+ return SkillAPI.getSkill(skills.get(id)).getName();
+ } else { return ""; }
}
checkExpired();
- ArrayList active = new ArrayList(clickIndex);
- for (int i = 0; i < clickIndex; i++)
- {
+ ArrayList active = new ArrayList<>(clickIndex);
+ for (int i = 0; i < clickIndex; i++) {
active.add(clicks[i]);
}
return SkillAPI.getComboManager().getComboString(active);
@@ -200,8 +181,7 @@ else if (clickIndex == clicks.length)
*
* @return true if conflict, false otherwise
*/
- public boolean hasConflict(int id)
- {
+ public boolean hasConflict(int id) {
return getConflicts(id).size() > 0;
}
@@ -213,14 +193,11 @@ public boolean hasConflict(int id)
*
* @return ID of conflict or -1 if no conflict
*/
- public List getConflicts(int id)
- {
+ public List getConflicts(int id) {
ComboManager cm = SkillAPI.getComboManager();
- List conflicts = new ArrayList();
- for (int taken : skills.keySet())
- {
- if (cm.conflicts(id, taken))
- conflicts.add(taken);
+ List conflicts = new ArrayList<>();
+ for (int taken : skills.keySet()) {
+ if (cm.conflicts(id, taken)) { conflicts.add(taken); }
}
return conflicts;
}
@@ -231,31 +208,28 @@ public List getConflicts(int id)
*
* @param skill skill to add
*/
- public void addSkill(Skill skill)
- {
- if (skill == null || !skill.canCast()) return;
+ public void addSkill(Skill skill) {
+ if (skill == null || !skill.canCast() || !SkillAPI.getSettings().isCombosEnabled()) { return; }
// Can't already be added
- if (skill.hasCombo())
- {
+ if (skill.hasCombo()) {
setSkill(skill, skill.getCombo());
return;
+ } else if (!SkillAPI.getSettings().shouldAutoAssignCombos()) {
+ return;
}
// Get next available combo
ComboManager cm = SkillAPI.getComboManager();
int combo = 1 << (Click.BITS * (cm.getComboSize() - 1));
int max = (1 << (Click.BITS * cm.getComboSize())) - 1;
- while (combo <= max && (!cm.isValidDefaultCombo(combo) || hasConflict(combo)))
- combo++;
+ while (combo <= max && (!cm.isValidDefaultCombo(combo) || hasConflict(combo))) { combo++; }
// Add it if valid
- if (combo <= max)
- {
+ if (combo <= max) {
skills.put(combo, skill.getName().toLowerCase());
reverse.put(skill.getName(), combo);
- }
- else Logger.invalid("Failed to assign combo for " + skill.getName() + " - no remaining combos");
+ } else { Logger.invalid("Failed to assign combo for " + skill.getName() + " - no remaining combos"); }
}
/**
@@ -263,9 +237,8 @@ public void addSkill(Skill skill)
*
* @param skill skill to remove
*/
- public void removeSkill(Skill skill)
- {
- if (skill == null || !reverse.containsKey(skill.getName())) return;
+ public void removeSkill(Skill skill) {
+ if (skill == null || !reverse.containsKey(skill.getName())) { return; }
skills.remove(reverse.remove(skill.getName()));
}
@@ -277,8 +250,7 @@ public void removeSkill(Skill skill)
*
* @return true if active, false otherwise
*/
- public boolean isComboUsed(int id)
- {
+ public boolean isComboUsed(int id) {
return skills.containsKey(id);
}
@@ -289,8 +261,7 @@ public boolean isComboUsed(int id)
*
* @return true if valid, false otherwise
*/
- public boolean isValidCombo(int id)
- {
+ public boolean isValidCombo(int id) {
return SkillAPI.getComboManager().isValidCombo(id);
}
@@ -301,8 +272,7 @@ public boolean isValidCombo(int id)
*
* @return true if has a combo, false otherwise
*/
- public boolean hasCombo(Skill skill)
- {
+ public boolean hasCombo(Skill skill) {
return reverse.containsKey(skill.getName());
}
@@ -317,18 +287,14 @@ public boolean hasCombo(Skill skill)
*
* @return true if set successfully, false otherwise
*/
- public boolean setSkill(Skill skill, int id)
- {
- if (skill == null || !skill.canCast() || !isValidCombo(id)) return false;
+ public boolean setSkill(Skill skill, int id) {
+ if (skill == null || !skill.canCast() || !isValidCombo(id)) { return false; }
removeSkill(skill);
List conflicts = getConflicts(id);
- if (conflicts.size() > 0)
- {
- for (int conflict : conflicts)
- {
- if (conflict == id)
- {
+ if (conflicts.size() > 0) {
+ for (int conflict : conflicts) {
+ if (conflict == id) {
Skill old = SkillAPI.getSkill(skills.get(conflict));
old.clearCombo();
addSkill(old);
@@ -336,19 +302,15 @@ public boolean setSkill(Skill skill, int id)
}
skills.put(id, skill.getName().toLowerCase());
reverse.put(skill.getName(), id);
- for (int conflict : conflicts)
- {
- if (conflict != id)
- {
+ for (int conflict : conflicts) {
+ if (conflict != id) {
Skill old = SkillAPI.getSkill(skills.get(conflict));
old.clearCombo();
addSkill(old);
reverse.remove(skills.remove(conflict));
}
}
- }
- else
- {
+ } else {
skills.put(id, skill.getName().toLowerCase());
reverse.put(skill.getName(), id);
}
@@ -363,8 +325,7 @@ public boolean setSkill(Skill skill, int id)
*
* @return combo string
*/
- public String getComboString(Skill skill)
- {
+ public String getComboString(Skill skill) {
int combo = reverse.get(skill.getName());
return SkillAPI.getComboManager().getComboString(combo);
}
diff --git a/src/com/sucy/skill/api/player/PlayerData.java b/src/com/sucy/skill/api/player/PlayerData.java
index 523e9fe7..687f6b54 100644
--- a/src/com/sucy/skill/api/player/PlayerData.java
+++ b/src/com/sucy/skill/api/player/PlayerData.java
@@ -28,9 +28,10 @@
import com.rit.sucy.config.Filter;
import com.rit.sucy.config.FilterType;
-import com.rit.sucy.items.InventoryManager;
+import com.rit.sucy.config.parse.DataSection;
import com.rit.sucy.player.TargetHelper;
import com.rit.sucy.version.VersionManager;
+import com.rit.sucy.version.VersionPlayer;
import com.sucy.skill.SkillAPI;
import com.sucy.skill.api.classes.RPGClass;
import com.sucy.skill.api.enums.*;
@@ -39,50 +40,56 @@
import com.sucy.skill.api.skills.Skill;
import com.sucy.skill.api.skills.SkillShot;
import com.sucy.skill.api.skills.TargetSkill;
+import com.sucy.skill.cast.PlayerCastBars;
import com.sucy.skill.data.GroupSettings;
-import com.sucy.skill.data.Permissions;
+import com.sucy.skill.data.PlayerEquips;
import com.sucy.skill.dynamic.EffectComponent;
+import com.sucy.skill.gui.handlers.AttributeHandler;
+import com.sucy.skill.gui.handlers.DetailsHandler;
+import com.sucy.skill.gui.handlers.ProfessHandler;
+import com.sucy.skill.gui.handlers.SkillHandler;
+import com.sucy.skill.gui.tool.GUITool;
import com.sucy.skill.language.ErrorNodes;
import com.sucy.skill.language.GUINodes;
import com.sucy.skill.language.RPGFilter;
import com.sucy.skill.listener.AttributeListener;
-import com.sucy.skill.listener.TreeListener;
import com.sucy.skill.log.LogType;
import com.sucy.skill.log.Logger;
import com.sucy.skill.manager.AttributeManager;
-import com.sucy.skill.task.InventoryTask;
import com.sucy.skill.task.ScoreboardTask;
-import com.sucy.skill.tree.basic.InventoryTree;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeInstance;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
-import org.bukkit.inventory.Inventory;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
+
+import static com.sucy.skill.api.event.PlayerSkillCastFailedEvent.Cause.*;
/**
* Represents one account for a player which can contain one class from each group
* and the skills in each of those classes. You should not instantiate this class
* yourself and instead get it from the SkillAPI static methods.
+ *
+ * In order to get a player's data, use "SkillAPI.getPlayerData(...)". Do NOT
+ * try to instantaite your own PlayerData object.
*/
-public final class PlayerData
-{
- private final HashMap classes = new HashMap();
- private final HashMap skills = new HashMap();
- private final HashMap binds = new HashMap();
- private final HashMap attributes = new HashMap();
- private final HashMap bonusAttrib = new HashMap();
-
+public class PlayerData {
+ private final HashMap classes = new HashMap<>();
+ private final HashMap skills = new HashMap<>();
+ private final HashMap binds = new HashMap<>();
+ private final HashMap attributes = new HashMap<>();
+ private final HashMap bonusAttrib = new HashMap<>();
+
+ private DataSection extraData = new DataSection();
private OfflinePlayer player;
private PlayerSkillBar skillBar;
+ private PlayerCastBars castBars;
private PlayerCombos combos;
+ private PlayerEquips equips;
private String scheme;
private String menuClass;
private double mana;
@@ -90,29 +97,31 @@ public final class PlayerData
private double bonusHealth;
private double bonusMana;
private double lastHealth;
+ private double hunger;
private boolean init;
private boolean passive;
private int attribPoints;
+ private long skillTimer;
/**
* Initializes a new account data representation for a player.
*
* @param player player to store the data for
*/
- public PlayerData(OfflinePlayer player, boolean init)
- {
+ PlayerData(OfflinePlayer player, boolean init) {
this.player = player;
this.skillBar = new PlayerSkillBar(this);
+ this.castBars = new PlayerCastBars(this);
this.combos = new PlayerCombos(this);
+ this.equips = new PlayerEquips(this);
this.init = SkillAPI.isLoaded() && init;
this.scheme = "default";
- for (String group : SkillAPI.getGroups())
- {
+ this.hunger = 1;
+ for (String group : SkillAPI.getGroups()) {
GroupSettings settings = SkillAPI.getSettings().getGroupSettings(group);
RPGClass rpgClass = settings.getDefault();
- if (rpgClass != null && settings.getPermission() == null)
- {
+ if (rpgClass != null && settings.getPermission() == null) {
setClass(rpgClass);
}
}
@@ -123,9 +132,8 @@ public PlayerData(OfflinePlayer player, boolean init)
*
* @return Bukkit player object of the owner or null if offline
*/
- public Player getPlayer()
- {
- return player.getPlayer();
+ public Player getPlayer() {
+ return new VersionPlayer(player).getPlayer();
}
/**
@@ -133,36 +141,57 @@ public Player getPlayer()
*
* @return name of the owner
*/
- public String getPlayerName()
- {
+ public String getPlayerName() {
return player.getName();
}
+ public UUID getUUID() {
+ return player.getUniqueId();
+ }
+
/**
* Retrieves the skill bar data for the owner
*
* @return skill bar data of the owner
*/
- public PlayerSkillBar getSkillBar()
- {
+ public PlayerSkillBar getSkillBar() {
return skillBar;
}
+ /**
+ * @return cast bars data for the player
+ */
+ public PlayerCastBars getCastBars() {
+ return castBars;
+ }
+
/**
* Returns the data for the player's combos
*
* @return combo data for the player
*/
- public PlayerCombos getComboData()
- {
+ public PlayerCombos getComboData() {
return combos;
}
+ /**
+ * @return extra data attached to the player's account
+ */
+ public DataSection getExtraData() {
+ return extraData;
+ }
+
+ /**
+ * @return equipped item data
+ */
+ public PlayerEquips getEquips() {
+ return equips;
+ }
+
/**
* @return health during last logout
*/
- public double getLastHealth()
- {
+ public double getLastHealth() {
return lastHealth;
}
@@ -171,18 +200,43 @@ public double getLastHealth()
*
* @param health health logged off with
*/
- public void setLastHealth(double health)
- {
+ public void setLastHealth(double health) {
lastHealth = health;
}
+ /**
+ * The hunger value here is not representative of the player's total hunger,
+ * rather the amount left of the next hunger point. This is manipulated by
+ * attributes were if an attribute says a player has twice as much "hunger"
+ * as normal, this will go down by decimals to slow the decay of hunger.
+ *
+ * @return amount of the next hunger point the player has
+ */
+ public double getHungerValue() {
+ return hunger;
+ }
+
+ /**
+ * @param hungerValue new hunger value
+ * @see PlayerData#getHungerValue
+ */
+ public void setHungerValue(final double hungerValue) {
+ this.hunger = hungerValue;
+ }
+
+ public int subtractHungerValue(final double amount) {
+ final double scaled = amount / scaleStat(AttributeManager.HUNGER, amount);
+ final int lost = scaled >= hunger ? (int) (scaled - hunger) + 1 : 0;
+ this.hunger += lost - amount;
+ return lost;
+ }
+
/**
* Ends the initialization flag for the data. Used by the
* API to avoid async issues. Do not use this in other
* plugins.
*/
- public void endInit()
- {
+ public void endInit() {
init = false;
}
@@ -191,8 +245,7 @@ public void endInit()
*
* @return map menu scheme name
*/
- public String getScheme()
- {
+ public String getScheme() {
return scheme;
}
@@ -201,8 +254,7 @@ public String getScheme()
*
* @param name name of the scheme
*/
- public void setScheme(String name)
- {
+ public void setScheme(String name) {
scheme = name;
}
@@ -218,11 +270,9 @@ public void setScheme(String name)
*
* @return attribute totals
*/
- public HashMap getAttributes()
- {
- HashMap map = new HashMap();
- for (String key : SkillAPI.getAttributeManager().getKeys())
- map.put(key, getAttribute(key));
+ public HashMap getAttributes() {
+ HashMap map = new HashMap<>();
+ for (String key : SkillAPI.getAttributeManager().getKeys()) { map.put(key, getAttribute(key)); }
return map;
}
@@ -234,9 +284,8 @@ public HashMap getAttributes()
*
* @return attribute totals
*/
- public HashMap getInvestedAttributes()
- {
- return new HashMap(attributes);
+ public HashMap getInvestedAttributes() {
+ return new HashMap<>(attributes);
}
/**
@@ -247,17 +296,15 @@ public HashMap getInvestedAttributes()
*
* @return number of total points
*/
- public int getAttribute(String key)
- {
+ public int getAttribute(String key) {
key = key.toLowerCase();
int total = 0;
- if (attributes.containsKey(key))
- total += attributes.get(key);
- if (bonusAttrib.containsKey(key))
- total += bonusAttrib.get(key);
- for (PlayerClass playerClass : classes.values())
+ if (attributes.containsKey(key)) { total += attributes.get(key); }
+ if (bonusAttrib.containsKey(key)) { total += bonusAttrib.get(key); }
+ for (PlayerClass playerClass : classes.values()) {
total += playerClass.getData().getAttribute(key, playerClass.getLevel());
- return total;
+ }
+ return Math.max(0, total);
}
/**
@@ -268,14 +315,8 @@ public int getAttribute(String key)
*
* @return number of invested points
*/
- public int getInvestedAttribute(String key)
- {
- key = key.toLowerCase();
- if (!attributes.containsKey(key))
- {
- return 0;
- }
- return attributes.get(key);
+ public int getInvestedAttribute(String key) {
+ return attributes.getOrDefault(key.toLowerCase(), 0);
}
/**
@@ -286,8 +327,7 @@ public int getInvestedAttribute(String key)
*
* @return true if any points are invested, false otherwise
*/
- public boolean hasAttribute(String key)
- {
+ public boolean hasAttribute(String key) {
return getAttribute(key) > 0;
}
@@ -297,25 +337,25 @@ public boolean hasAttribute(String key)
* has no remaining points, this will do nothing.
*
* @param key attribute key
+ *
+ * @return whether or not it was successfully upgraded
*/
- public void upAttribute(String key)
- {
+ public boolean upAttribute(String key) {
key = key.toLowerCase();
int current = getInvestedAttribute(key);
int max = SkillAPI.getAttributeManager().getAttribute(key).getMax();
- if (attribPoints > 0 && current < max)
- {
+ if (attribPoints > 0 && current < max) {
attributes.put(key, current + 1);
attribPoints--;
PlayerUpAttributeEvent event = new PlayerUpAttributeEvent(this, key);
Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- {
+ if (event.isCancelled()) {
attributes.put(key, current);
attribPoints++;
- }
+ } else { return true; }
}
+ return false;
}
/**
@@ -325,14 +365,12 @@ public void upAttribute(String key)
* @param key attribute to give points for
* @param amount amount to give
*/
- public void giveAttribute(String key, int amount)
- {
+ public void giveAttribute(String key, int amount) {
key = key.toLowerCase();
int current = getInvestedAttribute(key);
int max = SkillAPI.getAttributeManager().getAttribute(key).getMax();
amount = Math.min(amount + current, max);
- if (amount > current)
- {
+ if (amount > current) {
attributes.put(key, amount);
AttributeListener.updatePlayer(this);
}
@@ -345,12 +383,10 @@ public void giveAttribute(String key, int amount)
* @param key attribute key
* @param amount amount to add
*/
- public void addBonusAttributes(String key, int amount)
- {
- key = key.toLowerCase();
- if (bonusAttrib.containsKey(key))
- amount += bonusAttrib.get(key);
- bonusAttrib.put(key, Math.max(0, amount));
+ public void addBonusAttributes(String key, int amount) {
+ key = SkillAPI.getAttributeManager().normalize(key);
+ amount += bonusAttrib.getOrDefault(key, 0);
+ bonusAttrib.put(key, amount);
AttributeListener.updatePlayer(this);
}
@@ -361,28 +397,28 @@ public void addBonusAttributes(String key, int amount)
*
* @param key attribute key
*/
- public void refundAttribute(String key)
- {
+ public boolean refundAttribute(String key) {
key = key.toLowerCase();
int current = getInvestedAttribute(key);
- if (current > 0)
- {
+ if (current > 0) {
PlayerRefundAttributeEvent event = new PlayerRefundAttributeEvent(this, key);
Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled()) return;
+ if (event.isCancelled()) { return false; }
attribPoints += 1;
attributes.put(key, current - 1);
- if (current - 1 <= 0) attributes.remove(key);
+ if (current - 1 <= 0) { attributes.remove(key); }
AttributeListener.updatePlayer(this);
+
+ return true;
}
+ return false;
}
/**
* Refunds all spent attribute points for a specific attribute
*/
- public void refundAttributes(String key)
- {
+ public void refundAttributes(String key) {
key = key.toLowerCase();
attribPoints += getInvestedAttribute(key);
attributes.remove(key);
@@ -392,11 +428,9 @@ public void refundAttributes(String key)
/**
* Refunds all spent attribute points
*/
- public void refundAttributes()
- {
- ArrayList keys = new ArrayList(attributes.keySet());
- for (String key : keys)
- {
+ public void refundAttributes() {
+ ArrayList keys = new ArrayList<>(attributes.keySet());
+ for (String key : keys) {
refundAttributes(key);
}
}
@@ -406,8 +440,7 @@ public void refundAttributes()
*
* @return attribute point total
*/
- public int getAttributePoints()
- {
+ public int getAttributePoints() {
return attribPoints;
}
@@ -416,8 +449,7 @@ public int getAttributePoints()
*
* @param amount amount of attribute points
*/
- public void giveAttribPoints(int amount)
- {
+ public void giveAttribPoints(int amount) {
attribPoints += amount;
}
@@ -426,8 +458,7 @@ public void giveAttribPoints(int amount)
*
* @param amount amount of points to have
*/
- public void setAttribPoints(int amount)
- {
+ public void setAttribPoints(int amount) {
attribPoints = amount;
}
@@ -439,19 +470,21 @@ public void setAttribPoints(int amount)
*
* @return modified value
*/
- public double scaleStat(String stat, double value)
- {
- AttributeManager manager = SkillAPI.getAttributeManager();
- if (manager == null) return value;
- for (String key : manager.getKeys())
- {
- int amount = getAttribute(key);
- if (amount > 0)
- {
- value = manager.getAttribute(key).modifyStat(stat, value, amount);
+ public double scaleStat(final String stat, final double value) {
+ final AttributeManager manager = SkillAPI.getAttributeManager();
+ if (manager == null) { return value; }
+
+ final List matches = manager.forStat(stat);
+ if (matches == null) { return value; }
+
+ double modified = value;
+ for (final AttributeManager.Attribute attribute : matches) {
+ int amount = getAttribute(attribute.getKey());
+ if (amount > 0) {
+ modified = attribute.modifyStat(stat, modified, amount);
}
}
- return value;
+ return modified;
}
/**
@@ -460,67 +493,48 @@ public double scaleStat(String stat, double value)
* @param component component holding the value
* @param key key of the value
* @param value unmodified value
- * @param self whether or not the player is the target
*
* @return the modified value
*/
- public double scaleDynamic(EffectComponent component, String key, double value, boolean self)
- {
- AttributeManager manager = SkillAPI.getAttributeManager();
- if (manager == null) return value;
- for (String attr : manager.getKeys())
- {
- int amount = getAttribute(attr);
- if (amount > 0)
- {
- value = manager.getAttribute(attr).modify(component, key, self, value, amount);
+ public double scaleDynamic(EffectComponent component, String key, double value) {
+ final AttributeManager manager = SkillAPI.getAttributeManager();
+ if (manager == null) { return value; }
+
+ final List matches = manager.forComponent(component, key);
+ if (matches == null) { return value; }
+
+ for (final AttributeManager.Attribute attribute : matches) {
+ int amount = getAttribute(attribute.getKey());
+ if (amount > 0) {
+ value = attribute.modify(component, key, value, amount);
}
}
return value;
}
/**
- * Opens the attribute menu
+ * Opens the attribute menu for the player
+ *
+ * @return true if successfully opened, false if conditions weren't met
*/
- public void openAttributeMenu()
- {
+ public boolean openAttributeMenu() {
Player player = getPlayer();
- if (SkillAPI.getSettings().isAttributesEnabled() && player != null)
- {
- AttributeManager manager = SkillAPI.getAttributeManager();
- Inventory inv = InventoryManager.createInventory(
- AttributeListener.MENU_KEY,
- (manager.getKeys().size() + 8) / 9,
- SkillAPI.getLanguage().getMessage(
- GUINodes.ATTRIB_TITLE,
- true,
- FilterType.COLOR,
- RPGFilter.POINTS.setReplacement(attribPoints + ""),
- Filter.PLAYER.setReplacement(player.getName())
- ).get(0)
+ if (SkillAPI.getSettings().isAttributesEnabled() && player != null) {
+ GUITool.getAttributesMenu().show(
+ new AttributeHandler(),
+ this,
+ SkillAPI.getLanguage().getMessage(
+ GUINodes.ATTRIB_TITLE,
+ true,
+ FilterType.COLOR,
+ RPGFilter.POINTS.setReplacement(attribPoints + ""),
+ Filter.PLAYER.setReplacement(player.getName())
+ ).get(0),
+ SkillAPI.getAttributeManager().getAttributes()
);
- int i = 0;
- for (String key : manager.getKeys())
- {
- ItemStack icon = manager.getAttribute(key).getIcon().clone();
- ItemMeta meta = icon.getItemMeta();
- meta.setDisplayName(filter(meta.getDisplayName(), key));
- List lore = meta.getLore();
- for (int j = 0; j < lore.size(); j++)
- lore.set(j, filter(lore.get(j), key));
-
- icon.setItemMeta(meta);
- inv.setItem(i++, icon);
- }
- player.openInventory(inv);
+ return true;
}
- }
-
- private String filter(String text, String key)
- {
- return text
- .replace("{amount}", "" + getInvestedAttribute(key))
- .replace("{total}", "" + getAttribute(key));
+ return false;
}
/**
@@ -530,8 +544,7 @@ private String filter(String text, String key)
*
* @return the player's attribute data
*/
- public HashMap getAttributeData()
- {
+ public HashMap getAttributeData() {
return attributes;
}
@@ -550,8 +563,7 @@ public HashMap getAttributeData()
*
* @return true if has the skill, false otherwise
*/
- public boolean hasSkill(String name)
- {
+ public boolean hasSkill(String name) {
return name != null && skills.containsKey(name.toLowerCase());
}
@@ -562,13 +574,19 @@ public boolean hasSkill(String name)
*
* @return data for the skill or null if the player doesn't have the skill
*/
- public PlayerSkill getSkill(String name)
- {
- if (name == null)
- return null;
+ public PlayerSkill getSkill(String name) {
+ if (name == null) { return null; }
return skills.get(name.toLowerCase());
}
+ public int getInvestedSkillPoints() {
+ int total = 0;
+ for (PlayerSkill playerSkill : skills.values()) {
+ total += playerSkill.getInvestedCost();
+ }
+ return total;
+ }
+
/**
* Retrieves all of the skill data the player has. Modifying this
* collection will not modify the player's owned skills but modifying
@@ -576,8 +594,7 @@ public PlayerSkill getSkill(String name)
*
* @return collection of skill data for the owner
*/
- public Collection getSkills()
- {
+ public Collection getSkills() {
return skills.values();
}
@@ -588,8 +605,7 @@ public Collection getSkills()
*
* @return level of the skill or 0 if not found
*/
- public int getSkillLevel(String name)
- {
+ public int getSkillLevel(String name) {
PlayerSkill skill = getSkill(name);
return skill == null ? 0 : skill.getLevel();
}
@@ -600,8 +616,7 @@ public int getSkillLevel(String name)
*
* @param skill skill to give the player
*/
- public void giveSkill(Skill skill)
- {
+ public void giveSkill(Skill skill) {
giveSkill(skill, null);
}
@@ -612,11 +627,9 @@ public void giveSkill(Skill skill)
* @param skill skill to give the player
* @param parent parent class data
*/
- public void giveSkill(Skill skill, PlayerClass parent)
- {
+ public void giveSkill(Skill skill, PlayerClass parent) {
String key = skill.getKey();
- if (!skills.containsKey(key))
- {
+ if (!skills.containsKey(key)) {
PlayerSkill data = new PlayerSkill(this, skill, parent);
combos.addSkill(skill);
skills.put(key, data);
@@ -627,27 +640,29 @@ public void giveSkill(Skill skill, PlayerClass parent)
/**
* Attempts to auto-level any skills that are able to do so
*/
- public void autoLevel()
- {
- if (init) return;
+ public void autoLevel() {
+ if (init) { return; }
+
+ final Player player = getPlayer();
+ if (player == null) { return; }
- for (PlayerSkill skill : skills.values())
- {
- autoLevel(skill.getData());
+ for (PlayerSkill skill : skills.values()) {
+ if (skill.getData().isAllowed(player)) {
+ autoLevel(skill.getData());
+ }
}
}
- private void autoLevel(Skill skill)
- {
+ private void autoLevel(Skill skill) {
PlayerSkill data = skills.get(skill.getKey());
- if (data == null) return;
+ if (data == null || getPlayer() == null || !skill.isAllowed(getPlayer())) { return; }
int lastLevel = data.getLevel();
- while (data.getData().canAutoLevel() && !data.isMaxed() && data.getLevelReq() <= data.getPlayerClass().getLevel())
- {
+ while (data.getData().canAutoLevel(lastLevel)
+ && !data.isMaxed()
+ && data.getLevelReq() <= data.getPlayerClass().getLevel()) {
upgradeSkill(skill);
- if (lastLevel == data.getLevel())
- {
+ if (lastLevel == data.getLevel()) {
break;
}
lastLevel++;
@@ -664,77 +679,69 @@ private void autoLevel(Skill skill)
*
* @return true if successfully was upgraded, false otherwise
*/
- public boolean upgradeSkill(Skill skill)
- {
+ public boolean upgradeSkill(Skill skill) {
// Cannot be null
- if (skill == null)
- {
+ if (skill == null) {
return false;
}
// Must be a valid available skill
PlayerSkill data = skills.get(skill.getName().toLowerCase());
- if (data == null)
- {
+ if (data == null) {
return false;
}
// Must meet any skill requirements
- if (skill.getSkillReq() != null)
- {
- PlayerSkill req = skills.get(skill.getSkillReq().toLowerCase());
- if (req != null && req.getLevel() < skill.getSkillReqLevel())
- {
- return false;
- }
+ if (!skill.isCompatible(this) || !skill.hasInvestedEnough(this) || !skill.hasDependency(this)) {
+ return false;
}
int level = data.getPlayerClass().getLevel();
int points = data.getPlayerClass().getPoints();
int cost = data.getCost();
- if (!data.isMaxed() && level >= data.getLevelReq() && points >= cost)
- {
+ if (!data.isMaxed() && level >= data.getLevelReq() && points >= cost) {
// Upgrade event
PlayerSkillUpgradeEvent event = new PlayerSkillUpgradeEvent(this, data, cost);
Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- {
+ if (event.isCancelled()) {
return false;
}
// Apply upgrade
data.getPlayerClass().usePoints(cost);
- data.addLevels(1);
-
- // Passive calls
- if (passive)
- {
- Player player = getPlayer();
- if (player != null && skill instanceof PassiveSkill)
- {
- if (data.getLevel() == 1)
- {
- ((PassiveSkill) skill).initialize(player, data.getLevel());
- }
- else
- {
- ((PassiveSkill) skill).update(player, data.getLevel() - 1, data.getLevel());
- }
- }
+ forceUpSkill(data);
+
+ return true;
+ } else {
+ return false;
+ }
+ }
- // Unlock event
- if (data.getLevel() == 1)
- {
- Bukkit.getPluginManager().callEvent(new PlayerSkillUnlockEvent(this, data));
- this.autoLevel();
+ /**
+ * Forcefully upgrades a skill, not letting other plugins
+ * cancel it and ignoring any requirements to do so
+ *
+ * @param skill skill to forcefully upgrade
+ */
+ public void forceUpSkill(PlayerSkill skill) {
+ skill.addLevels(1);
+
+ // Passive calls
+ if (passive) {
+ Player player = getPlayer();
+ if (player != null && skill.getData() instanceof PassiveSkill) {
+ if (skill.getLevel() == 1) {
+ ((PassiveSkill) skill.getData()).initialize(player, skill.getLevel());
+ } else {
+ ((PassiveSkill) skill.getData()).update(player, skill.getLevel() - 1, skill.getLevel());
}
}
- return true;
- }
- else
- {
- return false;
+ // Unlock event
+ if (skill.getLevel() == 1) {
+ Bukkit.getPluginManager().callEvent(new PlayerSkillUnlockEvent(this, skill));
+ this.autoLevel();
+ }
}
}
@@ -747,91 +754,171 @@ public boolean upgradeSkill(Skill skill)
*
* @return true if successfully downgraded, false otherwise
*/
- public boolean downgradeSkill(Skill skill)
- {
+ public boolean downgradeSkill(Skill skill) {
// Cannot be null
- if (skill == null)
- {
+ if (skill == null) {
return false;
}
// Must be a valid available skill
PlayerSkill data = skills.get(skill.getName().toLowerCase());
- if (data == null)
- {
+ if (data == null) {
return false;
}
// Must not be a free skill
- if (data.getCost() == 0)
- {
+ if (data.getCost() == 0) {
return false;
}
// Must not be required by another skill
- for (PlayerSkill s : skills.values())
- {
+ for (PlayerSkill s : skills.values()) {
if (s.getData().getSkillReq() != null
- && s.getData().getSkillReq().equalsIgnoreCase(skill.getName())
- && data.getLevel() <= s.getData().getSkillReqLevel()
- && s.getLevel() > 0)
- {
+ && s.getData().getSkillReq().equalsIgnoreCase(skill.getName())
+ && data.getLevel() <= s.getData().getSkillReqLevel()
+ && s.getLevel() > 0) {
return false;
}
}
int cost = skill.getCost(data.getLevel() - 1);
- if (data.getLevel() > 0)
- {
+ if (data.getLevel() > 0) {
// Upgrade event
PlayerSkillDowngradeEvent event = new PlayerSkillDowngradeEvent(this, data, cost);
Bukkit.getPluginManager().callEvent(event);
- if (event.isCancelled())
- {
+ if (event.isCancelled()) {
return false;
}
// Apply upgrade
data.getPlayerClass().givePoints(cost, PointSource.REFUND);
- data.addLevels(-1);
+ forceDownSkill(data);
- // Passive calls
- Player player = getPlayer();
- if (player != null && skill instanceof PassiveSkill)
- {
- if (data.getLevel() == 0)
- {
- ((PassiveSkill) skill).stopEffects(player, 1);
- }
- else
- {
- ((PassiveSkill) skill).update(player, data.getLevel() + 1, data.getLevel());
- }
- }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Forcefully downgrades a skill, not letting other plugins
+ * stop it and ignoring any skill requirements to do so.
+ *
+ * @param skill skill to forcefully downgrade
+ */
+ public void forceDownSkill(PlayerSkill skill) {
+ skill.addLevels(-1);
- // Clear bindings
- if (data.getLevel() == 0)
- {
- clearBinds(skill);
+ // Passive calls
+ Player player = getPlayer();
+ if (player != null && skill.getData() instanceof PassiveSkill) {
+ if (skill.getLevel() == 0) {
+ ((PassiveSkill) skill.getData()).stopEffects(player, 1);
+ } else {
+ ((PassiveSkill) skill.getData()).update(player, skill.getLevel() + 1, skill.getLevel());
}
+ }
- return true;
+ // Clear bindings
+ if (skill.getLevel() == 0) {
+ clearBinds(skill.getData());
}
- else
- {
- return false;
+ }
+
+ /**
+ * Refunds a skill for the player, resetting it down
+ * to level 0 and giving back any invested skill points.
+ *
+ * @param skill skill to refund
+ */
+ public void refundSkill(PlayerSkill skill) {
+ Player player = getPlayer();
+
+ if (skill.getCost() == 0 || skill.getLevel() == 0) { return; }
+
+ skill.getPlayerClass().givePoints(skill.getInvestedCost(), PointSource.REFUND);
+ skill.setLevel(0);
+
+ if (player != null && (skill.getData() instanceof PassiveSkill)) {
+ ((PassiveSkill) skill.getData()).stopEffects(player, 1);
}
}
+ /**
+ * Refunds all skills for the player
+ */
+ public void refundSkills() {
+ for (PlayerSkill skill : skills.values()) { refundSkill(skill); }
+
+ clearAllBinds();
+ }
+
/**
* Shows the skill tree for the player. If the player has multiple trees,
* this will show the list of skill trees they can view.
*/
- public void showSkills()
- {
+ public void showSkills() {
showSkills(getPlayer());
}
+ /**
+ * Shows the class details for the player
+ *
+ * @param player player to show to
+ *
+ * @return true if shown, false if nothing to show
+ */
+ public boolean showDetails(Player player) {
+ if (classes.size() > 0 && player != null) {
+ HashMap iconMap = new HashMap<>();
+ for (Map.Entry entry : classes.entrySet()) {
+ iconMap.put(entry.getKey().toLowerCase(), entry.getValue().getData());
+ }
+
+ GUITool.getDetailsMenu().show(
+ new DetailsHandler(),
+ this,
+ SkillAPI.getLanguage().getMessage(
+ GUINodes.CLASS_LIST,
+ true,
+ FilterType.COLOR,
+ Filter.PLAYER.setReplacement(player.getName())
+ ).get(0),
+ iconMap
+ );
+ return true;
+ } else { return false; }
+ }
+
+ /**
+ * Shows profession options of the first class group available
+ *
+ * @param player player to show profession options for
+ *
+ * @return true if shown profession options, false if none available
+ */
+ public boolean showProfession(Player player) {
+ for (String group : SkillAPI.getGroups()) {
+ PlayerClass c = getClass(group);
+ if (c == null || (c.getLevel() == c.getData().getMaxLevel() && c.getData().getOptions().size() > 0)) {
+ GUITool.getProfessMenu(c == null ? null : c.getData()).show(
+ new ProfessHandler(),
+ this,
+ SkillAPI.getLanguage().getMessage(
+ GUINodes.PROFESS_TITLE,
+ true,
+ FilterType.COLOR,
+ Filter.PLAYER.setReplacement(player.getName()),
+ RPGFilter.GROUP.setReplacement(group)
+ ).get(0),
+ SkillAPI.getClasses()
+ );
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Shows the skill tree for the player. If the player has multiple trees,
* this will show the list of skill trees they can view.
@@ -840,37 +927,17 @@ public void showSkills()
*
* @return true if able to show the player, false otherwise
*/
- public boolean showSkills(Player player)
- {
+ public boolean showSkills(Player player) {
// Cannot show an invalid player, and cannot show no skills
- if (player == null || classes.size() == 0 || skills.size() == 0)
- {
+ if (player == null || classes.size() == 0 || skills.size() == 0) {
return false;
}
// Show list of classes that have skill trees
- if (classes.size() > 1)
- {
- Inventory inv = InventoryManager.createInventory(
- TreeListener.CLASS_LIST_KEY,
- (classes.size() + 8) / 9,
- SkillAPI.getLanguage().getMessage(
- GUINodes.CLASS_LIST,
- true,
- FilterType.COLOR,
- Filter.PLAYER.setReplacement(player.getName())
- ).get(0)
- );
- for (PlayerClass c : classes.values())
- {
- inv.addItem(c.getData().getIcon());
- }
- player.openInventory(inv);
- return true;
- }
+ if (classes.size() > 1) { return showDetails(player); }
// Show only class's skill tree otherwise
- else return showSkills(player, classes.get(classes.keySet().toArray(new String[1])[0]));
+ else { return showSkills(player, classes.values().iterator().next()); }
}
/**
@@ -881,17 +948,28 @@ public boolean showSkills(Player player)
*
* @return true if succeeded, false otherwise
*/
- public boolean showSkills(Player player, PlayerClass playerClass)
- {
+ public boolean showSkills(Player player, PlayerClass playerClass) {
// Cannot show an invalid player, and cannot show no skills
- if (player == null || playerClass.getData().getSkills().size() == 0)
- {
+ if (player == null || playerClass.getData().getSkills().size() == 0) {
return false;
}
// Show skill tree of the class
this.menuClass = playerClass.getData().getName();
- player.openInventory(((InventoryTree) playerClass.getData().getSkillTree()).getInventory(this));
+ GUITool.getSkillTree(playerClass.getData()).show(
+ new SkillHandler(),
+ this,
+ SkillAPI.getLanguage().getMessage(
+ GUINodes.SKILL_TREE,
+ true,
+ FilterType.COLOR,
+ RPGFilter.POINTS.setReplacement(playerClass.getPoints() + ""),
+ RPGFilter.LEVEL.setReplacement(playerClass.getLevel() + ""),
+ RPGFilter.CLASS.setReplacement(playerClass.getData().getName()),
+ Filter.PLAYER.setReplacement(getPlayerName())
+ ).get(0),
+ playerClass.getData().getSkillMap()
+ );
return true;
}
@@ -900,8 +978,7 @@ public boolean showSkills(Player player, PlayerClass playerClass)
*
* @return class name
*/
- public String getShownClassName()
- {
+ public String getShownClassName() {
return menuClass;
}
@@ -916,8 +993,7 @@ public String getShownClassName()
*
* @return true if professed, false otherwise
*/
- public boolean hasClass()
- {
+ public boolean hasClass() {
return classes.size() > 0;
}
@@ -928,8 +1004,7 @@ public boolean hasClass()
*
* @return true if has a class in the group, false otherwise
*/
- public boolean hasClass(String group)
- {
+ public boolean hasClass(String group) {
return classes.containsKey(group);
}
@@ -938,8 +1013,7 @@ public boolean hasClass(String group)
*
* @return collection of the data for professed classes
*/
- public Collection getClasses()
- {
+ public Collection getClasses() {
return classes.values();
}
@@ -951,8 +1025,7 @@ public Collection getClasses()
*
* @return professed class data or null if not professed for the group
*/
- public PlayerClass getClass(String group)
- {
+ public PlayerClass getClass(String group) {
return classes.get(group);
}
@@ -962,19 +1035,13 @@ public PlayerClass getClass(String group)
*
* @return main professed class data or null if not professed for the main group
*/
- public PlayerClass getMainClass()
- {
+ public PlayerClass getMainClass() {
String main = SkillAPI.getSettings().getMainGroup();
- if (classes.containsKey(main))
- {
+ if (classes.containsKey(main)) {
return classes.get(main);
- }
- else if (classes.size() > 0)
- {
+ } else if (classes.size() > 0) {
return classes.values().toArray(new PlayerClass[classes.size()])[0];
- }
- else
- {
+ } else {
return null;
}
}
@@ -988,25 +1055,20 @@ else if (classes.size() > 0)
*
* @return the player-specific data for the new class
*/
- public PlayerClass setClass(RPGClass rpgClass)
- {
+ public PlayerClass setClass(RPGClass rpgClass) {
PlayerClass c = classes.remove(rpgClass.getGroup());
- if (c != null)
- {
- for (Skill skill : c.getData().getSkills())
- {
+ if (c != null) {
+ for (Skill skill : c.getData().getSkills()) {
skills.remove(skill.getName().toLowerCase());
combos.removeSkill(skill);
}
- }
- else attribPoints += rpgClass.getGroupSettings().getStartingAttribs();
+ } else { attribPoints += rpgClass.getGroupSettings().getStartingAttribs(); }
PlayerClass classData = new PlayerClass(this, rpgClass);
classes.put(rpgClass.getGroup(), classData);
// Add in missing skills
- for (Skill skill : rpgClass.getSkills())
- {
+ for (Skill skill : rpgClass.getSkills()) {
giveSkill(skill, classData);
}
@@ -1023,9 +1085,8 @@ public PlayerClass setClass(RPGClass rpgClass)
*
* @return true if professed as the specific class, false otherwise
*/
- public boolean isExactClass(RPGClass rpgClass)
- {
- if (rpgClass == null) return false;
+ public boolean isExactClass(RPGClass rpgClass) {
+ if (rpgClass == null) { return false; }
PlayerClass c = classes.get(rpgClass.getGroup());
return (c != null) && (c.getData() == rpgClass);
}
@@ -1038,21 +1099,17 @@ public boolean isExactClass(RPGClass rpgClass)
*
* @return true if professed as the class or one of its children, false otherwise
*/
- public boolean isClass(RPGClass rpgClass)
- {
- if (rpgClass == null)
- {
+ public boolean isClass(RPGClass rpgClass) {
+ if (rpgClass == null) {
return false;
}
PlayerClass pc = classes.get(rpgClass.getGroup());
- if (pc == null) return false;
+ if (pc == null) { return false; }
RPGClass temp = pc.getData();
- while (temp != null)
- {
- if (temp == rpgClass)
- {
+ while (temp != null) {
+ if (temp == rpgClass) {
return true;
}
temp = temp.getParent();
@@ -1070,23 +1127,16 @@ public boolean isClass(RPGClass rpgClass)
*
* @return true if can profess, false otherwise
*/
- public boolean canProfess(RPGClass rpgClass)
- {
- if (rpgClass.isNeedsPermission())
- {
- Player p = getPlayer();
- if (p == null || (!p.hasPermission(Permissions.CLASS) && !p.hasPermission(Permissions.CLASS + "." + rpgClass.getName().toLowerCase().replace(" ", "-"))))
- {
- return false;
- }
+ public boolean canProfess(RPGClass rpgClass) {
+ Player p = getPlayer();
+ if (p == null || !rpgClass.isAllowed(p)) {
+ return false;
}
- if (classes.containsKey(rpgClass.getGroup()))
- {
+
+ if (classes.containsKey(rpgClass.getGroup())) {
PlayerClass current = classes.get(rpgClass.getGroup());
return rpgClass.getParent() == current.getData() && current.getData().getMaxLevel() <= current.getLevel();
- }
- else
- {
+ } else {
return !rpgClass.hasParent();
}
}
@@ -1098,22 +1148,19 @@ public boolean canProfess(RPGClass rpgClass)
*
* @param group group to reset
*/
- public void reset(String group)
- {
+ public void reset(String group) {
GroupSettings settings = SkillAPI.getSettings().getGroupSettings(group);
- if (!settings.canReset())
- return;
+ if (!settings.canReset()) { return; }
PlayerClass playerClass = classes.remove(group);
- if (playerClass != null)
- {
+ if (playerClass != null) {
// Remove skills
RPGClass data = playerClass.getData();
- for (Skill skill : data.getSkills())
- {
+ for (Skill skill : data.getSkills()) {
PlayerSkill ps = skills.remove(skill.getName().toLowerCase());
- if (ps != null && ps.isUnlocked() && ps.getData() instanceof PassiveSkill)
+ if (ps != null && ps.isUnlocked() && ps.getData() instanceof PassiveSkill) {
((PassiveSkill) ps.getData()).stopEffects(getPlayer(), ps.getLevel());
+ }
combos.removeSkill(skill);
}
@@ -1126,8 +1173,7 @@ public void reset(String group)
// Restore default class if applicable
RPGClass rpgClass = settings.getDefault();
- if (rpgClass != null && settings.getPermission() == null)
- {
+ if (rpgClass != null && settings.getPermission() == null) {
setClass(rpgClass);
}
binds.clear();
@@ -1138,27 +1184,23 @@ public void reset(String group)
* Resets all profession data for the player. This clears all professions the player
* has, leaving no remaining data until the player professes again to a starting class.
*/
- public void resetAll()
- {
- ArrayList keys = new ArrayList(classes.keySet());
- for (String key : keys)
- reset(key);
+ public void resetAll() {
+ ArrayList keys = new ArrayList<>(classes.keySet());
+ for (String key : keys) { reset(key); }
}
/**
* Resets attributes for the player
*/
- public void resetAttribs()
- {
+ public void resetAttribs() {
attributes.clear();
attribPoints = 0;
- for (PlayerClass c : classes.values())
- {
+ for (PlayerClass c : classes.values()) {
GroupSettings s = c.getData().getGroupSettings();
attribPoints += s.getStartingAttribs() + s.getAttribsForLevels(c.getLevel(), 1);
}
AttributeListener.updatePlayer(this);
- updateHealthAndMana(player.getPlayer());
+ updateHealthAndMana(getPlayer());
}
/**
@@ -1172,37 +1214,42 @@ public void resetAttribs()
*
* @return true if successfully professed, false otherwise
*/
- public boolean profess(RPGClass rpgClass)
- {
- if (rpgClass != null && canProfess(rpgClass))
- {
+ public boolean profess(RPGClass rpgClass) {
+ if (rpgClass != null && canProfess(rpgClass)) {
+ final PlayerClass previousData = classes.get(rpgClass.getGroup());
+ final RPGClass previous = previousData == null ? null : previousData.getData();
+
+ // Pre-class change event in case someone wants to stop it
+ final PlayerPreClassChangeEvent event = new PlayerPreClassChangeEvent(
+ this,
+ previousData,
+ previous,
+ rpgClass);
+ Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+
// Reset data if applicable
- if (SkillAPI.getSettings().getGroupSettings(rpgClass.getGroup()).isProfessReset())
- {
+ final boolean isResetting = SkillAPI.getSettings().getGroupSettings(rpgClass.getGroup()).isProfessReset();
+ if (isResetting) {
reset(rpgClass.getGroup());
}
// Inherit previous class data if any
- PlayerClass current = classes.get(rpgClass.getGroup());
- RPGClass previous;
- if (current == null)
- {
- previous = null;
+ final PlayerClass current;
+ if (previousData == null || isResetting) {
current = new PlayerClass(this, rpgClass);
classes.put(rpgClass.getGroup(), current);
attribPoints += rpgClass.getGroupSettings().getStartingAttribs();
- }
- else
- {
- previous = current.getData();
- current.setClassData(rpgClass);
+ } else {
+ current = previousData;
+ previousData.setClassData(rpgClass);
}
// Add skills
- for (Skill skill : rpgClass.getSkills())
- {
- if (!skills.containsKey(skill.getKey()))
- {
+ for (Skill skill : rpgClass.getSkills()) {
+ if (!skills.containsKey(skill.getKey())) {
skills.put(skill.getKey(), new PlayerSkill(this, skill, current));
combos.addSkill(skill);
}
@@ -1212,9 +1259,7 @@ public boolean profess(RPGClass rpgClass)
resetAttribs();
updateScoreboard();
return true;
- }
- else
- {
+ } else {
return false;
}
}
@@ -1225,24 +1270,30 @@ public boolean profess(RPGClass rpgClass)
* @param amount amount of experience to give
* @param source source of the experience
*/
- public void giveExp(double amount, ExpSource source)
- {
- for (PlayerClass playerClass : classes.values())
- {
- playerClass.giveExp(amount, source);
+ public void giveExp(double amount, ExpSource source) {
+ giveExp(amount, source, true);
+ }
+
+ /**
+ * Gives experience to the player from the given source
+ *
+ * @param amount amount of experience to give
+ * @param source source of the experience
+ * @param message whether or not to show the configured message if enabled
+ */
+ public void giveExp(double amount, ExpSource source, boolean message) {
+ for (PlayerClass playerClass : classes.values()) {
+ playerClass.giveExp(amount, source, message);
}
}
/**
* Causes the player to lose experience as a penalty (generally for dying)
*/
- public void loseExp()
- {
- for (PlayerClass playerClass : classes.values())
- {
+ public void loseExp() {
+ for (PlayerClass playerClass : classes.values()) {
double penalty = playerClass.getData().getGroupSettings().getDeathPenalty();
- if (penalty > 0)
- {
+ if (penalty > 0) {
playerClass.loseExp(penalty);
}
}
@@ -1254,25 +1305,17 @@ public void loseExp()
* @param amount amount of levels to give
* @param source source of the levels
*/
- public void giveLevels(int amount, ExpSource source)
- {
- for (PlayerClass playerClass : classes.values())
- {
+ public boolean giveLevels(int amount, ExpSource source) {
+ boolean success = false;
+ for (PlayerClass playerClass : classes.values()) {
RPGClass data = playerClass.getData();
- if (data.receivesExp(source))
- {
- int exp = 0;
- int count = 0;
- int temp = amount;
- while (temp > 0)
- {
- temp--;
- exp += data.getRequiredExp(playerClass.getLevel() + count++);
- }
- playerClass.giveExp(exp, source);
+ if (data.receivesExp(source)) {
+ success = true;
+ playerClass.giveLevels(amount);
}
}
updateHealthAndMana(getPlayer());
+ return success;
}
/**
@@ -1281,12 +1324,9 @@ public void giveLevels(int amount, ExpSource source)
* @param amount amount of levels to give
* @param source source of the levels
*/
- public void givePoints(int amount, ExpSource source)
- {
- for (PlayerClass playerClass : classes.values())
- {
- if (playerClass.getData().receivesExp(source))
- {
+ public void givePoints(int amount, ExpSource source) {
+ for (PlayerClass playerClass : classes.values()) {
+ if (playerClass.getData().receivesExp(source)) {
playerClass.givePoints(amount);
}
}
@@ -1303,41 +1343,32 @@ public void givePoints(int amount, ExpSource source)
*
* @param player player to update the health and mana for
*/
- public void updateHealthAndMana(Player player)
- {
- if (player == null)
- {
+ public void updateHealthAndMana(Player player) {
+ if (player == null) {
return;
}
// Update maxes
double health = bonusHealth;
maxMana = bonusMana;
- for (PlayerClass c : classes.values())
- {
+ for (PlayerClass c : classes.values()) {
health += c.getHealth();
maxMana += c.getMana();
}
- if (health == bonusHealth)
- {
+ if (health == bonusHealth) {
health += SkillAPI.getSettings().getDefaultHealth();
}
- if (health == 0)
- {
- health = 20;
+ if (health <= 0) {
+ health = SkillAPI.getSettings().getDefaultHealth();
}
- if (SkillAPI.getSettings().isModifyHealth())
- VersionManager.setMaxHealth(player, health);
+ if (SkillAPI.getSettings().isModifyHealth()) { player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(health); }
mana = Math.min(mana, maxMana);
// Health scaling is available starting with 1.6.2
- if (SkillAPI.getSettings().isOldHealth())
- {
+ if (SkillAPI.getSettings().isOldHealth()) {
player.setHealthScaled(true);
player.setHealthScale(20);
- }
- else
- {
+ } else {
player.setHealthScaled(false);
}
}
@@ -1349,12 +1380,25 @@ public void updateHealthAndMana(Player player)
*
* @param amount amount of bonus health to give
*/
- public void addMaxHealth(double amount)
- {
+
+ public void addMaxHealth(double amount) {
bonusHealth += amount;
- Player player = getPlayer();
- if (player != null)
- player.setMaxHealth(player.getMaxHealth() + amount);
+ final Player player = getPlayer();
+ if (player != null) {
+ if (VersionManager.isVersionAtLeast(VersionManager.V1_9_0)) {
+ final AttributeInstance attribute = player.getAttribute(Attribute.GENERIC_MAX_HEALTH);
+ attribute.setBaseValue(attribute.getBaseValue() + amount);
+ } else {
+ final double newHealth = player.getMaxHealth() + amount;
+ player.setMaxHealth(newHealth);
+ if (player.getMaxHealth() > newHealth) {
+ player.setMaxHealth(newHealth * 2 - player.getMaxHealth());
+ }
+
+ }
+
+
+ }
}
/**
@@ -1364,8 +1408,7 @@ public void addMaxHealth(double amount)
*
* @param amount amount of bonus mana to give
*/
- public void addMaxMana(double amount)
- {
+ public void addMaxMana(double amount) {
bonusMana += amount;
maxMana += amount;
mana += amount;
@@ -1376,8 +1419,7 @@ public void addMaxMana(double amount)
*
* @return current player mana
*/
- public double getMana()
- {
+ public double getMana() {
return mana;
}
@@ -1388,8 +1430,7 @@ public double getMana()
*
* @return true if has the amount of mana, false otherwise
*/
- public boolean hasMana(double amount)
- {
+ public boolean hasMana(double amount) {
return mana >= amount;
}
@@ -1398,26 +1439,21 @@ public boolean hasMana(double amount)
*
* @return max amount of mana the player can have
*/
- public double getMaxMana()
- {
+ public double getMaxMana() {
return maxMana;
}
/**
* Regenerates mana for the player based on the regen amounts of professed classes
*/
- public void regenMana()
- {
+ public void regenMana() {
double amount = 0;
- for (PlayerClass c : classes.values())
- {
- if (c.getData().hasManaRegen())
- {
+ for (PlayerClass c : classes.values()) {
+ if (c.getData().hasManaRegen()) {
amount += c.getData().getManaRegen();
}
}
- if (amount > 0)
- {
+ if (amount > 0) {
giveMana(amount, ManaSource.REGEN);
}
}
@@ -1427,8 +1463,7 @@ public void regenMana()
*
* @param amount current mana
*/
- public void setMana(double amount)
- {
+ public void setMana(double amount) {
this.mana = amount;
}
@@ -1438,8 +1473,7 @@ public void setMana(double amount)
*
* @param amount amount of mana to give
*/
- public void giveMana(double amount)
- {
+ public void giveMana(double amount) {
giveMana(amount, ManaSource.SPECIAL);
}
@@ -1450,26 +1484,24 @@ public void giveMana(double amount)
* @param amount amount of mana to give
* @param source source of the mana
*/
- public void giveMana(double amount, ManaSource source)
- {
+ public void giveMana(double amount, ManaSource source) {
PlayerManaGainEvent event = new PlayerManaGainEvent(this, amount, source);
Bukkit.getPluginManager().callEvent(event);
- if (!event.isCancelled())
- {
- Logger.log(LogType.MANA, 2, getPlayerName() + " gained " + amount + " mana due to " + event.getSource().name());
+ if (!event.isCancelled()) {
+ Logger.log(
+ LogType.MANA,
+ 2,
+ getPlayerName() + " gained " + amount + " mana due to " + event.getSource().name());
mana += event.getAmount();
- if (mana > maxMana)
- {
+ if (mana > maxMana) {
mana = maxMana;
}
- if (mana < 0)
- {
+ if (mana < 0) {
mana = 0;
}
- }
- else Logger.log(LogType.MANA, 2, getPlayerName() + " had their mana gain cancelled");
+ } else { Logger.log(LogType.MANA, 2, getPlayerName() + " had their mana gain cancelled"); }
}
/**
@@ -1478,8 +1510,7 @@ public void giveMana(double amount, ManaSource source)
*
* @param amount amount of mana to take away
*/
- public void useMana(double amount)
- {
+ public void useMana(double amount) {
useMana(amount, ManaCost.SPECIAL);
}
@@ -1490,18 +1521,18 @@ public void useMana(double amount)
* @param amount amount of mana to take away
* @param cost source of the mana cost
*/
- public void useMana(double amount, ManaCost cost)
- {
+ public void useMana(double amount, ManaCost cost) {
PlayerManaLossEvent event = new PlayerManaLossEvent(this, amount, cost);
Bukkit.getPluginManager().callEvent(event);
- if (!event.isCancelled())
- {
- Logger.log(LogType.MANA, 2, getPlayerName() + " used " + amount + " mana due to " + event.getSource().name());
+ if (!event.isCancelled()) {
+ Logger.log(
+ LogType.MANA,
+ 2,
+ getPlayerName() + " used " + amount + " mana due to " + event.getSource().name());
mana -= event.getAmount();
- if (mana < 0)
- {
+ if (mana < 0) {
mana = 0;
}
}
@@ -1510,10 +1541,11 @@ public void useMana(double amount, ManaCost cost)
/**
* Clears bonus health/mana
*/
- public void clearBonuses()
- {
+ public void clearBonuses() {
bonusMana = 0;
bonusHealth = 0;
+ bonusAttrib.clear();
+ equips = new PlayerEquips(this);
}
///////////////////////////////////////////////////////
@@ -1529,9 +1561,12 @@ public void clearBonuses()
*
* @return skill bound to the material or null if none are bound
*/
- public PlayerSkill getBoundSkill(Material mat)
- {
- return binds.get(mat);
+ public PlayerSkill getBoundSkill(Material mat) {
+ return binds.get(mat.toString());
+ }
+ public PlayerSkill getBoundSkill(String dispname) {
+ dispname = dispname.replaceAll("§.", "").replace(" ","_").toUpperCase();
+ return binds.get(dispname);
}
/**
@@ -1540,8 +1575,7 @@ public PlayerSkill getBoundSkill(Material mat)
*
* @return the skill binds data for the player
*/
- public HashMap getBinds()
- {
+ public HashMap getBinds() {
return binds;
}
@@ -1552,11 +1586,13 @@ public HashMap getBinds()
*
* @return true if a skill is bound to it, false otherwise
*/
- public boolean isBound(Material mat)
- {
- return binds.containsKey(mat);
+ public boolean isBound(Material mat) {
+ return binds.containsKey(mat.toString());
+ }
+ public boolean isBound(String dispname) {
+ dispname = dispname.replaceAll("§.", "").replace(" ","_").toUpperCase();
+ return binds.containsKey(dispname);
}
-
/**
* Binds a skill to a material for the player. The bind will not work if the skill
* was already bound to the material.
@@ -1566,49 +1602,73 @@ public boolean isBound(Material mat)
*
* @return true if was able to bind the skill, false otherwise
*/
- public boolean bind(Material mat, PlayerSkill skill)
- {
+ public boolean bind(Material mat, PlayerSkill skill) {
// Special cases
- if (mat == null || (skill != null && skill.getPlayerData() != this))
- {
+ if (mat == null || (skill != null && skill.getPlayerData() != this)) {
return false;
}
PlayerSkill bound = getBoundSkill(mat);
- if (bound != skill)
- {
+ if (bound != skill) {
// Apply the binding
- if (skill == null)
- {
- binds.remove(mat);
- }
- else
- {
- binds.put(mat, skill);
+ if (skill == null) {
+ binds.remove(mat.toString());
+ } else {
+ binds.put(mat.toString(), skill);
}
// Update the old skill's bind
- if (bound != null)
- {
- bound.setBind(null);
+ if (bound != null) {
+ bound.setBindMat(null);
}
// Update the new skill's bind
- if (skill != null)
- {
- skill.setBind(mat);
+ if (skill != null) {
+ skill.setBindMat(mat);
}
return true;
}
// The skill was already bound
- else
- {
+ else {
return false;
}
}
+ // iomatix: bind by disp name
+ public boolean bind(String dispname, PlayerSkill skill) {
+ // Special cases
+ if (dispname == null || (skill != null && skill.getPlayerData() != this)) {
+ return false;
+ }
+ dispname = dispname.replaceAll("§.", "").replace(" ","_").toUpperCase();
+ PlayerSkill bound = getBoundSkill(dispname);
+ if (bound != skill) {
+ // Apply the binding
+ if (skill == null) {
+ binds.remove(dispname);
+ } else {
+ binds.put(dispname, skill);
+ }
+ // Update the old skill's bind
+ if (bound != null) {
+ bound.setBindDispName(null);
+ }
+
+ // Update the new skill's bind
+ if (skill != null) {
+ skill.setBindDispName(dispname);
+ }
+
+ return true;
+ }
+
+ // The skill was already bound
+ else {
+ return false;
+ }
+ }
/**
* Clears a skill binding on the material. If there is no binding on the
* material, this will do nothing.
@@ -1617,9 +1677,9 @@ public boolean bind(Material mat, PlayerSkill skill)
*
* @return true if a binding was cleared, false otherwise
*/
- public boolean clearBind(Material mat)
- {
- return binds.remove(mat) != null;
+ public boolean clearBind(String dispname) {
+ dispname = dispname.replaceAll("§.", "").replace(" ","_").toUpperCase();
+ return binds.remove(dispname) != null;
}
/**
@@ -1628,14 +1688,11 @@ public boolean clearBind(Material mat)
*
* @param skill skill to unbind
*/
- public void clearBinds(Skill skill)
- {
- ArrayList keys = new ArrayList(binds.keySet());
- for (Material key : keys)
- {
+ public void clearBinds(Skill skill) {
+ ArrayList keys = new ArrayList<>(binds.keySet());
+ for (String key : keys) {
PlayerSkill bound = binds.get(key);
- if (bound.getData() == skill)
- {
+ if (bound.getData() == skill) {
binds.remove(key);
}
}
@@ -1644,8 +1701,7 @@ public void clearBinds(Skill skill)
/**
* Clears all binds the player currently has
*/
- public void clearAllBinds()
- {
+ public void clearAllBinds() {
binds.clear();
}
@@ -1660,8 +1716,7 @@ public void clearAllBinds()
*
* @param player player to record for
*/
- public void record(Player player)
- {
+ public void record(Player player) {
this.lastHealth = player.getHealth();
}
@@ -1670,10 +1725,8 @@ public void record(Player player)
* This is already done by the API and doesn't need to be
* done by other plugins.
*/
- public void updateScoreboard()
- {
- if (SkillAPI.getSettings().isShowScoreboard())
- SkillAPI.schedule(new ScoreboardTask(this), 2);
+ public void updateScoreboard() {
+ if (SkillAPI.getSettings().isShowScoreboard()) { SkillAPI.schedule(new ScoreboardTask(this), 2); }
}
/**
@@ -1682,17 +1735,13 @@ public void updateScoreboard()
*
* @param player player to set the passive skills up for
*/
- public void startPassives(Player player)
- {
- if (player == null)
- {
+ public void startPassives(Player player) {
+ if (player == null) {
return;
}
passive = true;
- for (PlayerSkill skill : skills.values())
- {
- if (skill.isUnlocked() && (skill.getData() instanceof PassiveSkill))
- {
+ for (PlayerSkill skill : skills.values()) {
+ if (skill.isUnlocked() && (skill.getData() instanceof PassiveSkill)) {
((PassiveSkill) skill.getData()).initialize(player, skill.getLevel());
}
}
@@ -1704,18 +1753,19 @@ public void startPassives(Player player)
*
* @param player player to stop the passive skills for
*/
- public void stopPassives(Player player)
- {
- if (player == null)
- {
+ public void stopPassives(Player player) {
+ if (player == null) {
return;
}
passive = false;
- for (PlayerSkill skill : skills.values())
- {
- if (skill.isUnlocked() && (skill.getData() instanceof PassiveSkill))
- {
- ((PassiveSkill) skill.getData()).stopEffects(player, skill.getLevel());
+ for (PlayerSkill skill : skills.values()) {
+ if (skill.isUnlocked() && (skill.getData() instanceof PassiveSkill)) {
+ try {
+ ((PassiveSkill) skill.getData()).stopEffects(player, skill.getLevel());
+ } catch (Exception ex) {
+ Logger.bug("Failed to stop passive skill " + skill.getData().getName());
+ ex.printStackTrace();
+ }
}
}
}
@@ -1729,8 +1779,7 @@ public void stopPassives(Player player)
*
* @return true if successfully cast the skill, false otherwise
*/
- public boolean cast(String skillName)
- {
+ public boolean cast(String skillName) {
return cast(skills.get(skillName.toLowerCase()));
}
@@ -1743,98 +1792,85 @@ public boolean cast(String skillName)
*
* @return true if successfully cast the skill, false otherwise
*/
- public boolean cast(PlayerSkill skill)
- {
+ public boolean cast(PlayerSkill skill) {
// Invalid skill
- if (skill == null)
- throw new IllegalArgumentException("Skill cannot be null");
+ if (skill == null) { throw new IllegalArgumentException("Skill cannot be null"); }
int level = skill.getLevel();
// Not unlocked or on cooldown
- if (level <= 0 || !check(skill, true, true))
- return false;
+ if (!check(skill, true, true)) { return false; }
// Dead players can't cast skills
Player p = getPlayer();
- if (p.isDead())
- return false;
+ if (p.isDead()) { return PlayerSkillCastFailedEvent.invoke(skill, CASTER_DEAD); }
+
+ // Disable casting in spectator mode
+ if (p.getGameMode().name().equals("SPECTATOR")) { return PlayerSkillCastFailedEvent.invoke(skill, SPECTATOR); }
// Skill Shots
- if (skill.getData() instanceof SkillShot)
- {
+ if (skill.getData() instanceof SkillShot) {
PlayerCastSkillEvent event = new PlayerCastSkillEvent(this, skill, p);
Bukkit.getPluginManager().callEvent(event);
// Make sure it isn't cancelled
- if (!event.isCancelled())
- {
- try
- {
- if (((SkillShot) skill.getData()).cast(p, level))
- {
- skill.startCooldown();
- if (SkillAPI.getSettings().isShowSkillMessages())
- {
- skill.getData().sendMessage(p, SkillAPI.getSettings().getMessageRadius());
- }
- if (SkillAPI.getSettings().isManaEnabled())
- {
- useMana(skill.getManaCost(), ManaCost.SKILL_CAST);
- }
- return true;
+ if (!event.isCancelled()) {
+ try {
+ if (((SkillShot) skill.getData()).cast(p, level)) {
+ return applyUse(p, skill, event.getManaCost());
+ } else {
+ return PlayerSkillCastFailedEvent.invoke(skill, EFFECT_FAILED);
}
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
Logger.bug("Failed to cast skill - " + skill.getData().getName() + ": Internal skill error");
ex.printStackTrace();
+ return PlayerSkillCastFailedEvent.invoke(skill, EFFECT_FAILED);
}
- }
+ } else { return PlayerSkillCastFailedEvent.invoke(skill, CANCELED); }
}
// Target Skills
- else if (skill.getData() instanceof TargetSkill)
- {
+ else if (skill.getData() instanceof TargetSkill) {
LivingEntity target = TargetHelper.getLivingTarget(p, skill.getData().getRange(level));
// Must have a target
- if (target == null)
- return false;
+ if (target == null) { return PlayerSkillCastFailedEvent.invoke(skill, NO_TARGET); }
PlayerCastSkillEvent event = new PlayerCastSkillEvent(this, skill, p);
Bukkit.getPluginManager().callEvent(event);
// Make sure it isn't cancelled
- if (!event.isCancelled())
- {
- try
- {
- if (((TargetSkill) skill.getData()).cast(p, target, level, !SkillAPI.getSettings().canAttack(p, target)))
- {
- skill.startCooldown();
- if (SkillAPI.getSettings().isShowSkillMessages())
- {
- skill.getData().sendMessage(p, SkillAPI.getSettings().getMessageRadius());
- }
- if (SkillAPI.getSettings().isManaEnabled())
- {
- useMana(skill.getManaCost(), ManaCost.SKILL_CAST);
- }
- return true;
+ if (!event.isCancelled()) {
+ try {
+ final boolean canAttack = !SkillAPI.getSettings().canAttack(p, target);
+ if (((TargetSkill) skill.getData()).cast(p, target, level, canAttack)) {
+ return applyUse(p, skill, event.getManaCost());
+ } else {
+ return PlayerSkillCastFailedEvent.invoke(skill, EFFECT_FAILED);
}
- }
- catch (Exception ex)
- {
+ } catch (Exception ex) {
Logger.bug("Failed to cast skill - " + skill.getData().getName() + ": Internal skill error");
ex.printStackTrace();
+ return PlayerSkillCastFailedEvent.invoke(skill, EFFECT_FAILED);
}
- }
+ } else { PlayerSkillCastFailedEvent.invoke(skill, CANCELED); }
}
return false;
}
+ private boolean applyUse(final Player player, final PlayerSkill skill, final double manaCost) {
+ skill.startCooldown();
+ if (SkillAPI.getSettings().isShowSkillMessages()) {
+ skill.getData().sendMessage(player, SkillAPI.getSettings().getMessageRadius());
+ }
+ if (SkillAPI.getSettings().isManaEnabled()) {
+ useMana(manaCost, ManaCost.SKILL_CAST);
+ }
+ skillTimer = System.currentTimeMillis() + SkillAPI.getSettings().getCastCooldown();
+ return true;
+ }
+
/**
* Checks the cooldown and mana requirements for a skill
*
@@ -1844,50 +1880,43 @@ else if (skill.getData() instanceof TargetSkill)
*
* @return true if can use
*/
- public boolean check(PlayerSkill skill, boolean cooldown, boolean mana)
- {
- if (skill == null)
- return false;
+ public boolean check(PlayerSkill skill, boolean cooldown, boolean mana) {
+ if (skill == null || System.currentTimeMillis() < skillTimer) { return false; }
SkillStatus status = skill.getStatus();
int level = skill.getLevel();
double cost = skill.getData().getManaCost(level);
// Not unlocked
- if (level <= 0)
- {
- return false;
+ if (level <= 0) {
+ return PlayerSkillCastFailedEvent.invoke(skill, NOT_UNLOCKED);
}
// On Cooldown
- if (status == SkillStatus.ON_COOLDOWN && cooldown)
- {
+ if (status == SkillStatus.ON_COOLDOWN && cooldown) {
SkillAPI.getLanguage().sendMessage(
- ErrorNodes.COOLDOWN,
- getPlayer(),
- FilterType.COLOR,
- RPGFilter.COOLDOWN.setReplacement(skill.getCooldown() + ""),
- RPGFilter.SKILL.setReplacement(skill.getData().getName())
+ ErrorNodes.COOLDOWN,
+ getPlayer(),
+ FilterType.COLOR,
+ RPGFilter.COOLDOWN.setReplacement(skill.getCooldown() + ""),
+ RPGFilter.SKILL.setReplacement(skill.getData().getName())
);
- return false;
+ return PlayerSkillCastFailedEvent.invoke(skill, ON_COOLDOWN);
}
// Not enough mana
- else if (status == SkillStatus.MISSING_MANA && mana)
- {
+ else if (status == SkillStatus.MISSING_MANA && mana) {
SkillAPI.getLanguage().sendMessage(
- ErrorNodes.MANA,
- getPlayer(),
- FilterType.COLOR,
- RPGFilter.SKILL.setReplacement(skill.getData().getName()),
- RPGFilter.MANA.setReplacement(getMana() + ""),
- RPGFilter.COST.setReplacement((int) Math.ceil(cost) + ""),
- RPGFilter.MISSING.setReplacement((int) Math.ceil(cost - getMana()) + "")
+ ErrorNodes.MANA,
+ getPlayer(),
+ FilterType.COLOR,
+ RPGFilter.SKILL.setReplacement(skill.getData().getName()),
+ RPGFilter.MANA.setReplacement(getMana() + ""),
+ RPGFilter.COST.setReplacement((int) Math.ceil(cost) + ""),
+ RPGFilter.MISSING.setReplacement((int) Math.ceil(cost - getMana()) + "")
);
- return false;
- }
-
- else return true;
+ return PlayerSkillCastFailedEvent.invoke(skill, NO_MANA);
+ } else { return true; }
}
/**
@@ -1895,17 +1924,16 @@ else if (status == SkillStatus.MISSING_MANA && mana)
*
* @param player player to set up for
*/
- public void init(Player player)
- {
- if (!SkillAPI.getSettings().isWorldEnabled(player.getWorld()))
- return;
+ public void init(Player player) {
+ if (!SkillAPI.getSettings().isWorldEnabled(player.getWorld())) { return; }
AttributeListener.updatePlayer(this);
- InventoryTask.check(player);
+ getEquips().update(player);
this.updateHealthAndMana(player);
- if (this.getLastHealth() > 0)
- player.setHealth(Math.min(this.getLastHealth(), player.getMaxHealth()));
this.startPassives(player);
this.updateScoreboard();
+ if (this.getLastHealth() > 0 && !player.isDead()) {
+ player.setHealth(Math.min(this.getLastHealth(), player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getBaseValue()));
+ }
}
}
diff --git a/src/com/sucy/skill/api/player/PlayerSkill.java b/src/com/sucy/skill/api/player/PlayerSkill.java
index bf4cdd7f..96de54ef 100644
--- a/src/com/sucy/skill/api/player/PlayerSkill.java
+++ b/src/com/sucy/skill/api/player/PlayerSkill.java
@@ -29,7 +29,14 @@
import com.sucy.skill.SkillAPI;
import com.sucy.skill.api.enums.SkillStatus;
import com.sucy.skill.api.skills.Skill;
+import com.sucy.skill.cast.IIndicator;
+import com.sucy.skill.cast.IndicatorSettings;
+import com.sucy.skill.manager.AttributeManager;
import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Represents player-specific data for a skill such as the player's
@@ -37,10 +44,12 @@
*/
public final class PlayerSkill
{
+ protected final List indicators = new ArrayList();
+
private Skill skill;
private PlayerData player;
private PlayerClass parent;
- private Material bind;
+ private String bind;
private long cooldown;
private int level;
private int points;
@@ -108,7 +117,7 @@ public PlayerData getPlayerData()
*
* @return the current material bound to or null if not bound
*/
- public Material getBind()
+ public String getBind()
{
return bind;
}
@@ -143,6 +152,23 @@ public int getCost()
return skill.getCost(level);
}
+ /**
+ * @return total invested cost in the skill
+ */
+ public int getInvestedCost()
+ {
+ int total = 0;
+ for (int i = 0; i < level; i++)
+ total += skill.getCost(i);
+ return total;
+
+ /* Could assume the linearly scaling cost, but API allows overrides
+ int x0 = skill.getCost(0);
+ int dx = skill.getCost(1) - x0;
+ return (x0 - dx) * level + dx * (level - 1) * level / 2;
+ */
+ }
+
/**
* @return mana cost to use the skill
*/
@@ -278,11 +304,17 @@ public void addPoints(int amount)
*
* @param mat new bind material
*/
- public void setBind(Material mat)
+ public void setBindMat(Material mat)
{
- this.bind = mat;
+ this.bind = mat.toString();
getPlayerData().bind(mat, this);
}
+
+ public void setBindDispName(String dispname)
+ {
+ this.bind = dispname;
+ getPlayerData().bind(dispname, this);
+ }
/**
* Reverts the skill back to level 0, locking it from
@@ -300,7 +332,8 @@ public void revert()
*/
public void startCooldown()
{
- cooldown = System.currentTimeMillis() + (int) (skill.getCooldown(level) * 1000);
+ long cd = (long)player.scaleStat(AttributeManager.COOLDOWN, skill.getCooldown(level) * 1000L);
+ cooldown = System.currentTimeMillis() + cd;
}
/**
@@ -336,4 +369,43 @@ public void addCooldown(double seconds)
else
cooldown = System.currentTimeMillis() + (int) (seconds * 1000);
}
+
+ /**
+ * Initializes the indicators for the skill
+ *
+ * @param player player to base location off of
+ */
+ public void initIndicators(Player player)
+ {
+ indicators.clear();
+ skill.createPreview(indicators, player, level);
+ }
+
+ /**
+ * Updates the preview indicators each interval
+ *
+ * @param player player to base location off of
+ */
+ public void updateIndicators(Player player)
+ {
+ skill.updateIndicators(indicators, player, level);
+ }
+
+ /**
+ * Makes the packets for active indicators
+ *
+ * @param step animation step
+ *
+ * @return packet list
+ *
+ * @throws Exception
+ */
+ public List makePackets(int step)
+ throws Exception
+ {
+ List packets = new ArrayList();
+ for (IIndicator indicator : indicators)
+ indicator.makePackets(packets, IndicatorSettings.particle, step);
+ return packets;
+ }
}
diff --git a/src/com/sucy/skill/api/player/PlayerSkillBar.java b/src/com/sucy/skill/api/player/PlayerSkillBar.java
index 772c4373..06dd3399 100644
--- a/src/com/sucy/skill/api/player/PlayerSkillBar.java
+++ b/src/com/sucy/skill/api/player/PlayerSkillBar.java
@@ -35,6 +35,7 @@
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
/**
@@ -46,6 +47,7 @@ public class PlayerSkillBar
UNASSIGNED = "e";
private final HashMap slots = new HashMap();
+ private final HashSet reserved = new HashSet();
private final PlayerData player;
private boolean enabled = true;
private boolean setup = false;
@@ -57,14 +59,19 @@ public class PlayerSkillBar
*/
public PlayerSkillBar(PlayerData player)
{
+ if (SkillAPI.getSettings().isUsingCombat()) {
+ reserve(SkillAPI.getSettings().getCastSlot());
+ }
+
this.player = player;
for (int i = 1; i <= 9; i++)
- {
- if (SkillAPI.getSettings().getDefaultBarLayout()[i - 1])
- {
+ if (SkillAPI.getSettings().getDefaultBarLayout()[i - 1] && !reserved.contains(i - 1))
slots.put(i, UNASSIGNED);
- }
- }
+ }
+
+ public void reserve(int slot) {
+ this.reserved.add(slot);
+ this.slots.remove(slot);
}
/**
@@ -111,12 +118,9 @@ public Player getPlayer()
public int getFirstWeaponSlot()
{
for (int i = 0; i < 9; i++)
- {
if (isWeaponSlot(i))
- {
return i;
- }
- }
+
return -1;
}
@@ -131,16 +135,12 @@ public int getItemsInSkillSlots()
int count = 0;
Player p = player.getPlayer();
if (p == null)
- {
return -1;
- }
+
for (int slot : slots.keySet())
- {
if (slot > 0 && slot < 10 && p.getInventory().getItem(slot - 1) != null)
- {
count++;
- }
- }
+
return count;
}
@@ -156,17 +156,13 @@ public int countOpenSlots()
int count = 0;
Player p = player.getPlayer();
if (p == null)
- {
return -1;
- }
+
ItemStack[] items = p.getInventory().getContents();
for (int i = 0; i < items.length; i++)
- {
- if (items[i] == null && !slots.containsKey(i + 1))
- {
+ if ((items[i] == null || items[i].getType() == Material.AIR) && !slots.containsKey(i + 1) && !reserved.contains(i))
count++;
- }
- }
+
return count;
}
@@ -194,35 +190,27 @@ public void toggleEnabled()
*/
public void toggleSlot(int slot)
{
- if (!isEnabled() || SkillAPI.getSettings().getLockedSlots()[slot])
- {
+ if (!isEnabled() || SkillAPI.getSettings().getLockedSlots()[slot] || reserved.contains(slot))
return;
- }
+
slot++;
// Make sure there is always at least one weapon slot
- if (!slots.containsKey(slot) && (slots.size() == 8 || countOpenSlots() == 0))
- {
+ if (!slots.containsKey(slot) && (slots.size() == 8 - reserved.size() || countOpenSlots() == 0))
return;
- }
// Cannot have item in cursor
Player p = player.getPlayer();
if (p == null || (p.getItemOnCursor() != null && p.getItemOnCursor().getType() != Material.AIR))
- {
return;
- }
// Toggle the slot
clear(p);
if (slots.containsKey(slot))
- {
slots.remove(slot);
- }
else
- {
slots.put(slot, UNASSIGNED);
- }
+
setup(p);
}
@@ -233,24 +221,12 @@ public void toggleSlot(int slot)
*/
public void apply(int slot)
{
- if (getPlayer() == null || getPlayer().getGameMode() == GameMode.CREATIVE)
- {
+ if (getPlayer() == null || getPlayer().getGameMode() == GameMode.CREATIVE || !isEnabled() || isWeaponSlot(slot))
return;
- }
- if (!isEnabled())
- {
- return;
- }
- if (isWeaponSlot(slot))
- {
- return;
- }
+
PlayerSkill skill = player.getSkill(slots.get(slot + 1));
- if (skill == null)
- {
- return;
- }
- player.cast(skill);
+ if (skill != null)
+ player.cast(skill);
}
/**
@@ -261,15 +237,13 @@ public void apply(int slot)
public void clear(HumanEntity player)
{
if (player == null || !setup)
- {
return;
- }
+
for (int i = 0; i < 9; i++)
{
if (isWeaponSlot(i))
- {
continue;
- }
+
player.getInventory().setItem(i, null);
}
setup = false;
@@ -283,15 +257,13 @@ public void clear(HumanEntity player)
public void clear(PlayerDeathEvent event)
{
if (event == null || !setup)
- {
return;
- }
+
for (int i = 0; i < 9; i++)
{
if (isWeaponSlot(i))
- {
continue;
- }
+
event.getDrops().remove(event.getEntity().getInventory().getItem(i));
event.getEntity().getInventory().setItem(i, null);
}
@@ -306,9 +278,8 @@ public void reset()
for (int i = 0; i < 9; i++)
{
if (isWeaponSlot(i))
- {
continue;
- }
+
slots.put(i + 1, UNASSIGNED);
}
update(getPlayer());
@@ -322,9 +293,7 @@ public void reset()
public void setup(HumanEntity player)
{
if (player == null || !enabled || player.getGameMode() == GameMode.CREATIVE || setup)
- {
return;
- }
// Disable the skill bar if there isn't enough space
if (countOpenSlots() < getItemsInSkillSlots())
@@ -349,15 +318,12 @@ public void setup(HumanEntity player)
for (int i = 0; i < 9; i++)
{
if (isWeaponSlot(i))
- {
continue;
- }
+
ItemStack item = player.getInventory().getItem(i);
player.getInventory().setItem(i, SkillAPI.getSettings().getUnassigned());
if (item != null)
- {
player.getInventory().addItem(item);
- }
}
// Update the slots
@@ -392,9 +358,8 @@ public void unlock(PlayerSkill skill)
public void assign(PlayerSkill skill, int slot)
{
if (isWeaponSlot(slot))
- {
return;
- }
+
for (Map.Entry entry : slots.entrySet())
{
if (entry.getValue().equals(skill.getData().getName()))
@@ -421,9 +386,7 @@ public void update(HumanEntity player)
{
int index = i - 1;
if (isWeaponSlot(index))
- {
continue;
- }
PlayerSkill skill = this.player.getSkill(slots.get(i));
if (skill == null || !skill.isUnlocked())
@@ -436,9 +399,7 @@ public void update(HumanEntity player)
}
}
else if (isEnabled() && player != null)
- {
- player.getInventory().setItem(index, skill.getData().getIndicator(skill));
- }
+ player.getInventory().setItem(index, skill.getData().getIndicator(skill, true));
}
}
@@ -515,14 +476,10 @@ public void applySettings()
if (layout[i - 1])
{
if (!slots.containsKey(i))
- {
slots.put(i, UNASSIGNED);
- }
}
else if (slots.containsKey(i))
- {
slots.remove(i);
- }
}
}
}
diff --git a/src/com/sucy/skill/api/player/PlayerSkillSlot.java b/src/com/sucy/skill/api/player/PlayerSkillSlot.java
new file mode 100644
index 00000000..98e569f0
--- /dev/null
+++ b/src/com/sucy/skill/api/player/PlayerSkillSlot.java
@@ -0,0 +1,149 @@
+/**
+ * SkillAPI
+ * com.sucy.skill.api.player.PlayerSkillSlot
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Steven Sucy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.sucy.skill.api.player;
+
+import com.sucy.skill.SkillAPI;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.ArrayList;
+
+/**
+ * Handles the skill slot for casting when bars are disabled
+ */
+public class PlayerSkillSlot
+{
+ private ArrayList skills = new ArrayList();
+ private int index = 0;
+ private PlayerData player;
+
+ /**
+ * Initializes the skill slot for the given player
+ *
+ * @param data data of the player
+ */
+ public void init(PlayerData data)
+ {
+ this.player = data;
+ this.index = 0;
+ this.skills.clear();
+
+ for (PlayerSkill skill : data.getSkills())
+ if (skill.getData().canCast() && skill.isUnlocked())
+ skills.add(skill);
+ }
+
+ /**
+ * Gets the current item that should be displayed in the skill slot
+ *
+ * @return item display
+ */
+ public ItemStack getDisplay()
+ {
+ return skills.size() == 0 ?
+ SkillAPI.getSettings().getCastItem()
+ : skills.get(index).getData().getIndicator(skills.get(index), true);
+ }
+
+ /**
+ * Adds a skill to the available skills, if castable
+ *
+ * @param skill skill to add
+ */
+ public void unlock(PlayerSkill skill)
+ {
+ if (skill.isUnlocked() && skill.getData().canCast())
+ skills.add(skill);
+ }
+
+ /**
+ * Clears a specified skill, if available
+ *
+ * @param skill skill to clear
+ */
+ public void clear(PlayerSkill skill)
+ {
+ if (skill.getData().canCast())
+ {
+ skills.remove(skill);
+ index = Math.max(Math.min(index, skills.size() - 1), 0);
+ }
+ }
+
+ /**
+ * Clears all available skills
+ */
+ public void clearAll()
+ {
+ skills.clear();
+ index = 0;
+ }
+
+ /**
+ * Updates the displayed item for the player
+ *
+ * @param player player to update for
+ */
+ public void updateItem(Player player)
+ {
+ if (player != null)
+ player.getInventory().setItem(SkillAPI.getSettings().getCastSlot(), getDisplay());
+ }
+
+ /**
+ * Activates the skill slot, casting the hovered item
+ */
+ public void activate()
+ {
+ if (skills.size() > 0)
+ player.cast(skills.get(index));
+ }
+
+ /**
+ * Cycles to the next skill
+ */
+ public void next()
+ {
+ if (skills.size() > 0)
+ {
+ index = (index + 1) % skills.size();
+ updateItem(player.getPlayer());
+ }
+ }
+
+ /**
+ * Cycles to the previous skill
+ */
+ public void prev()
+ {
+ if (skills.size() > 0)
+ {
+ index = (index + skills.size() - 1) % skills.size();
+ updateItem(player.getPlayer());
+ }
+ }
+}
diff --git a/src/com/sucy/skill/api/projectile/CustomProjectile.java b/src/com/sucy/skill/api/projectile/CustomProjectile.java
index ea0fce54..85d7fe41 100644
--- a/src/com/sucy/skill/api/projectile/CustomProjectile.java
+++ b/src/com/sucy/skill/api/projectile/CustomProjectile.java
@@ -1,21 +1,21 @@
/**
* SkillAPI
* com.sucy.skill.api.projectile.CustomProjectile
- *
+ *
* The MIT License (MIT)
- *
+ *
* Copyright (c) 2014 Steven Sucy
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software") to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
- *
+ *
Represents a projectile that uses an item as the actual projectile.
*/
@@ -48,7 +52,7 @@ public class ItemProjectile extends CustomProjectile
private static final String NAME = "SkillAPI#";
private static int NEXT = 0;
- private Item item;
+ private final Item item;
/**
*