commit 155d28401eda78148a163fafbeb1a457512e10a9 Author: Sindusk Date: Fri Mar 30 17:23:56 2018 -0400 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/src/mod/sin/armoury/ArmourTweaks.java b/src/mod/sin/armoury/ArmourTweaks.java new file mode 100644 index 0000000..c2bca8c --- /dev/null +++ b/src/mod/sin/armoury/ArmourTweaks.java @@ -0,0 +1,132 @@ +package mod.sin.armoury; + +import java.util.logging.Logger; + +import org.gotti.wurmunlimited.modloader.ReflectionUtil; +import org.gotti.wurmunlimited.modloader.classhooks.HookManager; + +import com.wurmonline.server.Server; +import com.wurmonline.server.combat.Armour; +import com.wurmonline.server.combat.ArmourTypes; +import com.wurmonline.server.items.Item; +import com.wurmonline.server.items.Materials; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.NotFoundException; +import mod.sin.lib.Util; + +public class ArmourTweaks { + public static Logger logger = Logger.getLogger(ArmourTweaks.class.getName()); + + public static ArmouryMod mod; + + public static float newGetArmourModFor(Item armour){ + int armourType; + float toReturn = 0.0f; + if (armour != null && (armourType = armour.getArmourType()) > -1) { + if(mod.armourTypeReduction.containsKey(armourType)){ + toReturn = mod.armourTypeReduction.get(armourType)-mod.unarmouredReduction; + }else{ + logger.severe("[ERROR]: Could not find armour reduction reference for armour type "+armourType); + toReturn = 0f; + } + if (mod.armourReductionOverride.containsKey(armour.getTemplateId())){ + toReturn = mod.armourReductionOverride.get(armour.getTemplateId())-mod.unarmouredReduction; + } + if ((armourType == ArmourTypes.ARMOUR_RING || armourType == ArmourTypes.ARMOUR_CHAIN) && armour.getMaterial() == Materials.MATERIAL_STEEL){ + toReturn += 0.02f; + } + if (armour.getMaterial() == Materials.MATERIAL_GLIMMERSTEEL){ + toReturn += mod.glimmersteelMaterialMod; + } else if(armour.getMaterial() == Materials.MATERIAL_SERYLL) { + toReturn += mod.seryllMaterialMod; + } else if (armour.getMaterial() == Materials.MATERIAL_ADAMANTINE) { + toReturn += mod.adamantineMaterialMod; + } + toReturn *= 1.0f + Armour.getRarityArmourBonus(armour.getRarity()); + toReturn = mod.unarmouredReduction + (float)((double)toReturn * Server.getBuffedQualityEffect(armour.getCurrentQualityLevel() / 100.0f)); + } + return 1.0f - toReturn; + } + + public static void setArmourLimitFactors(ArmouryMod mod){ + try{ + logger.info("Setting armour limit factors"); + for(Armour armour : mod.clothArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.clothArmourLimitFactor); + } + for(Armour armour : mod.leatherArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.leatherArmourLimitFactor); + } + for(Armour armour : mod.studdedArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.studdedArmourLimitFactor); + } + for(Armour armour : mod.chainArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.chainArmourLimitFactor); + } + for(Armour armour : mod.plateArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.plateArmourLimitFactor); + } + for(Armour armour : mod.drakeArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.drakeArmourLimitFactor); + } + for(Armour armour : mod.dragonscaleArmour){ + ReflectionUtil.setPrivateField(armour, ReflectionUtil.getField(armour.getClass(), "limitingFactor"), mod.dragonscaleArmourLimitFactor); + } + } catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public static void preInit(ArmouryMod mod){ + ArmourTweaks.mod = mod; + try { + ClassPool classPool = HookManager.getInstance().getClassPool(); + final Class thisClass = ArmourTweaks.class; + + if(mod.enableArmourReductionModifications){ + CtClass ctArmour = classPool.get("com.wurmonline.server.combat.Armour"); + String body = "" + + "{" + + " return "+ArmourTweaks.class.getName()+".newGetArmourModFor($1);" + + "}"; + Util.setBodyDeclared(thisClass, ctArmour, "getArmourModFor", body); + /*ctArmour.getDeclaredMethod("getArmourModFor").setBody("{ " + + "return "+ArmourTweaks.class.getName()+".newGetArmourModFor($1); }");*/ + } + } catch (NotFoundException e) { + e.printStackTrace(); + } + } + + public static void onItemTemplatesCreated(ArmouryMod mod){ + try { + if(mod.enableArmourMovementModifications){ + logger.info("Starting armour movement modifications..."); + for(String armourName : mod.armourMovement.keySet()){ + int armourTemplate = 0; + if(mod.armourNameToItemTemplate.containsKey(armourName)){ + armourTemplate = mod.armourNameToItemTemplate.get(armourName); + }else{ + logger.severe("[ERROR]: Could not edit armour movement for item name \""+armourName+"\". It may be invalid."); + continue; + } + Armour armourToEdit = Armour.getArmour(armourTemplate); + if(armourToEdit != null){ + float oldValue = ReflectionUtil.getPrivateField(armourToEdit, ReflectionUtil.getField(armourToEdit.getClass(), "movemodifier")); + ReflectionUtil.setPrivateField(armourToEdit, ReflectionUtil.getField(armourToEdit.getClass(), "movemodifier"), mod.armourMovement.get(armourName)); + logger.info("Editing movement modifier for armour \""+armourName+"\": From "+oldValue+" to "+mod.armourMovement.get(armourName)); + }else{ + logger.severe("[ERROR]: Could not edit armour movement for item name \""+armourName+"\". It may be invalid."); + } + } + } + if(mod.enableCustomArmourLimitFactors){ + setArmourLimitFactors(mod); + } + } catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + e.printStackTrace(); + } + } +} diff --git a/src/mod/sin/armoury/ArmouryMod.java b/src/mod/sin/armoury/ArmouryMod.java new file mode 100644 index 0000000..706dae8 --- /dev/null +++ b/src/mod/sin/armoury/ArmouryMod.java @@ -0,0 +1,342 @@ +package mod.sin.armoury; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.gotti.wurmunlimited.modloader.interfaces.Configurable; +import org.gotti.wurmunlimited.modloader.interfaces.ItemTemplatesCreatedListener; +import org.gotti.wurmunlimited.modloader.interfaces.PreInitable; +import org.gotti.wurmunlimited.modloader.interfaces.ServerStartedListener; +import org.gotti.wurmunlimited.modloader.interfaces.WurmServerMod; + +import com.wurmonline.server.combat.Armour; +import com.wurmonline.server.combat.ArmourTypes; +import com.wurmonline.server.items.ItemList; +import com.wurmonline.server.items.ItemTemplate; +import com.wurmonline.server.items.ItemTemplateFactory; + +public class ArmouryMod +implements WurmServerMod, Configurable, PreInitable, ItemTemplatesCreatedListener, ServerStartedListener { + private Logger logger; + + // Configuration options + public boolean bDebug = false; + public boolean enableNonPlayerCrits = true; + public boolean fixArmourLimitBuffBug = true; + public boolean fixArmourLimitSpellEffect = true; + + // -- Armour configuration -- // + public boolean enableArmourReductionModifications = true; + public float unarmouredReduction = 0.05f; + // Armour Mapping + public String[] armourTypes = {"cloth", "leather", "studded", "chain", "plate", "drake", "dragonscale", // Worn armour pieces + "scale", "ring", "splint"}; // Used by the system but not worn by players + public HashMap armourTypeReduction = new HashMap(); + public HashMap armourTypeReference = new HashMap(); + // Armour modifiers + public float adamantineMaterialMod = 0.05f; + public float glimmersteelMaterialMod = 0.1f; + public float seryllMaterialMod = 0.1f; + // Armour limit factors + public boolean enableCustomArmourLimitFactors = true; + public float clothArmourLimitFactor = 0.3f; + public float leatherArmourLimitFactor = 0.3f; + public float studdedArmourLimitFactor = 0.0f; + public float chainArmourLimitFactor = -0.15f; + public float plateArmourLimitFactor = -0.3f; + public float drakeArmourLimitFactor = -0.3f; + public float dragonscaleArmourLimitFactor = -0.3f; + public HashMap armourReductionOverride = new HashMap(); + // Armour movement + public boolean enableArmourMovementModifications = true; + public HashMap armourMovement = new HashMap(); + + // - Shield configuration -- // + public boolean enableShieldDamageEnchants = true; + public boolean enableShieldSpeedEnchants = true; + + // -- Weapon configuration -- // + public float minimumSwingTime = 3.0f; + public boolean raresReduceSwingTime = true; + public float rareSwingSpeedReduction = 0.2f; + public boolean fixSavedSwingTimer = true; + public boolean betterDualWield = true; // HIGHLY EXPERIMENTAL + // Weapon variable changes + public HashMap weaponDamage = new HashMap(); + public HashMap weaponSpeed = new HashMap(); + public HashMap weaponCritChance = new HashMap(); + public HashMap weaponReach = new HashMap(); + public HashMap weaponWeightGroup = new HashMap(); + public HashMap weaponParryPercent = new HashMap(); + public HashMap weaponSkillPenalty = new HashMap(); + + public ArmouryMod(){ + this.logger = Logger.getLogger(this.getClass().getName()); + } + + @Override + public void configure(Properties properties) { + this.logger.info("Beginning configuration... [Testing]"); + // Base configuration options + this.bDebug = Boolean.parseBoolean(properties.getProperty("debug", Boolean.toString(this.bDebug))); + this.enableNonPlayerCrits = Boolean.parseBoolean(properties.getProperty("enableNonPlayerCrits", Boolean.toString(this.enableNonPlayerCrits))); + this.fixArmourLimitBuffBug = Boolean.parseBoolean(properties.getProperty("fixArmourLimitBuffBug", Boolean.toString(this.fixArmourLimitBuffBug))); + this.fixArmourLimitSpellEffect = Boolean.parseBoolean(properties.getProperty("fixArmourLimitSpellEffect", Boolean.toString(this.fixArmourLimitSpellEffect))); + // Armour configuration + this.initArmourDefaults(); // Create references for use soon. + this.enableArmourReductionModifications = Boolean.parseBoolean(properties.getProperty("enableArmourReductionModifications", Boolean.toString(this.enableArmourReductionModifications))); + if(enableArmourReductionModifications){ + this.unarmouredReduction = Float.parseFloat(properties.getProperty("unarmouredReduction", Float.toString(this.unarmouredReduction))); + for(String armourType : armourTypes){ + int armourNum = armourTypeReference.get(armourType); + float defaultVal = armourTypeReduction.get(armourNum); + armourTypeReduction.put(armourNum, Float.parseFloat(properties.getProperty(armourType+"Reduction", Float.toString(defaultVal)))); + if(armourTypeReduction.get(armourNum) <= 0f){ + this.logger.warning("[ERROR]: Armour type \""+armourType+"\" not set properly the Armour Reduction configuration in armoury.properties! It will not reduce damage at all until resolved!"); + } + } + } + this.adamantineMaterialMod = Float.parseFloat(properties.getProperty("adamantineMaterialMod", Float.toString(this.adamantineMaterialMod))); + this.glimmersteelMaterialMod = Float.parseFloat(properties.getProperty("glimmersteelMaterialMod", Float.toString(this.glimmersteelMaterialMod))); + this.seryllMaterialMod = Float.parseFloat(properties.getProperty("seryllMaterialMod", Float.toString(this.seryllMaterialMod))); + // Armour limit factors + this.enableCustomArmourLimitFactors = Boolean.parseBoolean(properties.getProperty("enableCustomArmourLimitFactors", Boolean.toString(this.enableCustomArmourLimitFactors))); + this.clothArmourLimitFactor = Float.parseFloat(properties.getProperty("clothArmourLimitFactor", Float.toString(this.clothArmourLimitFactor))); + this.leatherArmourLimitFactor = Float.parseFloat(properties.getProperty("leatherArmourLimitFactor", Float.toString(this.leatherArmourLimitFactor))); + this.studdedArmourLimitFactor = Float.parseFloat(properties.getProperty("studdedArmourLimitFactor", Float.toString(this.studdedArmourLimitFactor))); + this.chainArmourLimitFactor = Float.parseFloat(properties.getProperty("chainArmourLimitFactor", Float.toString(this.chainArmourLimitFactor))); + this.plateArmourLimitFactor = Float.parseFloat(properties.getProperty("plateArmourLimitFactor", Float.toString(this.plateArmourLimitFactor))); + this.drakeArmourLimitFactor = Float.parseFloat(properties.getProperty("drakeArmourLimitFactor", Float.toString(this.drakeArmourLimitFactor))); + this.dragonscaleArmourLimitFactor = Float.parseFloat(properties.getProperty("dragonscaleArmourLimitFactor", Float.toString(this.dragonscaleArmourLimitFactor))); + // Armour movement modifiers + this.enableArmourMovementModifications = Boolean.parseBoolean(properties.getProperty("enableArmourMovementModifications", Boolean.toString(this.enableArmourMovementModifications))); + // Shield configuration + this.enableShieldDamageEnchants = Boolean.parseBoolean(properties.getProperty("enableShieldDamageEnchants", Boolean.toString(this.enableShieldDamageEnchants))); + // Weapon configuration + this.minimumSwingTime = Float.parseFloat(properties.getProperty("minimumSwingTime", Float.toString(this.minimumSwingTime))); + this.raresReduceSwingTime = Boolean.parseBoolean(properties.getProperty("raresReduceSwingTime", Boolean.toString(this.raresReduceSwingTime))); + this.rareSwingSpeedReduction = Float.parseFloat(properties.getProperty("rareSwingSpeedReduction", Float.toString(this.rareSwingSpeedReduction))); + this.fixSavedSwingTimer = Boolean.parseBoolean(properties.getProperty("fixSavedSwingTimer", Boolean.toString(this.fixSavedSwingTimer))); + this.betterDualWield = Boolean.parseBoolean(properties.getProperty("betterDualWield", Boolean.toString(this.betterDualWield))); + for (String name : properties.stringPropertyNames()) { + try { + String value = properties.getProperty(name); + switch (name) { + case "debug": + case "classname": + case "classpath": + case "sharedClassLoader": + break; //ignore + default: + if (name.startsWith("armourMovement")) { + String[] split = value.split(","); + String armourName = split[0]; + float newVal = Float.parseFloat(split[1]); + armourMovement.put(armourName, newVal); + } else if (name.startsWith("armourReductionOverride")) { + String[] split = value.split(","); + int armourId = Integer.parseInt(split[0]); + float reductionValue = Float.parseFloat(split[1]); + armourReductionOverride.put(armourId, reductionValue); + } else if (name.startsWith("weaponDamage")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + float newVal = Float.parseFloat(split[1]); + weaponDamage.put(weaponId, newVal); + } else if (name.startsWith("weaponSpeed")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + float newVal = Float.parseFloat(split[1]); + weaponSpeed.put(weaponId, newVal); + } else if (name.startsWith("weaponCritChance")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + float newVal = Float.parseFloat(split[1]); + weaponCritChance.put(weaponId, newVal); + } else if (name.startsWith("weaponReach")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + int newVal = Integer.parseInt(split[1]); + weaponReach.put(weaponId, newVal); + } else if (name.startsWith("weaponWeightGroup")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + int newVal = Integer.parseInt(split[1]); + weaponWeightGroup.put(weaponId, newVal); + } else if (name.startsWith("weaponParryPercent")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + float newVal = Float.parseFloat(split[1]); + weaponParryPercent.put(weaponId, newVal); + } else if (name.startsWith("weaponSkillPenalty")) { + String[] split = value.split(","); + int weaponId = Integer.parseInt(split[0]); + double newVal = Double.parseDouble(split[1]); + weaponSkillPenalty.put(weaponId, newVal); + } else { + //Debug("Unknown config property: " + name); + } + } + } catch (Exception e) { + Debug("Error processing property " + name); + e.printStackTrace(); + } + } + // Print values of mod configuration + this.logger.info(" -- Mod Configuration -- "); + this.logger.log(Level.INFO, "enableNonPlayerCrits: " + this.enableNonPlayerCrits); + this.logger.log(Level.INFO, "fixArmourLimitBuffBug: " + this.fixArmourLimitBuffBug); + this.logger.log(Level.INFO, "fixArmourLimitSpellEffect: " + this.fixArmourLimitSpellEffect); + this.logger.info(" -- Armour Configuration -- "); + this.logger.log(Level.INFO, "enableArmourReductionModifications: " + this.enableArmourReductionModifications); + if(enableArmourReductionModifications){ + this.logger.log(Level.INFO, "unarmouredReduction: " + this.unarmouredReduction); + this.logger.info("> Armour Reduction Settings <"); + for(String armourType : armourTypeReference.keySet()){ + this.logger.info(armourType+" - "+((int)(armourTypeReduction.get(armourTypeReference.get(armourType))*100))+"%"); + } + } + this.logger.log(Level.INFO, "adamantineMaterialMod: " + this.adamantineMaterialMod); + this.logger.log(Level.INFO, "glimmersteelMaterialMod: " + this.glimmersteelMaterialMod); + this.logger.log(Level.INFO, "seryllMaterialMod: " + this.seryllMaterialMod); + this.logger.log(Level.INFO, "enableCustomArmourLimitFactors: " + this.enableCustomArmourLimitFactors); + if(enableCustomArmourLimitFactors){ + this.logger.log(Level.INFO, "clothArmourLimitFactor: " + this.clothArmourLimitFactor); + this.logger.log(Level.INFO, "leatherArmourLimitFactor: " + this.leatherArmourLimitFactor); + this.logger.log(Level.INFO, "studdedArmourLimitFactor: " + this.studdedArmourLimitFactor); + this.logger.log(Level.INFO, "chainArmourLimitFactor: " + this.chainArmourLimitFactor); + this.logger.log(Level.INFO, "plateArmourLimitFactor: " + this.plateArmourLimitFactor); + this.logger.log(Level.INFO, "drakeArmourLimitFactor: " + this.drakeArmourLimitFactor); + this.logger.log(Level.INFO, "dragonscaleArmourLimitFactor: " + this.dragonscaleArmourLimitFactor); + } + this.logger.info(" -- Shield Configuration -- "); + this.logger.log(Level.INFO, "enableShieldDamageEnchants: " + this.enableShieldDamageEnchants); + this.logger.info(" -- Weapon Configuration -- "); + this.logger.log(Level.INFO, "minimumSwingTime: " + this.minimumSwingTime); + this.logger.log(Level.INFO, "raresReduceSwingTime: " + this.raresReduceSwingTime); + this.logger.log(Level.INFO, "rareSwingSpeedReduction: " + this.rareSwingSpeedReduction); + this.logger.log(Level.INFO, "fixSavedSwingTimer: " + this.fixSavedSwingTimer); + this.logger.log(Level.INFO, "betterDualWield: " + this.betterDualWield); + this.Debug("Debugging messages are enabled."); + this.logger.info(" -- Configuration complete -- "); + } + + protected void Debug(String x) { + if (this.bDebug) { + System.out.println(String.valueOf(this.getClass().getSimpleName()) + ": " + x); + System.out.flush(); + this.logger.log(Level.INFO, x); + } + } + + @Override + public void preInit(){ + CombatTweaks.preInit(this); + ArmourTweaks.preInit(this); + ShieldTweaks.preInit(this); + } + + @Override + public void onItemTemplatesCreated(){ + logger.info("Creating armour template lists..."); + createArmourTemplateLists(); + ArmourTweaks.onItemTemplatesCreated(this); + } + + @Override + public void onServerStarted(){ + WeaponTweaks.onServerStarted(this); + } + + public HashMap armourNameToItemTemplate = new HashMap(); + + public ArrayList clothArmour = new ArrayList(); + public ArrayList leatherArmour = new ArrayList(); + public ArrayList studdedArmour = new ArrayList(); + public ArrayList chainArmour = new ArrayList(); + public ArrayList plateArmour = new ArrayList(); + public ArrayList drakeArmour = new ArrayList(); + public ArrayList dragonscaleArmour = new ArrayList(); + + private void addArmour(ArrayList typeList, int itemTemplate){ + ItemTemplate it = ItemTemplateFactory.getInstance().getTemplateOrNull(itemTemplate); + if(it != null){ + armourNameToItemTemplate.put(it.getName(), itemTemplate); + } + typeList.add(Armour.getArmour(itemTemplate)); + } + + public void createArmourTemplateLists(){ + addArmour(clothArmour, ItemList.clothHood); + addArmour(clothArmour, ItemList.clothSleeve); + addArmour(clothArmour, ItemList.clothJacket); + addArmour(clothArmour, ItemList.clothShirt); + addArmour(clothArmour, ItemList.clothGlove); + addArmour(clothArmour, ItemList.clothHose); + addArmour(clothArmour, ItemList.clothShoes); + addArmour(leatherArmour, ItemList.leatherHat0); + addArmour(leatherArmour, ItemList.leatherCap); + addArmour(leatherArmour, ItemList.leatherSleeve); + addArmour(leatherArmour, ItemList.leatherJacket); + addArmour(leatherArmour, ItemList.leatherGlove); + addArmour(leatherArmour, ItemList.leatherHose); + addArmour(leatherArmour, ItemList.leatherBoot); + addArmour(studdedArmour, ItemList.studdedLeatherCap); + addArmour(studdedArmour, ItemList.studdedLeatherSleeve); + addArmour(studdedArmour, ItemList.studdedLeatherJacket); + addArmour(studdedArmour, ItemList.studdedLeatherGlove); + addArmour(studdedArmour, ItemList.studdedLeatherHose); + addArmour(studdedArmour, ItemList.studdedLeatherBoot); + addArmour(chainArmour, ItemList.chainCoif); + addArmour(chainArmour, ItemList.chainSleeve); + addArmour(chainArmour, ItemList.chainJacket); + addArmour(chainArmour, ItemList.chainGlove); + addArmour(chainArmour, ItemList.chainHose); + addArmour(chainArmour, ItemList.chainBoot); + addArmour(plateArmour, ItemList.helmetGreat); + addArmour(plateArmour, ItemList.helmetBasinet); + addArmour(plateArmour, ItemList.helmetOpen); + addArmour(plateArmour, ItemList.plateSleeve); + addArmour(plateArmour, ItemList.plateJacket); + addArmour(plateArmour, ItemList.plateGauntlet); + addArmour(plateArmour, ItemList.plateHose); + addArmour(plateArmour, ItemList.plateBoot); + addArmour(drakeArmour, ItemList.dragonLeatherCap); + addArmour(drakeArmour, ItemList.dragonLeatherSleeve); + addArmour(drakeArmour, ItemList.dragonLeatherJacket); + addArmour(drakeArmour, ItemList.dragonLeatherGlove); + addArmour(drakeArmour, ItemList.dragonLeatherHose); + addArmour(drakeArmour, ItemList.dragonLeatherBoot); + addArmour(dragonscaleArmour, ItemList.dragonScaleSleeve); + addArmour(dragonscaleArmour, ItemList.dragonScaleJacket); + addArmour(dragonscaleArmour, ItemList.dragonScaleGauntlet); + addArmour(dragonscaleArmour, ItemList.dragonScaleHose); + addArmour(dragonscaleArmour, ItemList.dragonScaleBoot); + } + + private void initArmourDefaults(){ + armourTypeReference.put("cloth", ArmourTypes.ARMOUR_CLOTH); + armourTypeReduction.put(ArmourTypes.ARMOUR_CLOTH, 0.4f); + armourTypeReference.put("leather", ArmourTypes.ARMOUR_LEATHER); + armourTypeReduction.put(ArmourTypes.ARMOUR_LEATHER, 0.5f); + armourTypeReference.put("studded", ArmourTypes.ARMOUR_STUDDED); + armourTypeReduction.put(ArmourTypes.ARMOUR_STUDDED, 0.55f); + armourTypeReference.put("chain", ArmourTypes.ARMOUR_CHAIN); + armourTypeReduction.put(ArmourTypes.ARMOUR_CHAIN, 0.6f); + armourTypeReference.put("plate", ArmourTypes.ARMOUR_PLATE); + armourTypeReduction.put(ArmourTypes.ARMOUR_PLATE, 0.7f); + armourTypeReference.put("drake", ArmourTypes.ARMOUR_LEATHER_DRAGON); + armourTypeReduction.put(ArmourTypes.ARMOUR_LEATHER_DRAGON, 0.7f); + armourTypeReference.put("dragonscale", ArmourTypes.ARMOUR_SCALE_DRAGON); + armourTypeReduction.put(ArmourTypes.ARMOUR_SCALE_DRAGON, 0.75f); + armourTypeReference.put("scale", ArmourTypes.ARMOUR_SCALE); + armourTypeReduction.put(ArmourTypes.ARMOUR_SCALE, 0.5f); + armourTypeReference.put("ring", ArmourTypes.ARMOUR_RING); + armourTypeReduction.put(ArmourTypes.ARMOUR_RING, 0.55f); + armourTypeReference.put("splint", ArmourTypes.ARMOUR_SPLINT); + armourTypeReduction.put(ArmourTypes.ARMOUR_SPLINT, 0.6f); + } +} diff --git a/src/mod/sin/armoury/CombatTweaks.java b/src/mod/sin/armoury/CombatTweaks.java new file mode 100644 index 0000000..528287d --- /dev/null +++ b/src/mod/sin/armoury/CombatTweaks.java @@ -0,0 +1,302 @@ +package mod.sin.armoury; + +import org.gotti.wurmunlimited.modloader.ReflectionUtil; +import org.gotti.wurmunlimited.modloader.classhooks.HookManager; + +import com.wurmonline.server.Server; +import com.wurmonline.server.creatures.CombatHandler; +import com.wurmonline.server.creatures.Creature; +import com.wurmonline.server.creatures.SpellEffectsEnum; +import com.wurmonline.server.items.Item; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CtClass; +import javassist.CtPrimitiveType; +import javassist.NotFoundException; +import javassist.bytecode.Descriptor; +import javassist.expr.ExprEditor; +import javassist.expr.MethodCall; +import mod.sin.lib.Util; + +public class CombatTweaks { + public static Item handleDualWieldAttack(CombatHandler handler, Creature opponent, float delta){ + try { + Creature performer = ReflectionUtil.getPrivateField(handler, ReflectionUtil.getField(handler.getClass(), "creature")); + for(Item weapon : performer.getSecondaryWeapons()){ + if(Server.rand.nextBoolean()) continue; + float time = handler.getSpeed(weapon); + float timer = performer.addToWeaponUsed(weapon, delta); + if(timer > time){ + performer.deductFromWeaponUsed(weapon, time); + return weapon; + } + } + return null; + } catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + e.printStackTrace(); + return null; + } + } + + public static void preInit(ArmouryMod mod){ + try { + ClassPool classPool = HookManager.getInstance().getClassPool(); + Class thisClass = CombatTweaks.class; + + // - Allow critical hits on creatures as well as players - + mod.enableNonPlayerCrits = false; // Disabled for now as it's not working. + if(mod.enableNonPlayerCrits){ + CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler"); + CtClass[] attackParams1 = { + classPool.get("com.wurmonline.server.creatures.Creature"), + classPool.get("com.wurmonline.server.items.Item"), + CtPrimitiveType.booleanType + }; + String desc = Descriptor.ofMethod(CtPrimitiveType.booleanType, attackParams1); + Util.setReason("Enable player critical strikes on creatures."); + Util.instrumentDescribed(thisClass, ctCombatHandler, "attack", desc, "isPlayer", "$_ = true"); + /*ctCombatHandler.getMethod("attack", Descriptor.ofMethod(CtPrimitiveType.booleanType, attackParams1)).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("isPlayer")) { + m.replace("$_ = true;"); + return; + } + } + });*/ + CtClass[] attackParams2 = { + classPool.get("com.wurmonline.server.creatures.Creature"), + classPool.get("com.wurmonline.server.creatures.AttackAction") + }; + desc = Descriptor.ofMethod(CtPrimitiveType.booleanType, attackParams2); + Util.setReason("Enable player critical strikes on creatures."); + Util.instrumentDescribed(thisClass, ctCombatHandler, "attack", desc, "isPlayer", "$_ = true"); + /*ctCombatHandler.getMethod("attack", Descriptor.ofMethod(CtPrimitiveType.booleanType, attackParams2)).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("isPlayer")) { + m.replace("$_ = true;"); + return; + } + } + });*/ + } + + // - Fix the Armour Limit being shown in the buff bar at all times - + if(mod.fixArmourLimitBuffBug){ + CtClass ctPlayerInfo = classPool.get("com.wurmonline.server.players.PlayerInfo"); + String replace = "" + + "communicator.sendRemoveSpellEffect(com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_NONE);" + + "communicator.sendRemoveSpellEffect(com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_MEDIUM);" + + "communicator.sendRemoveSpellEffect(com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_HEAVY);" + + "$_ = $proceed($$);"; + Util.setReason("Fix armour limit buff bug."); + Util.instrumentDeclared(thisClass, ctPlayerInfo, "setArmourLimitingFactor", "sendRemoveSpellEffect", replace); + /*ctPlayerInfo.getDeclaredMethod("setArmourLimitingFactor").instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("sendRemoveSpellEffect")) { + m.replace("communicator.sendRemoveSpellEffect(com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_NONE);" + + "communicator.sendRemoveSpellEffect(com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_MEDIUM);" + + "communicator.sendRemoveSpellEffect(com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_HEAVY);" + + "$_ = $proceed($$);"); + return; + } + } + });*/ + replace = "if($1 == null){" + + " $1 = com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_NONE;" + + "}" + + "$_ = $proceed($$);" + + "communicator.sendAddSpellEffect($1, 100000, this.limitingArmourFactor*100.0f);"; + Util.setReason("Fix armour limit buff bug."); + Util.instrumentDeclared(thisClass, ctPlayerInfo, "setArmourLimitingFactor", "sendAddStatusEffect", replace); + ctPlayerInfo.getDeclaredMethod("setArmourLimitingFactor").instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("sendAddStatusEffect")) { + m.replace("if($1 == null){" + + " $1 = com.wurmonline.server.creatures.SpellEffectsEnum.ARMOUR_LIMIT_NONE;" + + "}" + + "$_ = $proceed($$);" + + "communicator.sendAddSpellEffect($1, 100000, this.limitingArmourFactor*100.0f);"); + return; + } + } + }); + } + + // - Make spell effects hud show your armour limit properly - // + if(mod.fixArmourLimitSpellEffect){ + ReflectionUtil.setPrivateField(SpellEffectsEnum.ARMOUR_LIMIT_HEAVY, ReflectionUtil.getField(SpellEffectsEnum.ARMOUR_LIMIT_HEAVY.getClass(), "name"), "Armour Penalty"); + ReflectionUtil.setPrivateField(SpellEffectsEnum.ARMOUR_LIMIT_MEDIUM, ReflectionUtil.getField(SpellEffectsEnum.ARMOUR_LIMIT_MEDIUM.getClass(), "name"), "Armour Penalty"); + ReflectionUtil.setPrivateField(SpellEffectsEnum.ARMOUR_LIMIT_LIGHT, ReflectionUtil.getField(SpellEffectsEnum.ARMOUR_LIMIT_LIGHT.getClass(), "name"), "Armour Bonus"); + ReflectionUtil.setPrivateField(SpellEffectsEnum.ARMOUR_LIMIT_NONE, ReflectionUtil.getField(SpellEffectsEnum.ARMOUR_LIMIT_NONE.getClass(), "name"), "Armour Bonus"); + } + + // - Change the minimum swing timer - // + if(mod.minimumSwingTime != 3.0f){ + CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler"); + String strBuilder = ""; + if(mod.raresReduceSwingTime){ + strBuilder += "" + + "if(weapon.getRarity() > 0){" + + " calcspeed -= weapon.getRarity()*"+String.valueOf(mod.rareSwingSpeedReduction)+"f;" + + "}"; + } + strBuilder += "$_ = $proceed("+String.valueOf(mod.minimumSwingTime)+"f, $2);"; + + final String stringReplace = strBuilder; + CtClass[] params1 = { + classPool.get("com.wurmonline.server.creatures.AttackAction"), + classPool.get("com.wurmonline.server.items.Item") + }; + String desc = Descriptor.ofMethod(CtClass.floatType, params1); + Util.setReason("Adjust swing timer."); + Util.instrumentDescribed(thisClass, ctCombatHandler, "getSpeed", desc, "max", stringReplace); + /*ctCombatHandler.getMethod("getSpeed", desc).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("max")) { + m.replace(stringReplace); + return; + } + } + });*/ + CtClass[] params2 = { classPool.get("com.wurmonline.server.items.Item") }; + desc = Descriptor.ofMethod(CtClass.floatType, params2); + Util.setReason("Adjust swing timer."); + Util.instrumentDescribed(thisClass, ctCombatHandler, "getSpeed", desc, "max", stringReplace); + /*ctCombatHandler.getMethod("getSpeed", desc).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("max")) { + m.replace(stringReplace); + return; + } + } + });*/ + } + + // - Saved swing timer fix - + if(mod.fixSavedSwingTimer){ + CtClass ctCreature = classPool.get("com.wurmonline.server.creatures.Creature"); + String replace = "$_ = $proceed($1, new Float(0f));"; + Util.setReason("Fix saved swing timer."); + Util.instrumentDeclared(thisClass, ctCreature, "deductFromWeaponUsed", "put", replace); + /*ctCreature.getDeclaredMethod("deductFromWeaponUsed").instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("put")) { + m.replace("$_ = $proceed($1, new Float(0f));"); + return; + } + } + });*/ + } + + // - Attempt for a better dual wield system - + // This really doesn't work. I don't get dual wield and why it's so bad. + if(mod.betterDualWield){ + CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler"); + CtClass[] params1 = { + classPool.get("com.wurmonline.server.creatures.Creature"), + CtClass.intType, + CtClass.booleanType, + CtClass.floatType, + classPool.get("com.wurmonline.server.behaviours.Action") + }; + String desc = Descriptor.ofMethod(CtClass.booleanType, params1); + String replace = "if(this.creature.isPlayer()){" + + " com.wurmonline.server.items.Item weapon = mod.sin.armoury.CombatTweaks.handleDualWieldAttack(this, opponent, delta);" + + " if(weapon != null){" + + " lDead = attack(opponent, weapon, true);" + + " }" + + "}" + + "$_ = $proceed($$);"; + Util.setReason("Better Dual Wield"); + Util.instrumentDescribed(thisClass, ctCombatHandler, "attack", desc, "getSecondaryWeapons", replace); + /*ctCombatHandler.getMethod("attack", desc).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("getSecondaryWeapons")) { + m.replace("if(this.creature.isPlayer()){" + + " com.wurmonline.server.items.Item weapon = mod.sin.armoury.CombatTweaks.handleDualWieldAttack(this, opponent, delta);" + + " if(weapon != null){" + + " lDead = attack(opponent, weapon, true);" + + " }" + + "}" + + "$_ = $proceed($$);"); + return; + } + } + });*/ + /*ctCombatHandler.getMethod("attack", desc).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("nextBoolean")) { + m.replace("$_ = true;"); + return; + } + } + });*/ + replace = "if(this.creature.isPlayer()){" + + " $_ = 1;" + + "}else{" + + " $_ = $proceed($$);" + + "}"; + Util.setReason("Better Dual Wield"); + Util.instrumentDescribed(thisClass, ctCombatHandler, "attack", desc, "getHugeMoveCounter", replace); + /*ctCombatHandler.getMethod("attack", desc).instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("getHugeMoveCounter")) { + m.replace("if(this.creature.isPlayer()){" + + " $_ = 1;" + + "}else{" + + " $_ = $proceed($$);" + + "}"); + return; + } + } + });*/ + } + /*CtClass ctCreature = classPool.get("com.wurmonline.server.creatures.Creature"); + ctCreature.getDeclaredMethod("addToWeaponUsed").insertBefore("logger.info(\"Timer for \"+$1.getName()+\" = \"+this.weaponsUsed.get($1));"); + + // Conclusion: This is the "main loop" for combat. It is called very frequently. + CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler"); + CtClass[] params1 = { + classPool.get("com.wurmonline.server.creatures.Creature"), + CtClass.intType, + CtClass.booleanType, + CtClass.floatType, + classPool.get("com.wurmonline.server.behaviours.Action") + }; + String desc = Descriptor.ofMethod(CtClass.booleanType, params1); + CtMethod ctAttack = ctCombatHandler.getMethod("attack", desc); + //ctAttack.insertBefore("logger.info(\"Calling attack(Creature, int, boolean, float, Action)\");"); + ctAttack.instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("deductFromWeaponUsed")) { + m.replace("logger.info(\"Deducting from weapon: \"+$2);" + + "$_ = $proceed($$);"); + return; + } + } + });*/ + + // Conclusion: This apparently is not used in standard combat. + /*CtClass[] params2 = { + classPool.get("com.wurmonline.server.creatures.Creature"), + classPool.get("com.wurmonline.server.creatures.AttackAction") + }; + desc = Descriptor.ofMethod(CtClass.booleanType, params2); + ctCombatHandler.getMethod("attack", desc).insertBefore("logger.info(\"Calling attack(Creature, AttackAction)\");");*/ + + // Conclusion: This is called only when a swing is done. + /*CtClass[] params3 = { + classPool.get("com.wurmonline.server.creatures.Creature"), + classPool.get("com.wurmonline.server.items.Item"), + CtClass.booleanType + }; + desc = Descriptor.ofMethod(CtClass.booleanType, params3); + ctCombatHandler.getMethod("attack", desc).insertBefore("logger.info(\"Calling attack(Creature, Item, boolean)\");");*/ + + } catch (CannotCompileException | NotFoundException | IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/src/mod/sin/armoury/ShieldTweaks.java b/src/mod/sin/armoury/ShieldTweaks.java new file mode 100644 index 0000000..04a95e3 --- /dev/null +++ b/src/mod/sin/armoury/ShieldTweaks.java @@ -0,0 +1,94 @@ +package mod.sin.armoury; + +import java.util.logging.Logger; + +import org.gotti.wurmunlimited.modloader.classhooks.HookManager; + +import com.wurmonline.server.Server; +import com.wurmonline.server.bodys.Wound; +import com.wurmonline.server.creatures.Creature; +import com.wurmonline.server.items.Item; +import com.wurmonline.server.sounds.SoundPlayer; +import com.wurmonline.shared.constants.Enchants; + +import javassist.ClassPool; +import javassist.CtClass; +import javassist.NotFoundException; +import mod.sin.lib.Util; + +public class ShieldTweaks { + public static Logger logger = Logger.getLogger(ShieldTweaks.class.getName()); + public static boolean checkShieldSpeed(Item shield){ + if(shield != null && shield.getSpellSpeedBonus() > Server.rand.nextInt(500)){ + return true; + } + return false; + } + + public static void doSharedPain(Creature attacker, Creature defender, Item shield){ + if(shield.getSpellPainShare() > 0f){ + float powerReq = Server.rand.nextInt(300); + if(!(powerReq < shield.getSpellPainShare())){ + return; + } + boolean playSound = false; + if(shield.getBonusForSpellEffect(Enchants.BUFF_ROTTING_TOUCH) > 0f){ + double damage = shield.getBonusForSpellEffect(Enchants.BUFF_ROTTING_TOUCH)*31d; + attacker.addWoundOfType(defender, Wound.TYPE_INFECTION, 0, true, 1.0f, true, damage); + playSound = true; + }else if(shield.getBonusForSpellEffect(Enchants.BUFF_FLAMING_AURA) > 0f){ + double damage = shield.getBonusForSpellEffect(Enchants.BUFF_FLAMING_AURA)*27d; + attacker.addWoundOfType(defender, Wound.TYPE_BURN, 0, true, 1.0f, true, damage); + playSound = true; + }else if(shield.getBonusForSpellEffect(Enchants.BUFF_FROSTBRAND) > 0f){ + double damage = shield.getBonusForSpellEffect(Enchants.BUFF_FROSTBRAND)*28d; + attacker.addWoundOfType(defender, Wound.TYPE_COLD, 0, true, 1.0f, true, damage); + playSound = true; + }else if(shield.getBonusForSpellEffect(Enchants.BUFF_VENOM) > 0f){ + double damage = shield.getBonusForSpellEffect(Enchants.BUFF_VENOM)*30d; + attacker.addWoundOfType(defender, Wound.TYPE_POISON, 0, true, 1.0f, true, damage); + playSound = true; + } + if(playSound){ + SoundPlayer.playSound(attacker.getTemplate().getHitSound(attacker.getSex()), attacker.getTileX(), attacker.getTileY(), true, 0.3f); + } + } + } + + public static void preInit(ArmouryMod mod){ + try { + ClassPool classPool = HookManager.getInstance().getClassPool(); + Class thisClass = ShieldTweaks.class; + if(mod.enableShieldDamageEnchants){ + CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler"); + String replace = ShieldTweaks.class.getName()+".doSharedPain(this.creature, defender, defShield);" + + "$_ = $proceed($$);"; + Util.setReason("Enable shield damage enchants."); + Util.instrumentDeclared(thisClass, ctCombatHandler, "checkShield", "setDamage", replace); + /*ctCombatHandler.getDeclaredMethod("checkShield").instrument(new ExprEditor(){ + public void edit(MethodCall m) throws CannotCompileException { + if (m.getMethodName().equals("setDamage")) { + m.replace(ShieldTweaks.class.getName()+".doSharedPain(this.creature, defender, defShield);" + + "$_ = $proceed($$);"); + return; + } + } + });*/ + } + if(mod.enableShieldSpeedEnchants){ + CtClass ctCombatHandler = classPool.get("com.wurmonline.server.creatures.CombatHandler"); + String insert = "if("+ShieldTweaks.class.getName()+".checkShieldSpeed(defender.getShield())){" + + " defender.getCombatHandler().usedShieldThisRound--;" + + "}"; + Util.setReason("Enable shield speed enchants."); + Util.insertBeforeDeclared(thisClass, ctCombatHandler, "checkShield", insert); + /*ctCombatHandler.getDeclaredMethod("checkShield").insertBefore("" + + "if("+ShieldTweaks.class.getName()+".checkShieldSpeed(defender.getShield())){" + + " defender.getCombatHandler().usedShieldThisRound--;" + + "}");*/ + } + }catch (NotFoundException e) { + e.printStackTrace(); + } + } +} diff --git a/src/mod/sin/armoury/WeaponTweaks.java b/src/mod/sin/armoury/WeaponTweaks.java new file mode 100644 index 0000000..26025e9 --- /dev/null +++ b/src/mod/sin/armoury/WeaponTweaks.java @@ -0,0 +1,247 @@ +package mod.sin.armoury; + +import java.util.Map; +import java.util.logging.Logger; + +import org.gotti.wurmunlimited.modloader.ReflectionUtil; + +import com.wurmonline.server.combat.Weapon; +import com.wurmonline.server.items.ItemTemplate; +import com.wurmonline.server.items.ItemTemplateFactory; + +public class WeaponTweaks { + public static Logger logger = Logger.getLogger(WeaponTweaks.class.getName()); + public static Map weapons; + + public static void printWeapons(){ + try{ + for(int i : weapons.keySet()){ + Weapon cw = weapons.get(i); + ItemTemplate wt = ItemTemplateFactory.getInstance().getTemplateOrNull(i); + if(wt == null){ + logger.warning("Null weapon template for id "+i); + }else{ + logger.info("Weapon \""+wt.sizeString+wt.getName()+"\" (ID "+i+") stats: ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "damage"))+" damage], ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "speed"))+" speed], ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "critchance"))+" critchance], ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "reach"))+" reach], ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "weightGroup"))+" weightGroup], ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "parryPercent"))+" parryPercent], ["+ + ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "skillPenalty"))+" skillPenalty]" + ); + } + } + } catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public static void editWeaponStats(ArmouryMod mod){ + try { + Weapon cw; + ItemTemplate it; + String tweakType = ""; + if(mod.weaponDamage.keySet() != null){ + tweakType = "damage"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponDamage.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + float oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "damage")); + float newValue = mod.weaponDamage.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting damage on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "damage"), newValue); + } + } + if(mod.weaponSpeed.keySet() != null){ + tweakType = "speed"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponSpeed.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid. Please double check your configuration."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + float oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "speed")); + float newValue = mod.weaponSpeed.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting speed on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "speed"), newValue); + } + } + if(mod.weaponCritChance.keySet() != null){ + tweakType = "crit chance"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponCritChance.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid. Please double check your configuration."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + float oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "critchance")); + float newValue = mod.weaponCritChance.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting crit chance on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "critchance"), newValue); + } + } + if(mod.weaponReach.keySet() != null){ + tweakType = "reach"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponReach.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid. Please double check your configuration."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + int oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "reach")); + int newValue = mod.weaponReach.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting reach on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "reach"), newValue); + } + } + if(mod.weaponWeightGroup.keySet() != null){ + tweakType = "weight group"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponWeightGroup.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid. Please double check your configuration."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + int oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "weightGroup")); + int newValue = mod.weaponWeightGroup.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting weight group on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "weightGroup"), newValue); + } + } + if(mod.weaponParryPercent.keySet() != null){ + tweakType = "parry percent"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponParryPercent.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid. Please double check your configuration."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + float oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "parryPercent")); + float newValue = mod.weaponParryPercent.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting parry percent on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "parryPercent"), newValue); + } + } + if(mod.weaponSkillPenalty.keySet() != null){ + tweakType = "skill penalty"; + logger.info("Beginning weapon "+tweakType+" tweaks..."); + for(int id : mod.weaponSkillPenalty.keySet()){ + it = ItemTemplateFactory.getInstance().getTemplateOrNull(id); + if(it == null){ + logger.severe("[ERROR]: Item template for id "+id+" in weapon "+tweakType+" configuration is invalid. Please double check your configuration."); + continue; + } + cw = weapons.get(id); + if(cw == null){ + logger.severe("[ERROR]: Weapon for id "+id+" in the weapon "+tweakType+" configuration is invalid."); + continue; + } + double oldValue = ReflectionUtil.getPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "skillPenalty")); + double newValue = mod.weaponSkillPenalty.get(id); + String diff = ""; + if(newValue > oldValue){ + diff = "+"+(newValue-oldValue); + }else{ + diff = String.valueOf(newValue-oldValue); + } + logger.info("Setting skill penalty on "+it.sizeString+it.getName()+" to "+newValue+" from "+oldValue+" ("+diff+")"); + ReflectionUtil.setPrivateField(cw, ReflectionUtil.getField(cw.getClass(), "skillPenalty"), newValue); + } + } + } catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + e.printStackTrace(); + } + } + + public static void onServerStarted(ArmouryMod mod){ + try { + logger.info("Beginning WeaponTweaks initialization..."); + weapons = ReflectionUtil.getPrivateField(Weapon.class, ReflectionUtil.getField(Weapon.class, "weapons")); + + //printWeapons(); // For debugging/information purposes + + editWeaponStats(mod); + + //printWeapons(); // For debugging/information purposes + + } catch (IllegalArgumentException | IllegalAccessException | ClassCastException | NoSuchFieldException e) { + e.printStackTrace(); + } + } +}