Merge branch 'master' of github.com:mcMMO-Dev/mcMMO into configurable

This commit is contained in:
nossr50 2019-05-14 23:01:05 -07:00
commit f0d6f7077b
13 changed files with 135 additions and 43 deletions

View File

@ -151,6 +151,20 @@ Version 2.2.0
Added API method to grab the level cap of a skill by its PrimarySkillType ENUM definition Added API method to grab the level cap of a skill by its PrimarySkillType ENUM definition
Added API method to check if a skill was being level capped Added API method to check if a skill was being level capped
Added 'UndefinedSkillBehaviour' for trying to use a method that has no behaviour defined for the provided skill Added 'UndefinedSkillBehaviour' for trying to use a method that has no behaviour defined for the provided skill
Version 2.1.60
Fixed a NPE error if a LivingEntity's target was set to null
Fixed a bug where tamed mobs could kill themselves if their owner shot them once
Corrected a typo when naming entities summoned by COTW (Locale string - Taming.Summon.Name.Format)
Fixed a bug where tamed mobs could have hearts instead of their name in their own death messages
Fixed a bug where multi-block crops would fail to double/triple drop (Sugar Cane, Cactus, etc)
Optimized the bonus drop code to reduce overhead
Version 2.1.59
Raised the overfishing limit from 3 to 10
Improved the overfishing messages to be more clear about its mechanics
Overfishing locale keys renamed "Fishing.ScarcityTip" and "Fishing.LowResourcesTip"
NOTES: This and other exploit prevention measures are much more customizable in 2.2, which shouldn't be too far off.
Version 2.1.58 Version 2.1.58
Fixed the wrong locale string being used for Mining Double Drops Fixed the wrong locale string being used for Mining Double Drops

View File

@ -212,7 +212,7 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.14-R0.1-SNAPSHOT</version> <version>1.14.1-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -6,7 +6,7 @@ import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@ConfigSerializable @ConfigSerializable
public class ConfigSectionExploitFishing { public class ConfigSectionExploitFishing {
public static final int OVER_FISHING_LIMIT_DEFAULT = 3; public static final int OVER_FISHING_LIMIT_DEFAULT = 10;
public static final boolean ADMINS_OVER_FISHING_DEFAULT = true; public static final boolean ADMINS_OVER_FISHING_DEFAULT = true;
public static final float OVER_FISHING_SIZE = 1.0F; public static final float OVER_FISHING_SIZE = 1.0F;
public static final int FISHING_ROD_SPAM_THRESHOLD_MILLISECONDS_DEFAULT = 200; public static final int FISHING_ROD_SPAM_THRESHOLD_MILLISECONDS_DEFAULT = 200;

View File

@ -65,7 +65,6 @@ public class BlockListener implements Listener {
if (!mcMMO.getDynamicSettingsManager().getBonusDropManager().isBonusDropWhitelisted(is.getType())) if (!mcMMO.getDynamicSettingsManager().getBonusDropManager().isBonusDropWhitelisted(is.getType()))
continue; continue;
//TODO: Should just store the amount of drops in the metadata itself and use a loop
if (event.getBlock().getMetadata(MetadataConstants.BONUS_DROPS_METAKEY).size() > 0) { if (event.getBlock().getMetadata(MetadataConstants.BONUS_DROPS_METAKEY).size() > 0) {
BonusDropMeta bonusDropMeta = (BonusDropMeta) event.getBlock().getMetadata(MetadataConstants.BONUS_DROPS_METAKEY).get(0); BonusDropMeta bonusDropMeta = (BonusDropMeta) event.getBlock().getMetadata(MetadataConstants.BONUS_DROPS_METAKEY).get(0);
int bonusCount = bonusDropMeta.asInt(); int bonusCount = bonusDropMeta.asInt();
@ -79,6 +78,30 @@ public class BlockListener implements Listener {
} }
} }
/*@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockDropItemEvent(BlockDropItemEvent event)
{
for(Item item : event.getItems())
{
ItemStack is = new ItemStack(item.getItemStack());
if(event.getBlock().getMetadata(mcMMO.doubleDrops).size() > 0)
{
List<MetadataValue> metadataValue = event.getBlock().getMetadata(mcMMO.doubleDrops);
BonusDrops bonusDrops = (BonusDrops) metadataValue.get(0);
Collection<ItemStack> potentialDrops = (Collection<ItemStack>) bonusDrops.value();
>>>>>>> 2746bac86ac8b201960ac47bc19eac4b84d790a0
for (int i = 0; i < bonusCount; i++) {
event.getBlock().getWorld().dropItemNaturally(event.getBlockState().getLocation(), is);
}
event.getBlock().removeMetadata(MetadataConstants.BONUS_DROPS_METAKEY, plugin);
}
}
}
/** /**
* Monitor BlockPistonExtend events. * Monitor BlockPistonExtend events.
* *

View File

@ -3,7 +3,6 @@ package com.gmail.nossr50.listeners;
import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.AdvancedConfig;
import com.gmail.nossr50.config.WorldBlacklist; import com.gmail.nossr50.config.WorldBlacklist;
import com.gmail.nossr50.core.MetadataConstants; import com.gmail.nossr50.core.MetadataConstants;
import com.gmail.nossr50.datatypes.meta.OldName;
import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType;
import com.gmail.nossr50.datatypes.skills.subskills.interfaces.InteractType; import com.gmail.nossr50.datatypes.skills.subskills.interfaces.InteractType;
@ -38,13 +37,10 @@ import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource; import org.bukkit.projectiles.ProjectileSource;
import java.util.List;
public class EntityListener implements Listener { public class EntityListener implements Listener {
private final mcMMO plugin; private final mcMMO plugin;
@ -67,6 +63,12 @@ public class EntityListener implements Listener {
if (!mcMMO.getConfigManager().getConfigExploitPrevention().getEndermenEndermiteFix()) if (!mcMMO.getConfigManager().getConfigExploitPrevention().getEndermenEndermiteFix())
return; return;
//It's rare but targets can be null sometimes
if(event.getTarget() == null)
{
return;
}
//Prevent entities from giving XP if they target endermite //Prevent entities from giving XP if they target endermite
if (event.getTarget() instanceof Endermite) { if (event.getTarget() instanceof Endermite) {
if (event.getEntity().getMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY) == null || event.getEntity().getMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY).size() <= 0) if (event.getEntity().getMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY) == null || event.getEntity().getMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY).size() <= 0)
@ -363,21 +365,15 @@ public class EntityListener implements Listener {
/** /**
* This sets entity names back to whatever they are supposed to be * This sets entity names back to whatever they are supposed to be
*/ */
if (!(attacker instanceof Player) && defender instanceof Player) { if(event.getFinalDamage() >= target.getHealth())
if (event.getFinalDamage() >= ((LivingEntity) defender).getHealth()) { {
List<MetadataValue> metadataValue = attacker.getMetadata("mcMMO_oldName"); if(attacker instanceof LivingEntity)
{
if (metadataValue.size() <= 0) CombatUtils.fixNames((LivingEntity) attacker);
return;
if (metadataValue != null) {
OldName oldName = (OldName) metadataValue.get(0);
attacker.setCustomName(oldName.asString());
attacker.setCustomNameVisible(false);
}
} }
}
CombatUtils.fixNames(target);
}
} }

View File

@ -382,7 +382,7 @@ public class PlayerListener implements Listener {
case CAUGHT_FISH: case CAUGHT_FISH:
if (mcMMO.getConfigManager().getConfigExploitPrevention().getConfigSectionExploitFishing().isPreventFishingExploits()) { if (mcMMO.getConfigManager().getConfigExploitPrevention().getConfigSectionExploitFishing().isPreventFishingExploits()) {
if (fishingManager.isExploitingFishing(event.getHook().getLocation().toVector())) { if (fishingManager.isExploitingFishing(event.getHook().getLocation().toVector())) {
player.sendMessage(LocaleLoader.getString("Fishing.Scarcity")); player.sendMessage(LocaleLoader.getString("Fishing.ScarcityTip", mcMMO.getConfigManager().getConfigExploitPrevention().getOverFishingAreaSize() * 2));
event.setExpToDrop(0); event.setExpToDrop(0);
Item caughtItem = (Item) caught; Item caughtItem = (Item) caught;
caughtItem.remove(); caughtItem.remove();

View File

@ -48,6 +48,10 @@ public class FishingManager extends SkillManager {
private long fishHookSpawnTimestamp; private long fishHookSpawnTimestamp;
private long lastWarned; private long lastWarned;
private long lastWarnedExhaust; private long lastWarnedExhaust;
public static final int FISHING_ROD_CAST_CD_MILLISECONDS = 100;
private final long FISHING_COOLDOWN_SECONDS = 1000L;
private FishHook fishHookReference;
private BoundingBox lastFishingBoundingBox; private BoundingBox lastFishingBoundingBox;
private Location hookLocation; private Location hookLocation;
private int fishCaughtCounter; private int fishCaughtCounter;
@ -130,7 +134,7 @@ public class FishingManager extends SkillManager {
fishCaughtCounter = 1; fishCaughtCounter = 1;
if (fishCaughtCounter + 1 == overfishLimit) { if (fishCaughtCounter + 1 == overfishLimit) {
getPlayer().sendMessage(LocaleLoader.getString("Fishing.LowResources")); getPlayer().sendMessage(LocaleLoader.getString("Fishing.LowResourcesTip", mcMMO.getConfigManager().getConfigExploitPrevention().getOverFishingAreaSize() * 2));
} }
//If the new bounding box does not intersect with the old one, then update our bounding box reference //If the new bounding box does not intersect with the old one, then update our bounding box reference

View File

@ -85,7 +85,9 @@ public class Herbalism {
protected static int countAndMarkDoubleDropsMultiBlockPlant(BlockState blockState, boolean triple, HerbalismManager herbalismManager) { protected static int countAndMarkDoubleDropsMultiBlockPlant(BlockState blockState, boolean triple, HerbalismManager herbalismManager) {
Block block = blockState.getBlock(); Block block = blockState.getBlock();
Material blockType = blockState.getType(); Material blockType = blockState.getType();
int dropAmount = mcMMO.getPlaceStore().isTrue(block) ? 0 : 1; int dropAmount = 0;
int bonusDropAmount = 0;
int bonusAdd = triple ? 2 : 1;
if (blockType == Material.CHORUS_PLANT) { if (blockType == Material.CHORUS_PLANT) {
dropAmount = 1; dropAmount = 1;
@ -94,6 +96,17 @@ public class Herbalism {
dropAmount = calculateChorusPlantDrops(block, triple, herbalismManager); dropAmount = calculateChorusPlantDrops(block, triple, herbalismManager);
} }
} else { } else {
//Check the block itself first
if(!mcMMO.getPlaceStore().isTrue(block))
{
dropAmount++;
if(herbalismManager.checkDoubleDrop(blockState))
bonusDropAmount+=bonusAdd;
} else {
mcMMO.getPlaceStore().setFalse(blockState);
}
// Handle the two blocks above it - cacti & sugar cane can only grow 3 high naturally // Handle the two blocks above it - cacti & sugar cane can only grow 3 high naturally
for (int y = 1; y < 255; y++) { for (int y = 1; y < 255; y++) {
Block relativeBlock = block.getRelative(BlockFace.UP, y); Block relativeBlock = block.getRelative(BlockFace.UP, y);
@ -107,12 +120,15 @@ public class Herbalism {
} else { } else {
dropAmount++; dropAmount++;
if (herbalismManager.checkDoubleDrop(relativeBlock.getState())) if(herbalismManager.checkDoubleDrop(relativeBlock.getState()))
BlockUtils.markDropsAsBonus(relativeBlock.getState(), triple); bonusDropAmount+=bonusAdd;
} }
} }
} }
//Mark the original block for bonus drops
BlockUtils.markDropsAsBonus(blockState, bonusDropAmount);
return dropAmount; return dropAmount;
} }

View File

@ -249,6 +249,14 @@ public class TamingManager extends SkillManager {
} }
public void attackTarget(LivingEntity target) { public void attackTarget(LivingEntity target) {
if(target instanceof Tameable)
{
Tameable tameable = (Tameable) target;
if(tameable.getOwner() == getPlayer())
{
return;
}
}
double range = 5; double range = 5;
Player player = getPlayer(); Player player = getPlayer();
@ -299,36 +307,36 @@ public class TamingManager extends SkillManager {
} }
location = Misc.getLocationOffset(location, 1); location = Misc.getLocationOffset(location, 1);
LivingEntity entity = (LivingEntity) player.getWorld().spawnEntity(location, type); LivingEntity callOfWildEntity = (LivingEntity) player.getWorld().spawnEntity(location, type);
FakeEntityTameEvent event = new FakeEntityTameEvent(entity, player); FakeEntityTameEvent event = new FakeEntityTameEvent(callOfWildEntity, player);
mcMMO.p.getServer().getPluginManager().callEvent(event); mcMMO.p.getServer().getPluginManager().callEvent(event);
if (event.isCancelled()) { if (event.isCancelled()) {
continue; continue;
} }
entity.setMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY, MetadataConstants.metadataValue); callOfWildEntity.setMetadata(MetadataConstants.UNNATURAL_MOB_METAKEY, MetadataConstants.metadataValue);
((Tameable) entity).setOwner(player); ((Tameable) callOfWildEntity).setOwner(player);
entity.setRemoveWhenFarAway(false); callOfWildEntity.setRemoveWhenFarAway(false);
addToTracker(entity); addToTracker(callOfWildEntity);
switch (type) { switch (type) {
case OCELOT: case OCELOT:
((Ocelot) entity).setCatType(Ocelot.Type.values()[1 + Misc.getRandom().nextInt(3)]); ((Ocelot) callOfWildEntity).setCatType(Ocelot.Type.values()[1 + Misc.getRandom().nextInt(3)]);
break; break;
case WOLF: case WOLF:
entity.setMaxHealth(20.0); callOfWildEntity.setMaxHealth(20.0);
entity.setHealth(entity.getMaxHealth()); callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth());
break; break;
case HORSE: case HORSE:
Horse horse = (Horse) entity; Horse horse = (Horse) callOfWildEntity;
entity.setMaxHealth(15.0 + (Misc.getRandom().nextDouble() * 15)); callOfWildEntity.setMaxHealth(15.0 + (Misc.getRandom().nextDouble() * 15));
entity.setHealth(entity.getMaxHealth()); callOfWildEntity.setHealth(callOfWildEntity.getMaxHealth());
horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]); horse.setColor(Horse.Color.values()[Misc.getRandom().nextInt(Horse.Color.values().length)]);
horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]); horse.setStyle(Horse.Style.values()[Misc.getRandom().nextInt(Horse.Style.values().length)]);
horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength()))); horse.setJumpStrength(Math.max(AdvancedConfig.getInstance().getMinHorseJumpStrength(), Math.min(Math.min(Misc.getRandom().nextDouble(), Misc.getRandom().nextDouble()) * 2, AdvancedConfig.getInstance().getMaxHorseJumpStrength())));
@ -340,10 +348,10 @@ public class TamingManager extends SkillManager {
} }
if (Permissions.renamePets(player)) { if (Permissions.renamePets(player)) {
entity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", player.getName(), StringUtils.getPrettyEntityTypeString(type))); callOfWildEntity.setCustomName(LocaleLoader.getString("Taming.Summon.Name.Format", player.getName(), StringUtils.getPrettyEntityTypeString(type)));
} }
ParticleEffectUtils.playCallOfTheWildEffect(entity); ParticleEffectUtils.playCallOfTheWildEffect(callOfWildEntity);
} }
ItemStack leftovers = new ItemStack(heldItem); ItemStack leftovers = new ItemStack(heldItem);

View File

@ -35,6 +35,15 @@ public final class BlockUtils {
blockState.setMetadata(MetadataConstants.BONUS_DROPS_METAKEY, new BonusDropMeta(1, mcMMO.p)); blockState.setMetadata(MetadataConstants.BONUS_DROPS_METAKEY, new BonusDropMeta(1, mcMMO.p));
} }
/**
* Marks a block to drop extra copies of items
* @param blockState target blockstate
* @param amount amount of extra items to drop
*/
public static void markDropsAsBonus(BlockState blockState, int amount) {
blockState.setMetadata(MetadataConstants.BONUS_DROPS_METAKEY, new BonusDropMeta(amount, mcMMO.p));
}
/** /**
* Checks if a player successfully passed the double drop check * Checks if a player successfully passed the double drop check
* *

View File

@ -4,6 +4,7 @@ import com.gmail.nossr50.core.MetadataConstants;
import com.gmail.nossr50.datatypes.experience.SpecialXPKey; import com.gmail.nossr50.datatypes.experience.SpecialXPKey;
import com.gmail.nossr50.datatypes.experience.XPGainReason; import com.gmail.nossr50.datatypes.experience.XPGainReason;
import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.interactions.NotificationType;
import com.gmail.nossr50.datatypes.meta.OldName;
import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.McMMOPlayer;
import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType;
@ -31,10 +32,12 @@ import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause; import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityDamageEvent.DamageModifier; import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.projectiles.ProjectileSource; import org.bukkit.projectiles.ProjectileSource;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
public final class CombatUtils { public final class CombatUtils {
@ -347,6 +350,25 @@ public final class CombatUtils {
} }
} }
/**
* This cleans up names from displaying in chat as hearts
* @param entity target entity
*/
public static void fixNames(LivingEntity entity)
{
List<MetadataValue> metadataValue = entity.getMetadata("mcMMO_oldName");
if(metadataValue.size() <= 0)
return;
if(metadataValue != null)
{
OldName oldName = (OldName) metadataValue.get(0);
entity.setCustomName(oldName.asString());
entity.setCustomNameVisible(false);
}
}
public static int getLimitBreakDamage(Player player, SubSkillType subSkillType) { public static int getLimitBreakDamage(Player player, SubSkillType subSkillType) {
return RankUtils.getRank(player, subSkillType); return RankUtils.getRank(player, subSkillType);
} }

View File

@ -215,11 +215,11 @@ Excavation.Skills.GigaDrillBreaker.Refresh=[[GREEN]]Your [[YELLOW]]Giga Drill Br
Excavation.Skills.GigaDrillBreaker.Other.Off=Giga Drill Breaker[[GREEN]] has worn off for [[YELLOW]]{0} Excavation.Skills.GigaDrillBreaker.Other.Off=Giga Drill Breaker[[GREEN]] has worn off for [[YELLOW]]{0}
Excavation.Skills.GigaDrillBreaker.Other.On=[[GREEN]]{0}[[DARK_GREEN]] has used [[RED]]Giga Drill Breaker! Excavation.Skills.GigaDrillBreaker.Other.On=[[GREEN]]{0}[[DARK_GREEN]] has used [[RED]]Giga Drill Breaker!
#FISHING #FISHING
Fishing.Scarcity=[[YELLOW]]&oThis area is suffering from overfishing, try fishing in a new area. Fishing.ScarcityTip=[[YELLOW]]&oThis area is suffering from overfishing, cast your rod in a different spot for more fish. At least {0} blocks away.
Fishing.Scared=[[GRAY]]&oChaotic movements will scare fish! Fishing.Scared=[[GRAY]]&oChaotic movements will scare fish!
Fishing.Exhausting=[[RED]]&oImproper use of the fishing rod will cause fatigue and wear out the rod! Fishing.Exhausting=[[RED]]&oImproper use of the fishing rod will cause fatigue and wear out the rod!
Fishing.LowResources=[[GRAY]]You sense that there might not be many fish left in this area.
Fishing.OverFishingDetected=[[YELLOW]]Player named &r{0}[[YELLOW]]has over-fished three times in a row at the same location, potential abuse detected. Fishing.OverFishingDetected=[[YELLOW]]Player named &r{0}[[YELLOW]]has over-fished three times in a row at the same location, potential abuse detected.
Fishing.LowResourcesTip=[[GRAY]]You sense that there might not be many fish left in this area. Try fishing at least {0} blocks away.
Fishing.Ability.Info=Magic Hunter: [[GRAY]] **Improves With Treasure Hunter Rank** Fishing.Ability.Info=Magic Hunter: [[GRAY]] **Improves With Treasure Hunter Rank**
Fishing.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (SHAKE) Fishing.Ability.Locked.0=LOCKED UNTIL {0}+ SKILL (SHAKE)
Fishing.Ability.Locked.1=LOCKED UNTIL {0}+ SKILL (ICE FISHING) Fishing.Ability.Locked.1=LOCKED UNTIL {0}+ SKILL (ICE FISHING)
@ -474,7 +474,7 @@ Taming.Summon.Fail.Ocelot=[[RED]]You have too many ocelots nearby to summon any
Taming.Summon.Fail.Wolf=[[RED]]You have too many wolves nearby to summon any more. Taming.Summon.Fail.Wolf=[[RED]]You have too many wolves nearby to summon any more.
Taming.Summon.Fail.Horse=[[RED]]You have too many horses nearby to summon any more. Taming.Summon.Fail.Horse=[[RED]]You have too many horses nearby to summon any more.
Taming.Summon.Fail.TooMany=[[RED]]You have reached the maximum limit of pets to summon. [[YELLOW]]({0}) Taming.Summon.Fail.TooMany=[[RED]]You have reached the maximum limit of pets to summon. [[YELLOW]]({0})
Taming.Summon.Name.Format={0}''s {1} Taming.Summon.Name.Format={0}'s {1}
#UNARMED #UNARMED
Unarmed.Ability.Bonus.0=Iron Arm Style Unarmed.Ability.Bonus.0=Iron Arm Style
Unarmed.Ability.Bonus.1=+{0} DMG Upgrade Unarmed.Ability.Bonus.1=+{0} DMG Upgrade